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 android.app.ActivityManager.START_SUCCESS;
20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
21 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
23 import android.app.ActivityManager;
24 import android.app.ActivityOptions;
25 import android.content.IIntentSender;
26 import android.content.IIntentReceiver;
27 import android.app.PendingIntent;
28 import android.content.Intent;
29 import android.os.Binder;
30 import android.os.Bundle;
31 import android.os.IBinder;
32 import android.os.RemoteCallbackList;
33 import android.os.RemoteException;
34 import android.os.TransactionTooLargeException;
35 import android.os.UserHandle;
36 import android.util.ArrayMap;
37 import android.util.Slog;
38 import android.util.TimeUtils;
40 import com.android.internal.os.IResultReceiver;
42 import java.io.PrintWriter;
43 import java.lang.ref.WeakReference;
44 import java.util.Objects;
46 final class PendingIntentRecord extends IIntentSender.Stub {
47 private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
49 final ActivityManagerService owner;
52 final WeakReference<PendingIntentRecord> ref;
54 boolean canceled = false;
55 private ArrayMap<IBinder, Long> whitelistDuration;
56 private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
62 final static class Key {
64 final String packageName;
65 final ActivityRecord activity;
67 final int requestCode;
68 final Intent requestIntent;
69 final String requestResolvedType;
70 final SafeActivityOptions options;
72 String[] allResolvedTypes;
77 private static final int ODD_PRIME_NUMBER = 37;
79 Key(int _t, String _p, ActivityRecord _a, String _w,
80 int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) {
86 requestIntent = _i != null ? _i[_i.length-1] : null;
87 requestResolvedType = _it != null ? _it[_it.length-1] : null;
89 allResolvedTypes = _it;
95 hash = (ODD_PRIME_NUMBER*hash) + _f;
96 hash = (ODD_PRIME_NUMBER*hash) + _r;
97 hash = (ODD_PRIME_NUMBER*hash) + _userId;
99 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();
102 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();
104 if (requestIntent != null) {
105 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();
107 if (requestResolvedType != null) {
108 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
110 hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0);
111 hash = (ODD_PRIME_NUMBER*hash) + _t;
113 //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
114 // + Integer.toHexString(hashCode));
117 public boolean equals(Object otherObj) {
118 if (otherObj == null) {
122 Key other = (Key)otherObj;
123 if (type != other.type) {
126 if (userId != other.userId){
129 if (!Objects.equals(packageName, other.packageName)) {
132 if (activity != other.activity) {
135 if (!Objects.equals(who, other.who)) {
138 if (requestCode != other.requestCode) {
141 if (requestIntent != other.requestIntent) {
142 if (requestIntent != null) {
143 if (!requestIntent.filterEquals(other.requestIntent)) {
146 } else if (other.requestIntent != null) {
150 if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
153 if (flags != other.flags) {
157 } catch (ClassCastException e) {
162 public int hashCode() {
166 public String toString() {
167 return "Key{" + typeName() + " pkg=" + packageName
169 + (requestIntent != null
170 ? requestIntent.toShortString(false, true, false, false) : "<null>")
171 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}";
176 case ActivityManager.INTENT_SENDER_ACTIVITY:
177 return "startActivity";
178 case ActivityManager.INTENT_SENDER_BROADCAST:
179 return "broadcastIntent";
180 case ActivityManager.INTENT_SENDER_SERVICE:
181 return "startService";
182 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
183 return "startForegroundService";
184 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
185 return "activityResult";
187 return Integer.toString(type);
191 PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
195 ref = new WeakReference<PendingIntentRecord>(this);
198 void setWhitelistDurationLocked(IBinder whitelistToken, long duration) {
200 if (whitelistDuration == null) {
201 whitelistDuration = new ArrayMap<>();
203 whitelistDuration.put(whitelistToken, duration);
204 } else if (whitelistDuration != null) {
205 whitelistDuration.remove(whitelistToken);
206 if (whitelistDuration.size() <= 0) {
207 whitelistDuration = null;
211 this.stringName = null;
214 public void registerCancelListenerLocked(IResultReceiver receiver) {
215 if (mCancelCallbacks == null) {
216 mCancelCallbacks = new RemoteCallbackList<>();
218 mCancelCallbacks.register(receiver);
221 public void unregisterCancelListenerLocked(IResultReceiver receiver) {
222 if (mCancelCallbacks == null) {
223 return; // Already unregistered or detached.
225 mCancelCallbacks.unregister(receiver);
226 if (mCancelCallbacks.getRegisteredCallbackCount() <= 0) {
227 mCancelCallbacks = null;
231 public RemoteCallbackList<IResultReceiver> detachCancelListenersLocked() {
232 RemoteCallbackList<IResultReceiver> listeners = mCancelCallbacks;
233 mCancelCallbacks = null;
237 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
238 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
239 sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
240 requiredPermission, null, null, 0, 0, 0, options);
243 public int sendWithResult(int code, Intent intent, String resolvedType, IBinder whitelistToken,
244 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
245 return sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver,
246 requiredPermission, null, null, 0, 0, 0, options);
249 int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken,
250 IIntentReceiver finishedReceiver,
251 String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
252 int flagsMask, int flagsValues, Bundle options) {
253 if (intent != null) intent.setDefusable(true);
254 if (options != null) options.setDefusable(true);
256 synchronized (owner) {
259 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
260 owner.cancelIntentSenderLocked(this, true);
263 Intent finalIntent = key.requestIntent != null
264 ? new Intent(key.requestIntent) : new Intent();
266 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
268 if (intent != null) {
269 int changes = finalIntent.fillIn(intent, key.flags);
270 if ((changes & Intent.FILL_IN_DATA) == 0) {
271 resolvedType = key.requestResolvedType;
274 resolvedType = key.requestResolvedType;
276 flagsMask &= ~Intent.IMMUTABLE_FLAGS;
277 flagsValues &= flagsMask;
278 finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
280 resolvedType = key.requestResolvedType;
283 final int callingUid = Binder.getCallingUid();
284 final int callingPid = Binder.getCallingPid();
286 // Extract options before clearing calling identity
287 SafeActivityOptions mergedOptions = key.options;
288 if (mergedOptions == null) {
289 mergedOptions = SafeActivityOptions.fromBundle(options);
291 mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
294 final long origId = Binder.clearCallingIdentity();
296 if (whitelistDuration != null) {
297 Long duration = whitelistDuration.get(whitelistToken);
298 if (duration != null) {
299 int procState = owner.getUidState(callingUid);
300 if (!ActivityManager.isProcStateBackground(procState)) {
301 StringBuilder tag = new StringBuilder(64);
302 tag.append("pendingintent:");
303 UserHandle.formatUid(tag, callingUid);
305 if (finalIntent.getAction() != null) {
306 tag.append(finalIntent.getAction());
307 } else if (finalIntent.getComponent() != null) {
308 finalIntent.getComponent().appendShortString(tag);
309 } else if (finalIntent.getData() != null) {
310 tag.append(finalIntent.getData().toSafeString());
312 owner.tempWhitelistForPendingIntentLocked(callingPid,
313 callingUid, uid, duration, tag.toString());
315 Slog.w(TAG, "Not doing whitelist " + this + ": caller state="
321 boolean sendFinish = finishedReceiver != null;
322 int userId = key.userId;
323 if (userId == UserHandle.USER_CURRENT) {
324 userId = owner.mUserController.getCurrentOrTargetUserId();
326 int res = START_SUCCESS;
328 case ActivityManager.INTENT_SENDER_ACTIVITY:
330 // Note when someone has a pending intent, even from different
331 // users, then there's no need to ensure the calling user matches
332 // the target user, so validateIncomingUser is always false below.
334 if (key.allIntents != null && key.allIntents.length > 1) {
335 Intent[] allIntents = new Intent[key.allIntents.length];
336 String[] allResolvedTypes = new String[key.allIntents.length];
337 System.arraycopy(key.allIntents, 0, allIntents, 0,
338 key.allIntents.length);
339 if (key.allResolvedTypes != null) {
340 System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
341 key.allResolvedTypes.length);
343 allIntents[allIntents.length-1] = finalIntent;
344 allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
346 res = owner.getActivityStartController().startActivitiesInPackage(
347 uid, callingPid, callingUid, key.packageName, allIntents,
348 allResolvedTypes, resultTo, mergedOptions, userId,
349 false /* validateIncomingUser */,
350 this /* originatingPendingIntent */);
352 res = owner.getActivityStartController().startActivityInPackage(uid,
353 callingPid, callingUid, key.packageName, finalIntent,
354 resolvedType, resultTo, resultWho, requestCode, 0,
355 mergedOptions, userId, null, "PendingIntentRecord",
356 false /* validateIncomingUser */,
357 this /* originatingPendingIntent */);
359 } catch (RuntimeException e) {
360 Slog.w(TAG, "Unable to send startActivity intent", e);
363 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
364 final ActivityStack stack = key.activity.getStack();
366 stack.sendActivityResultLocked(-1, key.activity, key.who,
367 key.requestCode, code, finalIntent);
370 case ActivityManager.INTENT_SENDER_BROADCAST:
372 // If a completion callback has been requested, require
373 // that the broadcast be delivered synchronously
374 int sent = owner.broadcastIntentInPackage(key.packageName, uid,
375 finalIntent, resolvedType, finishedReceiver, code, null, null,
376 requiredPermission, options, (finishedReceiver != null),
378 if (sent == ActivityManager.BROADCAST_SUCCESS) {
381 } catch (RuntimeException e) {
382 Slog.w(TAG, "Unable to send startActivity intent", e);
385 case ActivityManager.INTENT_SENDER_SERVICE:
386 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
388 owner.startServiceInPackage(uid, finalIntent, resolvedType,
389 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
390 key.packageName, userId);
391 } catch (RuntimeException e) {
392 Slog.w(TAG, "Unable to send startService intent", e);
393 } catch (TransactionTooLargeException e) {
394 res = ActivityManager.START_CANCELED;
399 if (sendFinish && res != ActivityManager.START_CANCELED) {
401 finishedReceiver.performReceive(new Intent(finalIntent), 0,
402 null, null, false, false, key.userId);
403 } catch (RemoteException e) {
407 Binder.restoreCallingIdentity(origId);
412 return ActivityManager.START_CANCELED;
416 protected void finalize() throws Throwable {
419 owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
420 ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
427 public void completeFinalize() {
428 synchronized(owner) {
429 WeakReference<PendingIntentRecord> current =
430 owner.mIntentSenderRecords.get(key);
431 if (current == ref) {
432 owner.mIntentSenderRecords.remove(key);
437 void dump(PrintWriter pw, String prefix) {
438 pw.print(prefix); pw.print("uid="); pw.print(uid);
439 pw.print(" packageName="); pw.print(key.packageName);
440 pw.print(" type="); pw.print(key.typeName());
441 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags));
442 if (key.activity != null || key.who != null) {
443 pw.print(prefix); pw.print("activity="); pw.print(key.activity);
444 pw.print(" who="); pw.println(key.who);
446 if (key.requestCode != 0 || key.requestResolvedType != null) {
447 pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
448 pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
450 if (key.requestIntent != null) {
451 pw.print(prefix); pw.print("requestIntent=");
452 pw.println(key.requestIntent.toShortString(false, true, true, true));
454 if (sent || canceled) {
455 pw.print(prefix); pw.print("sent="); pw.print(sent);
456 pw.print(" canceled="); pw.println(canceled);
458 if (whitelistDuration != null) {
460 pw.print("whitelistDuration=");
461 for (int i = 0; i < whitelistDuration.size(); i++) {
465 pw.print(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i))));
467 TimeUtils.formatDuration(whitelistDuration.valueAt(i), pw);
471 if (mCancelCallbacks != null) {
472 pw.print(prefix); pw.println("mCancelCallbacks:");
473 for (int i = 0; i < mCancelCallbacks.getRegisteredCallbackCount(); i++) {
474 pw.print(prefix); pw.print(" #"); pw.print(i); pw.print(": ");
475 pw.println(mCancelCallbacks.getRegisteredCallbackItem(i));
480 public String toString() {
481 if (stringName != null) {
484 StringBuilder sb = new StringBuilder(128);
485 sb.append("PendingIntentRecord{");
486 sb.append(Integer.toHexString(System.identityHashCode(this)));
488 sb.append(key.packageName);
490 sb.append(key.typeName());
491 if (whitelistDuration != null) {
492 sb.append( " (whitelist: ");
493 for (int i = 0; i < whitelistDuration.size(); i++) {
497 sb.append(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i))));
499 TimeUtils.formatDuration(whitelistDuration.valueAt(i), sb);
504 return stringName = sb.toString();