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