• 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 com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
21 
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;
36 
37 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
38 
39 import java.io.PrintWriter;
40 import java.lang.ref.WeakReference;
41 
42 final class PendingIntentRecord extends IIntentSender.Stub {
43     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;
44 
45     final ActivityManagerService owner;
46     final Key key;
47     final int uid;
48     final WeakReference<PendingIntentRecord> ref;
49     boolean sent = false;
50     boolean canceled = false;
51     private long whitelistDuration = 0;
52 
53     String stringName;
54     String lastTagPrefix;
55     String lastTag;
56 
57     final static class Key {
58         final int type;
59         final String packageName;
60         final ActivityRecord activity;
61         final String who;
62         final int requestCode;
63         final Intent requestIntent;
64         final String requestResolvedType;
65         final Bundle options;
66         Intent[] allIntents;
67         String[] allResolvedTypes;
68         final int flags;
69         final int hashCode;
70         final int userId;
71 
72         private static final int ODD_PRIME_NUMBER = 37;
73 
Key(int _t, String _p, ActivityRecord _a, String _w, int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId)74         Key(int _t, String _p, ActivityRecord _a, String _w,
75                 int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) {
76             type = _t;
77             packageName = _p;
78             activity = _a;
79             who = _w;
80             requestCode = _r;
81             requestIntent = _i != null ? _i[_i.length-1] : null;
82             requestResolvedType = _it != null ? _it[_it.length-1] : null;
83             allIntents = _i;
84             allResolvedTypes = _it;
85             flags = _f;
86             options = _o;
87             userId = _userId;
88 
89             int hash = 23;
90             hash = (ODD_PRIME_NUMBER*hash) + _f;
91             hash = (ODD_PRIME_NUMBER*hash) + _r;
92             hash = (ODD_PRIME_NUMBER*hash) + _userId;
93             if (_w != null) {
94                 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();
95             }
96             if (_a != null) {
97                 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();
98             }
99             if (requestIntent != null) {
100                 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();
101             }
102             if (requestResolvedType != null) {
103                 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
104             }
105             hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
106             hash = (ODD_PRIME_NUMBER*hash) + _t;
107             hashCode = hash;
108             //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
109             //        + Integer.toHexString(hashCode));
110         }
111 
equals(Object otherObj)112         public boolean equals(Object otherObj) {
113             if (otherObj == null) {
114                 return false;
115             }
116             try {
117                 Key other = (Key)otherObj;
118                 if (type != other.type) {
119                     return false;
120                 }
121                 if (userId != other.userId){
122                     return false;
123                 }
124                 if (!packageName.equals(other.packageName)) {
125                     return false;
126                 }
127                 if (activity != other.activity) {
128                     return false;
129                 }
130                 if (who != other.who) {
131                     if (who != null) {
132                         if (!who.equals(other.who)) {
133                             return false;
134                         }
135                     } else if (other.who != null) {
136                         return false;
137                     }
138                 }
139                 if (requestCode != other.requestCode) {
140                     return false;
141                 }
142                 if (requestIntent != other.requestIntent) {
143                     if (requestIntent != null) {
144                         if (!requestIntent.filterEquals(other.requestIntent)) {
145                             return false;
146                         }
147                     } else if (other.requestIntent != null) {
148                         return false;
149                     }
150                 }
151                 if (requestResolvedType != other.requestResolvedType) {
152                     if (requestResolvedType != null) {
153                         if (!requestResolvedType.equals(other.requestResolvedType)) {
154                             return false;
155                         }
156                     } else if (other.requestResolvedType != null) {
157                         return false;
158                     }
159                 }
160                 if (flags != other.flags) {
161                     return false;
162                 }
163                 return true;
164             } catch (ClassCastException e) {
165             }
166             return false;
167         }
168 
hashCode()169         public int hashCode() {
170             return hashCode;
171         }
172 
toString()173         public String toString() {
174             return "Key{" + typeName() + " pkg=" + packageName
175                 + " intent="
176                 + (requestIntent != null
177                         ? requestIntent.toShortString(false, true, false, false) : "<null>")
178                 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}";
179         }
180 
typeName()181         String typeName() {
182             switch (type) {
183                 case ActivityManager.INTENT_SENDER_ACTIVITY:
184                     return "startActivity";
185                 case ActivityManager.INTENT_SENDER_BROADCAST:
186                     return "broadcastIntent";
187                 case ActivityManager.INTENT_SENDER_SERVICE:
188                     return "startService";
189                 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
190                     return "activityResult";
191             }
192             return Integer.toString(type);
193         }
194     }
195 
PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u)196     PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
197         owner = _owner;
198         key = _k;
199         uid = _u;
200         ref = new WeakReference<PendingIntentRecord>(this);
201     }
202 
setWhitelistDuration(long duration)203     void setWhitelistDuration(long duration) {
204         this.whitelistDuration = duration;
205         this.stringName = null;
206     }
207 
send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)208     public void send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
209             String requiredPermission, Bundle options) {
210         sendInner(code, intent, resolvedType, finishedReceiver,
211                 requiredPermission, null, null, 0, 0, 0, options, null);
212     }
213 
sendWithResult(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)214     public int sendWithResult(int code, Intent intent, String resolvedType,
215             IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
216         return sendInner(code, intent, resolvedType, finishedReceiver,
217                 requiredPermission, null, null, 0, 0, 0, options, null);
218     }
219 
sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options, IActivityContainer container)220     int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
221             String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
222             int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
223         if (intent != null) intent.setDefusable(true);
224         if (options != null) options.setDefusable(true);
225 
226         if (whitelistDuration > 0 && !canceled) {
227             // Must call before acquiring the lock. It's possible the method return before sending
228             // the intent due to some validations inside the lock, in which case the UID shouldn't
229             // be whitelisted, but since the whitelist is temporary, that would be ok.
230             owner.tempWhitelistAppForPowerSave(Binder.getCallingPid(), Binder.getCallingUid(), uid,
231                     whitelistDuration);
232         }
233 
234         synchronized (owner) {
235             final ActivityContainer activityContainer = (ActivityContainer)container;
236             if (activityContainer != null && activityContainer.mParentActivity != null &&
237                     activityContainer.mParentActivity.state
238                             != ActivityStack.ActivityState.RESUMED) {
239                 // Cannot start a child activity if the parent is not resumed.
240                 return ActivityManager.START_CANCELED;
241             }
242             if (!canceled) {
243                 sent = true;
244                 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
245                     owner.cancelIntentSenderLocked(this, true);
246                     canceled = true;
247                 }
248 
249                 Intent finalIntent = key.requestIntent != null
250                         ? new Intent(key.requestIntent) : new Intent();
251 
252                 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
253                 if (!immutable) {
254                     if (intent != null) {
255                         int changes = finalIntent.fillIn(intent, key.flags);
256                         if ((changes & Intent.FILL_IN_DATA) == 0) {
257                             resolvedType = key.requestResolvedType;
258                         }
259                     } else {
260                         resolvedType = key.requestResolvedType;
261                     }
262                     flagsMask &= ~Intent.IMMUTABLE_FLAGS;
263                     flagsValues &= flagsMask;
264                     finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
265                 } else {
266                     resolvedType = key.requestResolvedType;
267                 }
268 
269                 final long origId = Binder.clearCallingIdentity();
270 
271                 boolean sendFinish = finishedReceiver != null;
272                 int userId = key.userId;
273                 if (userId == UserHandle.USER_CURRENT) {
274                     userId = owner.mUserController.getCurrentOrTargetUserIdLocked();
275                 }
276                 int res = 0;
277                 switch (key.type) {
278                     case ActivityManager.INTENT_SENDER_ACTIVITY:
279                         if (options == null) {
280                             options = key.options;
281                         } else if (key.options != null) {
282                             Bundle opts = new Bundle(key.options);
283                             opts.putAll(options);
284                             options = opts;
285                         }
286                         try {
287                             if (key.allIntents != null && key.allIntents.length > 1) {
288                                 Intent[] allIntents = new Intent[key.allIntents.length];
289                                 String[] allResolvedTypes = new String[key.allIntents.length];
290                                 System.arraycopy(key.allIntents, 0, allIntents, 0,
291                                         key.allIntents.length);
292                                 if (key.allResolvedTypes != null) {
293                                     System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
294                                             key.allResolvedTypes.length);
295                                 }
296                                 allIntents[allIntents.length-1] = finalIntent;
297                                 allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
298                                 owner.startActivitiesInPackage(uid, key.packageName, allIntents,
299                                         allResolvedTypes, resultTo, options, userId);
300                             } else {
301                                 owner.startActivityInPackage(uid, key.packageName, finalIntent,
302                                         resolvedType, resultTo, resultWho, requestCode, 0,
303                                         options, userId, container, null);
304                             }
305                         } catch (RuntimeException e) {
306                             Slog.w(TAG, "Unable to send startActivity intent", e);
307                         }
308                         break;
309                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
310                         if (key.activity.task.stack != null) {
311                             key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
312                                     key.who, key.requestCode, code, finalIntent);
313                         }
314                         break;
315                     case ActivityManager.INTENT_SENDER_BROADCAST:
316                         try {
317                             // If a completion callback has been requested, require
318                             // that the broadcast be delivered synchronously
319                             int sent = owner.broadcastIntentInPackage(key.packageName, uid,
320                                     finalIntent, resolvedType, finishedReceiver, code, null, null,
321                                     requiredPermission, options, (finishedReceiver != null),
322                                     false, userId);
323                             if (sent == ActivityManager.BROADCAST_SUCCESS) {
324                                 sendFinish = false;
325                             }
326                         } catch (RuntimeException e) {
327                             Slog.w(TAG, "Unable to send startActivity intent", e);
328                         }
329                         break;
330                     case ActivityManager.INTENT_SENDER_SERVICE:
331                         try {
332                             owner.startServiceInPackage(uid, finalIntent,
333                                     resolvedType, key.packageName, userId);
334                         } catch (RuntimeException e) {
335                             Slog.w(TAG, "Unable to send startService intent", e);
336                         } catch (TransactionTooLargeException e) {
337                             res = ActivityManager.START_CANCELED;
338                         }
339                         break;
340                 }
341 
342                 if (sendFinish && res != ActivityManager.START_CANCELED) {
343                     try {
344                         finishedReceiver.performReceive(new Intent(finalIntent), 0,
345                                 null, null, false, false, key.userId);
346                     } catch (RemoteException e) {
347                     }
348                 }
349 
350                 Binder.restoreCallingIdentity(origId);
351 
352                 return res;
353             }
354         }
355         return ActivityManager.START_CANCELED;
356     }
357 
358     @Override
finalize()359     protected void finalize() throws Throwable {
360         try {
361             if (!canceled) {
362                 owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
363                         ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
364             }
365         } finally {
366             super.finalize();
367         }
368     }
369 
completeFinalize()370     public void completeFinalize() {
371         synchronized(owner) {
372             WeakReference<PendingIntentRecord> current =
373                     owner.mIntentSenderRecords.get(key);
374             if (current == ref) {
375                 owner.mIntentSenderRecords.remove(key);
376             }
377         }
378     }
379 
dump(PrintWriter pw, String prefix)380     void dump(PrintWriter pw, String prefix) {
381         pw.print(prefix); pw.print("uid="); pw.print(uid);
382                 pw.print(" packageName="); pw.print(key.packageName);
383                 pw.print(" type="); pw.print(key.typeName());
384                 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags));
385         if (key.activity != null || key.who != null) {
386             pw.print(prefix); pw.print("activity="); pw.print(key.activity);
387                     pw.print(" who="); pw.println(key.who);
388         }
389         if (key.requestCode != 0 || key.requestResolvedType != null) {
390             pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
391                     pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
392         }
393         if (key.requestIntent != null) {
394             pw.print(prefix); pw.print("requestIntent=");
395                     pw.println(key.requestIntent.toShortString(false, true, true, true));
396         }
397         if (sent || canceled) {
398             pw.print(prefix); pw.print("sent="); pw.print(sent);
399                     pw.print(" canceled="); pw.println(canceled);
400         }
401         if (whitelistDuration != 0) {
402             pw.print(prefix);
403             pw.print("whitelistDuration=");
404             TimeUtils.formatDuration(whitelistDuration, pw);
405             pw.println();
406         }
407     }
408 
toString()409     public String toString() {
410         if (stringName != null) {
411             return stringName;
412         }
413         StringBuilder sb = new StringBuilder(128);
414         sb.append("PendingIntentRecord{");
415         sb.append(Integer.toHexString(System.identityHashCode(this)));
416         sb.append(' ');
417         sb.append(key.packageName);
418         sb.append(' ');
419         sb.append(key.typeName());
420         if (whitelistDuration > 0) {
421             sb.append( " (whitelist: ");
422             TimeUtils.formatDuration(whitelistDuration, sb);
423             sb.append(")");
424         }
425         sb.append('}');
426         return stringName = sb.toString();
427     }
428 }
429