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