• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
20 
21 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
22 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
23 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
24 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
25 
26 import android.app.Activity;
27 import android.app.ActivityManagerInternal;
28 import android.app.AppGlobals;
29 import android.app.PendingIntent;
30 import android.content.IIntentSender;
31 import android.content.Intent;
32 import android.os.Binder;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.os.IBinder;
36 import android.os.Looper;
37 import android.os.Message;
38 import android.os.RemoteCallbackList;
39 import android.os.RemoteException;
40 import android.os.UserHandle;
41 import android.util.ArrayMap;
42 import android.util.Slog;
43 
44 import com.android.internal.os.IResultReceiver;
45 import com.android.internal.util.function.pooled.PooledLambda;
46 import com.android.server.LocalServices;
47 import com.android.server.wm.ActivityTaskManagerInternal;
48 import com.android.server.wm.SafeActivityOptions;
49 
50 import java.io.PrintWriter;
51 import java.lang.ref.WeakReference;
52 import java.util.ArrayList;
53 import java.util.HashMap;
54 import java.util.Iterator;
55 
56 /**
57  * Helper class for {@link ActivityManagerService} responsible for managing pending intents.
58  *
59  * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of
60  * {@link ActivityManagerService} lock since there can be direct calls into this class from outside
61  * AM. This helps avoid deadlocks.
62  */
63 public class PendingIntentController {
64     private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM;
65     private static final String TAG_MU = TAG + POSTFIX_MU;
66 
67     /** Lock for internal state. */
68     final Object mLock = new Object();
69     final Handler mH;
70     ActivityManagerInternal mAmInternal;
71     final UserController mUserController;
72     final ActivityTaskManagerInternal mAtmInternal;
73 
74     /** Set of IntentSenderRecord objects that are currently active. */
75     final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
76             = new HashMap<>();
77 
PendingIntentController(Looper looper, UserController userController)78     PendingIntentController(Looper looper, UserController userController) {
79         mH = new Handler(looper);
80         mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
81         mUserController = userController;
82     }
83 
onActivityManagerInternalAdded()84     void onActivityManagerInternalAdded() {
85         synchronized (mLock) {
86             mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
87         }
88     }
89 
getIntentSender(int type, String packageName, int callingUid, int userId, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions)90     public PendingIntentRecord getIntentSender(int type, String packageName, int callingUid,
91             int userId, IBinder token, String resultWho, int requestCode, Intent[] intents,
92             String[] resolvedTypes, int flags, Bundle bOptions) {
93         synchronized (mLock) {
94             if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid);
95 
96             // We're going to be splicing together extras before sending, so we're
97             // okay poking into any contained extras.
98             if (intents != null) {
99                 for (int i = 0; i < intents.length; i++) {
100                     intents[i].setDefusable(true);
101                 }
102             }
103             Bundle.setDefusable(bOptions, true);
104 
105             final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0;
106             final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0;
107             final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0;
108             flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT
109                     | PendingIntent.FLAG_UPDATE_CURRENT);
110 
111             PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token,
112                     resultWho, requestCode, intents, resolvedTypes, flags,
113                     SafeActivityOptions.fromBundle(bOptions), userId);
114             WeakReference<PendingIntentRecord> ref;
115             ref = mIntentSenderRecords.get(key);
116             PendingIntentRecord rec = ref != null ? ref.get() : null;
117             if (rec != null) {
118                 if (!cancelCurrent) {
119                     if (updateCurrent) {
120                         if (rec.key.requestIntent != null) {
121                             rec.key.requestIntent.replaceExtras(intents != null ?
122                                     intents[intents.length - 1] : null);
123                         }
124                         if (intents != null) {
125                             intents[intents.length - 1] = rec.key.requestIntent;
126                             rec.key.allIntents = intents;
127                             rec.key.allResolvedTypes = resolvedTypes;
128                         } else {
129                             rec.key.allIntents = null;
130                             rec.key.allResolvedTypes = null;
131                         }
132                     }
133                     return rec;
134                 }
135                 makeIntentSenderCanceled(rec);
136                 mIntentSenderRecords.remove(key);
137             }
138             if (noCreate) {
139                 return rec;
140             }
141             rec = new PendingIntentRecord(this, key, callingUid);
142             mIntentSenderRecords.put(key, rec.ref);
143             return rec;
144         }
145     }
146 
removePendingIntentsForPackage(String packageName, int userId, int appId, boolean doIt)147     boolean removePendingIntentsForPackage(String packageName, int userId, int appId,
148             boolean doIt) {
149 
150         boolean didSomething = false;
151         synchronized (mLock) {
152 
153             // Remove pending intents.  For now we only do this when force stopping users, because
154             // we have some problems when doing this for packages -- app widgets are not currently
155             // cleaned up for such packages, so they can be left with bad pending intents.
156             if (mIntentSenderRecords.size() <= 0) {
157                 return false;
158             }
159 
160             Iterator<WeakReference<PendingIntentRecord>> it
161                     = mIntentSenderRecords.values().iterator();
162             while (it.hasNext()) {
163                 WeakReference<PendingIntentRecord> wpir = it.next();
164                 if (wpir == null) {
165                     it.remove();
166                     continue;
167                 }
168                 PendingIntentRecord pir = wpir.get();
169                 if (pir == null) {
170                     it.remove();
171                     continue;
172                 }
173                 if (packageName == null) {
174                     // Stopping user, remove all objects for the user.
175                     if (pir.key.userId != userId) {
176                         // Not the same user, skip it.
177                         continue;
178                     }
179                 } else {
180                     if (UserHandle.getAppId(pir.uid) != appId) {
181                         // Different app id, skip it.
182                         continue;
183                     }
184                     if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
185                         // Different user, skip it.
186                         continue;
187                     }
188                     if (!pir.key.packageName.equals(packageName)) {
189                         // Different package, skip it.
190                         continue;
191                     }
192                 }
193                 if (!doIt) {
194                     return true;
195                 }
196                 didSomething = true;
197                 it.remove();
198                 makeIntentSenderCanceled(pir);
199                 if (pir.key.activity != null) {
200                     final Message m = PooledLambda.obtainMessage(
201                             PendingIntentController::clearPendingResultForActivity, this,
202                             pir.key.activity, pir.ref);
203                     mH.sendMessage(m);
204                 }
205             }
206         }
207 
208         return didSomething;
209     }
210 
cancelIntentSender(IIntentSender sender)211     public void cancelIntentSender(IIntentSender sender) {
212         if (!(sender instanceof PendingIntentRecord)) {
213             return;
214         }
215         synchronized (mLock) {
216             final PendingIntentRecord rec = (PendingIntentRecord) sender;
217             try {
218                 final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName,
219                         MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId());
220                 if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
221                     String msg = "Permission Denial: cancelIntentSender() from pid="
222                             + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
223                             + " is not allowed to cancel package " + rec.key.packageName;
224                     Slog.w(TAG, msg);
225                     throw new SecurityException(msg);
226                 }
227             } catch (RemoteException e) {
228                 throw new SecurityException(e);
229             }
230             cancelIntentSender(rec, true);
231         }
232     }
233 
cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity)234     public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) {
235         synchronized (mLock) {
236             makeIntentSenderCanceled(rec);
237             mIntentSenderRecords.remove(rec.key);
238             if (cleanActivity && rec.key.activity != null) {
239                 final Message m = PooledLambda.obtainMessage(
240                         PendingIntentController::clearPendingResultForActivity, this,
241                         rec.key.activity, rec.ref);
242                 mH.sendMessage(m);
243             }
244         }
245     }
246 
registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver)247     void registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) {
248         if (!(sender instanceof PendingIntentRecord)) {
249             return;
250         }
251         boolean isCancelled;
252         synchronized (mLock) {
253             PendingIntentRecord pendingIntent = (PendingIntentRecord) sender;
254             isCancelled = pendingIntent.canceled;
255             if (!isCancelled) {
256                 pendingIntent.registerCancelListenerLocked(receiver);
257             }
258         }
259         if (isCancelled) {
260             try {
261                 receiver.send(Activity.RESULT_CANCELED, null);
262             } catch (RemoteException e) {
263             }
264         }
265     }
266 
unregisterIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver)267     void unregisterIntentSenderCancelListener(IIntentSender sender,
268             IResultReceiver receiver) {
269         if (!(sender instanceof PendingIntentRecord)) {
270             return;
271         }
272         synchronized (mLock) {
273             ((PendingIntentRecord) sender).unregisterCancelListenerLocked(receiver);
274         }
275     }
276 
setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken, long duration)277     void setPendingIntentWhitelistDuration(IIntentSender target, IBinder whitelistToken,
278             long duration) {
279         if (!(target instanceof PendingIntentRecord)) {
280             Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
281             return;
282         }
283         synchronized (mLock) {
284             ((PendingIntentRecord) target).setWhitelistDurationLocked(whitelistToken, duration);
285         }
286     }
287 
makeIntentSenderCanceled(PendingIntentRecord rec)288     private void makeIntentSenderCanceled(PendingIntentRecord rec) {
289         rec.canceled = true;
290         final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
291         if (callbacks != null) {
292             final Message m = PooledLambda.obtainMessage(
293                     PendingIntentController::handlePendingIntentCancelled, this, callbacks);
294             mH.sendMessage(m);
295         }
296     }
297 
handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks)298     private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) {
299         int N = callbacks.beginBroadcast();
300         for (int i = 0; i < N; i++) {
301             try {
302                 callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null);
303             } catch (RemoteException e) {
304                 // Process is not longer running...whatever.
305             }
306         }
307         callbacks.finishBroadcast();
308         // We have to clean up the RemoteCallbackList here, because otherwise it will
309         // needlessly hold the enclosed callbacks until the remote process dies.
310         callbacks.kill();
311     }
312 
clearPendingResultForActivity(IBinder activityToken, WeakReference<PendingIntentRecord> pir)313     private void clearPendingResultForActivity(IBinder activityToken,
314             WeakReference<PendingIntentRecord> pir) {
315         mAtmInternal.clearPendingResultForActivity(activityToken, pir);
316     }
317 
dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage)318     void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) {
319         synchronized (mLock) {
320             boolean printed = false;
321 
322             pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
323 
324             if (mIntentSenderRecords.size() > 0) {
325                 // Organize these by package name, so they are easier to read.
326                 final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>();
327                 final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>();
328                 final Iterator<WeakReference<PendingIntentRecord>> it
329                         = mIntentSenderRecords.values().iterator();
330                 while (it.hasNext()) {
331                     WeakReference<PendingIntentRecord> ref = it.next();
332                     PendingIntentRecord rec = ref != null ? ref.get() : null;
333                     if (rec == null) {
334                         weakRefs.add(ref);
335                         continue;
336                     }
337                     if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) {
338                         continue;
339                     }
340                     ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName);
341                     if (list == null) {
342                         list = new ArrayList<>();
343                         byPackage.put(rec.key.packageName, list);
344                     }
345                     list.add(rec);
346                 }
347                 for (int i = 0; i < byPackage.size(); i++) {
348                     ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i);
349                     printed = true;
350                     pw.print("  * "); pw.print(byPackage.keyAt(i));
351                     pw.print(": "); pw.print(intents.size()); pw.println(" items");
352                     for (int j = 0; j < intents.size(); j++) {
353                         pw.print("    #"); pw.print(j); pw.print(": "); pw.println(intents.get(j));
354                         if (dumpAll) {
355                             intents.get(j).dump(pw, "      ");
356                         }
357                     }
358                 }
359                 if (weakRefs.size() > 0) {
360                     printed = true;
361                     pw.println("  * WEAK REFS:");
362                     for (int i = 0; i < weakRefs.size(); i++) {
363                         pw.print("    #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i));
364                     }
365                 }
366             }
367 
368             if (!printed) {
369                 pw.println("  (nothing)");
370             }
371         }
372     }
373 }
374