2 * Copyright (C) 2006 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.am;
19 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
22 import android.app.ActivityManager;
23 import android.app.IActivityContainer;
24 import android.content.IIntentSender;
25 import android.content.IIntentReceiver;
26 import android.app.PendingIntent;
27 import android.content.Intent;
28 import android.os.Binder;
29 import android.os.Bundle;
30 import android.os.IBinder;
31 import android.os.RemoteException;
32 import android.os.TransactionTooLargeException;
33 import android.os.UserHandle;
34 import android.util.Slog;
35 import android.util.TimeUtils;
37 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
39 import java.io.PrintWriter;
40 import java.lang.ref.WeakReference;
41 import java.util.Objects;
43 final class PendingIntentRecord extends IIntentSender.Stub {
44 private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
46 final ActivityManagerService owner;
49 final WeakReference<PendingIntentRecord> ref;
51 boolean canceled = false;
52 private long whitelistDuration = 0;
58 final static class Key {
60 final String packageName;
61 final ActivityRecord activity;
63 final int requestCode;
64 final Intent requestIntent;
65 final String requestResolvedType;
68 String[] allResolvedTypes;
73 private static final int ODD_PRIME_NUMBER = 37;
75 Key(int _t, String _p, ActivityRecord _a, String _w,
76 int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) {
82 requestIntent = _i != null ? _i[_i.length-1] : null;
83 requestResolvedType = _it != null ? _it[_it.length-1] : null;
85 allResolvedTypes = _it;
91 hash = (ODD_PRIME_NUMBER*hash) + _f;
92 hash = (ODD_PRIME_NUMBER*hash) + _r;
93 hash = (ODD_PRIME_NUMBER*hash) + _userId;
95 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();
98 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();
100 if (requestIntent != null) {
101 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();
103 if (requestResolvedType != null) {
104 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
106 hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0);
107 hash = (ODD_PRIME_NUMBER*hash) + _t;
109 //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
110 // + Integer.toHexString(hashCode));
113 public boolean equals(Object otherObj) {
114 if (otherObj == null) {
118 Key other = (Key)otherObj;
119 if (type != other.type) {
122 if (userId != other.userId){
125 if (!Objects.equals(packageName, other.packageName)) {
128 if (activity != other.activity) {
131 if (!Objects.equals(who, other.who)) {
134 if (requestCode != other.requestCode) {
137 if (requestIntent != other.requestIntent) {
138 if (requestIntent != null) {
139 if (!requestIntent.filterEquals(other.requestIntent)) {
142 } else if (other.requestIntent != null) {
146 if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
149 if (flags != other.flags) {
153 } catch (ClassCastException e) {
158 public int hashCode() {
162 public String toString() {
163 return "Key{" + typeName() + " pkg=" + packageName
165 + (requestIntent != null
166 ? requestIntent.toShortString(false, true, false, false) : "<null>")
167 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}";
172 case ActivityManager.INTENT_SENDER_ACTIVITY:
173 return "startActivity";
174 case ActivityManager.INTENT_SENDER_BROADCAST:
175 return "broadcastIntent";
176 case ActivityManager.INTENT_SENDER_SERVICE:
177 return "startService";
178 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
179 return "activityResult";
181 return Integer.toString(type);
185 PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
189 ref = new WeakReference<PendingIntentRecord>(this);
192 void setWhitelistDuration(long duration) {
193 this.whitelistDuration = duration;
194 this.stringName = null;
197 public void send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
198 String requiredPermission, Bundle options) {
199 sendInner(code, intent, resolvedType, finishedReceiver,
200 requiredPermission, null, null, 0, 0, 0, options, null);
203 public int sendWithResult(int code, Intent intent, String resolvedType,
204 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
205 return sendInner(code, intent, resolvedType, finishedReceiver,
206 requiredPermission, null, null, 0, 0, 0, options, null);
209 int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
210 String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
211 int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
212 if (intent != null) intent.setDefusable(true);
213 if (options != null) options.setDefusable(true);
215 if (whitelistDuration > 0 && !canceled) {
216 // Must call before acquiring the lock. It's possible the method return before sending
217 // the intent due to some validations inside the lock, in which case the UID shouldn't
218 // be whitelisted, but since the whitelist is temporary, that would be ok.
219 owner.tempWhitelistAppForPowerSave(Binder.getCallingPid(), Binder.getCallingUid(), uid,
223 synchronized (owner) {
224 final ActivityContainer activityContainer = (ActivityContainer)container;
225 if (activityContainer != null && activityContainer.mParentActivity != null &&
226 activityContainer.mParentActivity.state
227 != ActivityStack.ActivityState.RESUMED) {
228 // Cannot start a child activity if the parent is not resumed.
229 return ActivityManager.START_CANCELED;
233 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
234 owner.cancelIntentSenderLocked(this, true);
238 Intent finalIntent = key.requestIntent != null
239 ? new Intent(key.requestIntent) : new Intent();
241 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
243 if (intent != null) {
244 int changes = finalIntent.fillIn(intent, key.flags);
245 if ((changes & Intent.FILL_IN_DATA) == 0) {
246 resolvedType = key.requestResolvedType;
249 resolvedType = key.requestResolvedType;
251 flagsMask &= ~Intent.IMMUTABLE_FLAGS;
252 flagsValues &= flagsMask;
253 finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
255 resolvedType = key.requestResolvedType;
258 final long origId = Binder.clearCallingIdentity();
260 boolean sendFinish = finishedReceiver != null;
261 int userId = key.userId;
262 if (userId == UserHandle.USER_CURRENT) {
263 userId = owner.mUserController.getCurrentOrTargetUserIdLocked();
267 case ActivityManager.INTENT_SENDER_ACTIVITY:
268 if (options == null) {
269 options = key.options;
270 } else if (key.options != null) {
271 Bundle opts = new Bundle(key.options);
272 opts.putAll(options);
276 if (key.allIntents != null && key.allIntents.length > 1) {
277 Intent[] allIntents = new Intent[key.allIntents.length];
278 String[] allResolvedTypes = new String[key.allIntents.length];
279 System.arraycopy(key.allIntents, 0, allIntents, 0,
280 key.allIntents.length);
281 if (key.allResolvedTypes != null) {
282 System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
283 key.allResolvedTypes.length);
285 allIntents[allIntents.length-1] = finalIntent;
286 allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
287 owner.startActivitiesInPackage(uid, key.packageName, allIntents,
288 allResolvedTypes, resultTo, options, userId);
290 owner.startActivityInPackage(uid, key.packageName, finalIntent,
291 resolvedType, resultTo, resultWho, requestCode, 0,
292 options, userId, container, null);
294 } catch (RuntimeException e) {
295 Slog.w(TAG, "Unable to send startActivity intent", e);
298 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
299 if (key.activity.task.stack != null) {
300 key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
301 key.who, key.requestCode, code, finalIntent);
304 case ActivityManager.INTENT_SENDER_BROADCAST:
306 // If a completion callback has been requested, require
307 // that the broadcast be delivered synchronously
308 int sent = owner.broadcastIntentInPackage(key.packageName, uid,
309 finalIntent, resolvedType, finishedReceiver, code, null, null,
310 requiredPermission, options, (finishedReceiver != null),
312 if (sent == ActivityManager.BROADCAST_SUCCESS) {
315 } catch (RuntimeException e) {
316 Slog.w(TAG, "Unable to send startActivity intent", e);
319 case ActivityManager.INTENT_SENDER_SERVICE:
321 owner.startServiceInPackage(uid, finalIntent,
322 resolvedType, key.packageName, userId);
323 } catch (RuntimeException e) {
324 Slog.w(TAG, "Unable to send startService intent", e);
325 } catch (TransactionTooLargeException e) {
326 res = ActivityManager.START_CANCELED;
331 if (sendFinish && res != ActivityManager.START_CANCELED) {
333 finishedReceiver.performReceive(new Intent(finalIntent), 0,
334 null, null, false, false, key.userId);
335 } catch (RemoteException e) {
339 Binder.restoreCallingIdentity(origId);
344 return ActivityManager.START_CANCELED;
348 protected void finalize() throws Throwable {
351 owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
352 ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
359 public void completeFinalize() {
360 synchronized(owner) {
361 WeakReference<PendingIntentRecord> current =
362 owner.mIntentSenderRecords.get(key);
363 if (current == ref) {
364 owner.mIntentSenderRecords.remove(key);
369 void dump(PrintWriter pw, String prefix) {
370 pw.print(prefix); pw.print("uid="); pw.print(uid);
371 pw.print(" packageName="); pw.print(key.packageName);
372 pw.print(" type="); pw.print(key.typeName());
373 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags));
374 if (key.activity != null || key.who != null) {
375 pw.print(prefix); pw.print("activity="); pw.print(key.activity);
376 pw.print(" who="); pw.println(key.who);
378 if (key.requestCode != 0 || key.requestResolvedType != null) {
379 pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
380 pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
382 if (key.requestIntent != null) {
383 pw.print(prefix); pw.print("requestIntent=");
384 pw.println(key.requestIntent.toShortString(false, true, true, true));
386 if (sent || canceled) {
387 pw.print(prefix); pw.print("sent="); pw.print(sent);
388 pw.print(" canceled="); pw.println(canceled);
390 if (whitelistDuration != 0) {
392 pw.print("whitelistDuration=");
393 TimeUtils.formatDuration(whitelistDuration, pw);
398 public String toString() {
399 if (stringName != null) {
402 StringBuilder sb = new StringBuilder(128);
403 sb.append("PendingIntentRecord{");
404 sb.append(Integer.toHexString(System.identityHashCode(this)));
406 sb.append(key.packageName);
408 sb.append(key.typeName());
409 if (whitelistDuration > 0) {
410 sb.append( " (whitelist: ");
411 TimeUtils.formatDuration(whitelistDuration, sb);
415 return stringName = sb.toString();