• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package com.android.server.am;
18 
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;
22 
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;
39 
40 import com.android.internal.os.IResultReceiver;
41 
42 import java.io.PrintWriter;
43 import java.lang.ref.WeakReference;
44 import java.util.Objects;
45 
46 final class PendingIntentRecord extends IIntentSender.Stub {
47     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
48 
49     final ActivityManagerService owner;
50     final Key key;
51     final int uid;
52     final WeakReference<PendingIntentRecord> ref;
53     boolean sent = false;
54     boolean canceled = false;
55     private ArrayMap<IBinder, Long> whitelistDuration;
56     private RemoteCallbackList<IResultReceiver> mCancelCallbacks;
57 
58     String stringName;
59     String lastTagPrefix;
60     String lastTag;
61 
62     final static class Key {
63         final int type;
64         final String packageName;
65         final ActivityRecord activity;
66         final String who;
67         final int requestCode;
68         final Intent requestIntent;
69         final String requestResolvedType;
70         final SafeActivityOptions options;
71         Intent[] allIntents;
72         String[] allResolvedTypes;
73         final int flags;
74         final int hashCode;
75         final int userId;
76 
77         private static final int ODD_PRIME_NUMBER = 37;
78 
Key(int _t, String _p, ActivityRecord _a, String _w, int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId)79         Key(int _t, String _p, ActivityRecord _a, String _w,
80                 int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) {
81             type = _t;
82             packageName = _p;
83             activity = _a;
84             who = _w;
85             requestCode = _r;
86             requestIntent = _i != null ? _i[_i.length-1] : null;
87             requestResolvedType = _it != null ? _it[_it.length-1] : null;
88             allIntents = _i;
89             allResolvedTypes = _it;
90             flags = _f;
91             options = _o;
92             userId = _userId;
93 
94             int hash = 23;
95             hash = (ODD_PRIME_NUMBER*hash) + _f;
96             hash = (ODD_PRIME_NUMBER*hash) + _r;
97             hash = (ODD_PRIME_NUMBER*hash) + _userId;
98             if (_w != null) {
99                 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();
100             }
101             if (_a != null) {
102                 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();
103             }
104             if (requestIntent != null) {
105                 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();
106             }
107             if (requestResolvedType != null) {
108                 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
109             }
110             hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0);
111             hash = (ODD_PRIME_NUMBER*hash) + _t;
112             hashCode = hash;
113             //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
114             //        + Integer.toHexString(hashCode));
115         }
116 
equals(Object otherObj)117         public boolean equals(Object otherObj) {
118             if (otherObj == null) {
119                 return false;
120             }
121             try {
122                 Key other = (Key)otherObj;
123                 if (type != other.type) {
124                     return false;
125                 }
126                 if (userId != other.userId){
127                     return false;
128                 }
129                 if (!Objects.equals(packageName, other.packageName)) {
130                     return false;
131                 }
132                 if (activity != other.activity) {
133                     return false;
134                 }
135                 if (!Objects.equals(who, other.who)) {
136                     return false;
137                 }
138                 if (requestCode != other.requestCode) {
139                     return false;
140                 }
141                 if (requestIntent != other.requestIntent) {
142                     if (requestIntent != null) {
143                         if (!requestIntent.filterEquals(other.requestIntent)) {
144                             return false;
145                         }
146                     } else if (other.requestIntent != null) {
147                         return false;
148                     }
149                 }
150                 if (!Objects.equals(requestResolvedType, other.requestResolvedType)) {
151                     return false;
152                 }
153                 if (flags != other.flags) {
154                     return false;
155                 }
156                 return true;
157             } catch (ClassCastException e) {
158             }
159             return false;
160         }
161 
hashCode()162         public int hashCode() {
163             return hashCode;
164         }
165 
toString()166         public String toString() {
167             return "Key{" + typeName() + " pkg=" + packageName
168                 + " intent="
169                 + (requestIntent != null
170                         ? requestIntent.toShortString(false, true, false, false) : "<null>")
171                 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}";
172         }
173 
typeName()174         String typeName() {
175             switch (type) {
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";
186             }
187             return Integer.toString(type);
188         }
189     }
190 
PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u)191     PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
192         owner = _owner;
193         key = _k;
194         uid = _u;
195         ref = new WeakReference<PendingIntentRecord>(this);
196     }
197 
setWhitelistDurationLocked(IBinder whitelistToken, long duration)198     void setWhitelistDurationLocked(IBinder whitelistToken, long duration) {
199         if (duration > 0) {
200             if (whitelistDuration == null) {
201                 whitelistDuration = new ArrayMap<>();
202             }
203             whitelistDuration.put(whitelistToken, duration);
204         } else if (whitelistDuration != null) {
205             whitelistDuration.remove(whitelistToken);
206             if (whitelistDuration.size() <= 0) {
207                 whitelistDuration = null;
208             }
209 
210         }
211         this.stringName = null;
212     }
213 
registerCancelListenerLocked(IResultReceiver receiver)214     public void registerCancelListenerLocked(IResultReceiver receiver) {
215         if (mCancelCallbacks == null) {
216             mCancelCallbacks = new RemoteCallbackList<>();
217         }
218         mCancelCallbacks.register(receiver);
219     }
220 
unregisterCancelListenerLocked(IResultReceiver receiver)221     public void unregisterCancelListenerLocked(IResultReceiver receiver) {
222         if (mCancelCallbacks == null) {
223             return; // Already unregistered or detached.
224         }
225         mCancelCallbacks.unregister(receiver);
226         if (mCancelCallbacks.getRegisteredCallbackCount() <= 0) {
227             mCancelCallbacks = null;
228         }
229     }
230 
detachCancelListenersLocked()231     public RemoteCallbackList<IResultReceiver> detachCancelListenersLocked() {
232         RemoteCallbackList<IResultReceiver> listeners = mCancelCallbacks;
233         mCancelCallbacks = null;
234         return listeners;
235     }
236 
send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)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);
241     }
242 
sendWithResult(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle 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);
247     }
248 
sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle 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);
255 
256         synchronized (owner) {
257             if (!canceled) {
258                 sent = true;
259                 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
260                     owner.cancelIntentSenderLocked(this, true);
261                 }
262 
263                 Intent finalIntent = key.requestIntent != null
264                         ? new Intent(key.requestIntent) : new Intent();
265 
266                 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
267                 if (!immutable) {
268                     if (intent != null) {
269                         int changes = finalIntent.fillIn(intent, key.flags);
270                         if ((changes & Intent.FILL_IN_DATA) == 0) {
271                             resolvedType = key.requestResolvedType;
272                         }
273                     } else {
274                         resolvedType = key.requestResolvedType;
275                     }
276                     flagsMask &= ~Intent.IMMUTABLE_FLAGS;
277                     flagsValues &= flagsMask;
278                     finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
279                 } else {
280                     resolvedType = key.requestResolvedType;
281                 }
282 
283                 final int callingUid = Binder.getCallingUid();
284                 final int callingPid = Binder.getCallingPid();
285 
286                 // Extract options before clearing calling identity
287                 SafeActivityOptions mergedOptions = key.options;
288                 if (mergedOptions == null) {
289                     mergedOptions = SafeActivityOptions.fromBundle(options);
290                 } else {
291                     mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options));
292                 }
293 
294                 final long origId = Binder.clearCallingIdentity();
295 
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);
304                             tag.append(":");
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());
311                             }
312                             owner.tempWhitelistForPendingIntentLocked(callingPid,
313                                     callingUid, uid, duration, tag.toString());
314                         } else {
315                             Slog.w(TAG, "Not doing whitelist " + this + ": caller state="
316                                     + procState);
317                         }
318                     }
319                 }
320 
321                 boolean sendFinish = finishedReceiver != null;
322                 int userId = key.userId;
323                 if (userId == UserHandle.USER_CURRENT) {
324                     userId = owner.mUserController.getCurrentOrTargetUserId();
325                 }
326                 int res = START_SUCCESS;
327                 switch (key.type) {
328                     case ActivityManager.INTENT_SENDER_ACTIVITY:
329                         try {
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.
333 
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);
342                                 }
343                                 allIntents[allIntents.length-1] = finalIntent;
344                                 allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
345 
346                                 res = owner.getActivityStartController().startActivitiesInPackage(
347                                         uid, callingPid, callingUid, key.packageName, allIntents,
348                                         allResolvedTypes, resultTo, mergedOptions, userId,
349                                         false /* validateIncomingUser */);
350                             } else {
351                                 res = owner.getActivityStartController().startActivityInPackage(uid,
352                                         callingPid, callingUid, key.packageName, finalIntent,
353                                         resolvedType, resultTo, resultWho, requestCode, 0,
354                                         mergedOptions, userId, null, "PendingIntentRecord",
355                                         false /* validateIncomingUser */);
356                             }
357                         } catch (RuntimeException e) {
358                             Slog.w(TAG, "Unable to send startActivity intent", e);
359                         }
360                         break;
361                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
362                         final ActivityStack stack = key.activity.getStack();
363                         if (stack != null) {
364                             stack.sendActivityResultLocked(-1, key.activity, key.who,
365                                     key.requestCode, code, finalIntent);
366                         }
367                         break;
368                     case ActivityManager.INTENT_SENDER_BROADCAST:
369                         try {
370                             // If a completion callback has been requested, require
371                             // that the broadcast be delivered synchronously
372                             int sent = owner.broadcastIntentInPackage(key.packageName, uid,
373                                     finalIntent, resolvedType, finishedReceiver, code, null, null,
374                                     requiredPermission, options, (finishedReceiver != null),
375                                     false, userId);
376                             if (sent == ActivityManager.BROADCAST_SUCCESS) {
377                                 sendFinish = false;
378                             }
379                         } catch (RuntimeException e) {
380                             Slog.w(TAG, "Unable to send startActivity intent", e);
381                         }
382                         break;
383                     case ActivityManager.INTENT_SENDER_SERVICE:
384                     case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
385                         try {
386                             owner.startServiceInPackage(uid, finalIntent, resolvedType,
387                                     key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
388                                     key.packageName, userId);
389                         } catch (RuntimeException e) {
390                             Slog.w(TAG, "Unable to send startService intent", e);
391                         } catch (TransactionTooLargeException e) {
392                             res = ActivityManager.START_CANCELED;
393                         }
394                         break;
395                 }
396 
397                 if (sendFinish && res != ActivityManager.START_CANCELED) {
398                     try {
399                         finishedReceiver.performReceive(new Intent(finalIntent), 0,
400                                 null, null, false, false, key.userId);
401                     } catch (RemoteException e) {
402                     }
403                 }
404 
405                 Binder.restoreCallingIdentity(origId);
406 
407                 return res;
408             }
409         }
410         return ActivityManager.START_CANCELED;
411     }
412 
413     @Override
finalize()414     protected void finalize() throws Throwable {
415         try {
416             if (!canceled) {
417                 owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
418                         ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
419             }
420         } finally {
421             super.finalize();
422         }
423     }
424 
completeFinalize()425     public void completeFinalize() {
426         synchronized(owner) {
427             WeakReference<PendingIntentRecord> current =
428                     owner.mIntentSenderRecords.get(key);
429             if (current == ref) {
430                 owner.mIntentSenderRecords.remove(key);
431             }
432         }
433     }
434 
dump(PrintWriter pw, String prefix)435     void dump(PrintWriter pw, String prefix) {
436         pw.print(prefix); pw.print("uid="); pw.print(uid);
437                 pw.print(" packageName="); pw.print(key.packageName);
438                 pw.print(" type="); pw.print(key.typeName());
439                 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags));
440         if (key.activity != null || key.who != null) {
441             pw.print(prefix); pw.print("activity="); pw.print(key.activity);
442                     pw.print(" who="); pw.println(key.who);
443         }
444         if (key.requestCode != 0 || key.requestResolvedType != null) {
445             pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
446                     pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
447         }
448         if (key.requestIntent != null) {
449             pw.print(prefix); pw.print("requestIntent=");
450                     pw.println(key.requestIntent.toShortString(false, true, true, true));
451         }
452         if (sent || canceled) {
453             pw.print(prefix); pw.print("sent="); pw.print(sent);
454                     pw.print(" canceled="); pw.println(canceled);
455         }
456         if (whitelistDuration != null) {
457             pw.print(prefix);
458             pw.print("whitelistDuration=");
459             for (int i = 0; i < whitelistDuration.size(); i++) {
460                 if (i != 0) {
461                     pw.print(", ");
462                 }
463                 pw.print(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i))));
464                 pw.print(":");
465                 TimeUtils.formatDuration(whitelistDuration.valueAt(i), pw);
466             }
467             pw.println();
468         }
469         if (mCancelCallbacks != null) {
470             pw.print(prefix); pw.println("mCancelCallbacks:");
471             for (int i = 0; i < mCancelCallbacks.getRegisteredCallbackCount(); i++) {
472                 pw.print(prefix); pw.print("  #"); pw.print(i); pw.print(": ");
473                 pw.println(mCancelCallbacks.getRegisteredCallbackItem(i));
474             }
475         }
476     }
477 
toString()478     public String toString() {
479         if (stringName != null) {
480             return stringName;
481         }
482         StringBuilder sb = new StringBuilder(128);
483         sb.append("PendingIntentRecord{");
484         sb.append(Integer.toHexString(System.identityHashCode(this)));
485         sb.append(' ');
486         sb.append(key.packageName);
487         sb.append(' ');
488         sb.append(key.typeName());
489         if (whitelistDuration != null) {
490             sb.append( " (whitelist: ");
491             for (int i = 0; i < whitelistDuration.size(); i++) {
492                 if (i != 0) {
493                     sb.append(",");
494                 }
495                 sb.append(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i))));
496                 sb.append(":");
497                 TimeUtils.formatDuration(whitelistDuration.valueAt(i), sb);
498             }
499             sb.append(")");
500         }
501         sb.append('}');
502         return stringName = sb.toString();
503     }
504 }
505