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 import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_OWNER_CANCELED; 26 import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_SUPERSEDED; 27 28 import android.annotation.Nullable; 29 import android.app.Activity; 30 import android.app.ActivityManagerInternal; 31 import android.app.ActivityOptions; 32 import android.app.AppGlobals; 33 import android.app.PendingIntent; 34 import android.app.PendingIntentStats; 35 import android.app.compat.CompatChanges; 36 import android.content.IIntentSender; 37 import android.content.Intent; 38 import android.os.Binder; 39 import android.os.Bundle; 40 import android.os.Handler; 41 import android.os.IBinder; 42 import android.os.Looper; 43 import android.os.Message; 44 import android.os.PowerWhitelistManager; 45 import android.os.RemoteCallbackList; 46 import android.os.RemoteException; 47 import android.os.UserHandle; 48 import android.util.ArrayMap; 49 import android.util.Slog; 50 import android.util.SparseArray; 51 import android.util.SparseIntArray; 52 53 import com.android.internal.annotations.GuardedBy; 54 import com.android.internal.os.IResultReceiver; 55 import com.android.internal.util.RingBuffer; 56 import com.android.internal.util.function.pooled.PooledLambda; 57 import com.android.server.AlarmManagerInternal; 58 import com.android.server.LocalServices; 59 import com.android.server.am.PendingIntentRecord.CancellationReason; 60 import com.android.server.wm.ActivityTaskManagerInternal; 61 import com.android.server.wm.SafeActivityOptions; 62 63 import java.io.PrintWriter; 64 import java.lang.ref.WeakReference; 65 import java.util.ArrayList; 66 import java.util.Arrays; 67 import java.util.HashMap; 68 import java.util.Iterator; 69 import java.util.List; 70 71 /** 72 * Helper class for {@link ActivityManagerService} responsible for managing pending intents. 73 * 74 * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of 75 * {@link ActivityManagerService} lock since there can be direct calls into this class from outside 76 * AM. This helps avoid deadlocks. 77 */ 78 public class PendingIntentController { 79 private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM; 80 private static final String TAG_MU = TAG + POSTFIX_MU; 81 82 /** @see {@link #mRecentIntentsPerUid}. */ 83 private static final int RECENT_N = 10; 84 85 /** Lock for internal state. */ 86 final Object mLock = new Object(); 87 final Handler mH; 88 ActivityManagerInternal mAmInternal; 89 final UserController mUserController; 90 final ActivityTaskManagerInternal mAtmInternal; 91 92 /** Set of IntentSenderRecord objects that are currently active. */ 93 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords 94 = new HashMap<>(); 95 96 /** The number of PendingIntentRecord per uid */ 97 @GuardedBy("mLock") 98 private final SparseIntArray mIntentsPerUid = new SparseIntArray(); 99 100 /** The recent PendingIntentRecord, up to {@link #RECENT_N} per uid */ 101 @GuardedBy("mLock") 102 private final SparseArray<RingBuffer<String>> mRecentIntentsPerUid = new SparseArray<>(); 103 104 private final ActivityManagerConstants mConstants; 105 PendingIntentController(Looper looper, UserController userController, ActivityManagerConstants constants)106 PendingIntentController(Looper looper, UserController userController, 107 ActivityManagerConstants constants) { 108 mH = new Handler(looper); 109 mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); 110 mUserController = userController; 111 mConstants = constants; 112 } 113 onActivityManagerInternalAdded()114 void onActivityManagerInternalAdded() { 115 synchronized (mLock) { 116 mAmInternal = LocalServices.getService(ActivityManagerInternal.class); 117 } 118 } 119 getIntentSender(int type, String packageName, @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions)120 public PendingIntentRecord getIntentSender(int type, String packageName, 121 @Nullable String featureId, int callingUid, int userId, IBinder token, String resultWho, 122 int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions) { 123 synchronized (mLock) { 124 if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid); 125 126 // We're going to be splicing together extras before sending, so we're 127 // okay poking into any contained extras. 128 if (intents != null) { 129 for (int i = 0; i < intents.length; i++) { 130 intents[i].setDefusable(true); 131 } 132 } 133 Bundle.setDefusable(bOptions, true); 134 ActivityOptions opts = ActivityOptions.fromBundle(bOptions); 135 if (opts != null && opts.getPendingIntentBackgroundActivityStartMode() 136 != ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) { 137 Slog.wtf(TAG, "Resetting option setPendingIntentBackgroundActivityStartMode(" 138 + opts.getPendingIntentBackgroundActivityStartMode() 139 + ") to SYSTEM_DEFINED from the options provided by the pending " 140 + "intent creator (" 141 + packageName 142 + ") because this option is meant for the pending intent sender"); 143 if (CompatChanges.isChangeEnabled(PendingIntent.PENDING_INTENT_OPTIONS_CHECK, 144 callingUid)) { 145 throw new IllegalArgumentException("pendingIntentBackgroundActivityStartMode " 146 + "must not be set when creating a PendingIntent"); 147 } 148 opts.setPendingIntentBackgroundActivityStartMode( 149 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); 150 } 151 152 final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; 153 final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0; 154 final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0; 155 flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT 156 | PendingIntent.FLAG_UPDATE_CURRENT); 157 158 PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, featureId, 159 token, resultWho, requestCode, intents, resolvedTypes, flags, 160 new SafeActivityOptions(opts, Binder.getCallingPid(), Binder.getCallingUid()), 161 userId); 162 WeakReference<PendingIntentRecord> ref; 163 ref = mIntentSenderRecords.get(key); 164 PendingIntentRecord rec = ref != null ? ref.get() : null; 165 if (rec != null) { 166 if (!cancelCurrent) { 167 if (updateCurrent) { 168 if (rec.key.requestIntent != null) { 169 rec.key.requestIntent.replaceExtras(intents != null ? 170 intents[intents.length - 1] : null); 171 } 172 if (intents != null) { 173 intents[intents.length - 1] = rec.key.requestIntent; 174 rec.key.allIntents = intents; 175 rec.key.allResolvedTypes = resolvedTypes; 176 } else { 177 rec.key.allIntents = null; 178 rec.key.allResolvedTypes = null; 179 } 180 } 181 return rec; 182 } 183 makeIntentSenderCanceled(rec, CANCEL_REASON_SUPERSEDED); 184 mIntentSenderRecords.remove(key); 185 decrementUidStatLocked(rec); 186 } 187 if (noCreate) { 188 return rec; 189 } 190 rec = new PendingIntentRecord(this, key, callingUid); 191 mIntentSenderRecords.put(key, rec.ref); 192 incrementUidStatLocked(rec); 193 return rec; 194 } 195 } 196 removePendingIntentsForPackage(String packageName, int userId, int appId, boolean doIt, @CancellationReason int cancelReason)197 boolean removePendingIntentsForPackage(String packageName, int userId, int appId, 198 boolean doIt, @CancellationReason int cancelReason) { 199 200 boolean didSomething = false; 201 synchronized (mLock) { 202 203 // Remove pending intents. For now we only do this when force stopping users, because 204 // we have some problems when doing this for packages -- app widgets are not currently 205 // cleaned up for such packages, so they can be left with bad pending intents. 206 if (mIntentSenderRecords.size() <= 0) { 207 return false; 208 } 209 210 Iterator<WeakReference<PendingIntentRecord>> it 211 = mIntentSenderRecords.values().iterator(); 212 while (it.hasNext()) { 213 WeakReference<PendingIntentRecord> wpir = it.next(); 214 if (wpir == null) { 215 it.remove(); 216 continue; 217 } 218 PendingIntentRecord pir = wpir.get(); 219 if (pir == null) { 220 it.remove(); 221 continue; 222 } 223 if (packageName == null) { 224 // Stopping user, remove all objects for the user. 225 if (pir.key.userId != userId) { 226 // Not the same user, skip it. 227 continue; 228 } 229 } else { 230 if (UserHandle.getAppId(pir.uid) != appId) { 231 // Different app id, skip it. 232 continue; 233 } 234 if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { 235 // Different user, skip it. 236 continue; 237 } 238 if (!pir.key.packageName.equals(packageName)) { 239 // Different package, skip it. 240 continue; 241 } 242 } 243 if (!doIt) { 244 return true; 245 } 246 didSomething = true; 247 it.remove(); 248 makeIntentSenderCanceled(pir, cancelReason); 249 decrementUidStatLocked(pir); 250 if (pir.key.activity != null) { 251 final Message m = PooledLambda.obtainMessage( 252 PendingIntentController::clearPendingResultForActivity, this, 253 pir.key.activity, pir.ref); 254 mH.sendMessage(m); 255 } 256 } 257 } 258 259 return didSomething; 260 } 261 cancelIntentSender(IIntentSender sender)262 public void cancelIntentSender(IIntentSender sender) { 263 if (!(sender instanceof PendingIntentRecord)) { 264 return; 265 } 266 synchronized (mLock) { 267 final PendingIntentRecord rec = (PendingIntentRecord) sender; 268 try { 269 final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, 270 MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); 271 if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { 272 String msg = "Permission Denial: cancelIntentSender() from pid=" 273 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 274 + " is not allowed to cancel package " + rec.key.packageName; 275 Slog.w(TAG, msg); 276 throw new SecurityException(msg); 277 } 278 } catch (RemoteException e) { 279 throw new SecurityException(e); 280 } 281 cancelIntentSender(rec, true, CANCEL_REASON_OWNER_CANCELED); 282 } 283 } 284 cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity, @CancellationReason int cancelReason)285 public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity, 286 @CancellationReason int cancelReason) { 287 synchronized (mLock) { 288 makeIntentSenderCanceled(rec, cancelReason); 289 mIntentSenderRecords.remove(rec.key); 290 decrementUidStatLocked(rec); 291 if (cleanActivity && rec.key.activity != null) { 292 final Message m = PooledLambda.obtainMessage( 293 PendingIntentController::clearPendingResultForActivity, this, 294 rec.key.activity, rec.ref); 295 mH.sendMessage(m); 296 } 297 } 298 } 299 registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver)300 boolean registerIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver) { 301 if (!(sender instanceof PendingIntentRecord)) { 302 Slog.w(TAG, "registerIntentSenderCancelListener called on non-PendingIntentRecord"); 303 // In this case, it's not "success", but we don't know if it's canceld either. 304 return true; 305 } 306 boolean isCancelled; 307 synchronized (mLock) { 308 PendingIntentRecord pendingIntent = (PendingIntentRecord) sender; 309 isCancelled = pendingIntent.canceled; 310 if (!isCancelled) { 311 pendingIntent.registerCancelListenerLocked(receiver); 312 return true; 313 } else { 314 return false; 315 } 316 } 317 } 318 unregisterIntentSenderCancelListener(IIntentSender sender, IResultReceiver receiver)319 void unregisterIntentSenderCancelListener(IIntentSender sender, 320 IResultReceiver receiver) { 321 if (!(sender instanceof PendingIntentRecord)) { 322 return; 323 } 324 synchronized (mLock) { 325 ((PendingIntentRecord) sender).unregisterCancelListenerLocked(receiver); 326 } 327 } 328 setPendingIntentAllowlistDuration(IIntentSender target, IBinder allowlistToken, long duration, int type, @PowerWhitelistManager.ReasonCode int reasonCode, @Nullable String reason)329 void setPendingIntentAllowlistDuration(IIntentSender target, IBinder allowlistToken, 330 long duration, int type, @PowerWhitelistManager.ReasonCode int reasonCode, 331 @Nullable String reason) { 332 if (!(target instanceof PendingIntentRecord)) { 333 Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target); 334 return; 335 } 336 synchronized (mLock) { 337 ((PendingIntentRecord) target).setAllowlistDurationLocked(allowlistToken, duration, 338 type, reasonCode, reason); 339 } 340 } 341 getPendingIntentFlags(IIntentSender target)342 int getPendingIntentFlags(IIntentSender target) { 343 if (!(target instanceof PendingIntentRecord)) { 344 Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target); 345 return 0; 346 } 347 synchronized (mLock) { 348 return ((PendingIntentRecord) target).key.flags; 349 } 350 } 351 makeIntentSenderCanceled(PendingIntentRecord rec, @CancellationReason int cancelReason)352 private void makeIntentSenderCanceled(PendingIntentRecord rec, 353 @CancellationReason int cancelReason) { 354 rec.canceled = true; 355 rec.cancelReason = cancelReason; 356 final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); 357 if (callbacks != null) { 358 final Message m = PooledLambda.obtainMessage( 359 PendingIntentController::handlePendingIntentCancelled, this, callbacks); 360 mH.sendMessage(m); 361 } 362 final AlarmManagerInternal ami = LocalServices.getService(AlarmManagerInternal.class); 363 ami.remove(new PendingIntent(rec)); 364 } 365 handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks)366 private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) { 367 int N = callbacks.beginBroadcast(); 368 for (int i = 0; i < N; i++) { 369 try { 370 callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); 371 } catch (RemoteException e) { 372 // Process is not longer running...whatever. 373 } 374 } 375 callbacks.finishBroadcast(); 376 // We have to clean up the RemoteCallbackList here, because otherwise it will 377 // needlessly hold the enclosed callbacks until the remote process dies. 378 callbacks.kill(); 379 } 380 clearPendingResultForActivity(IBinder activityToken, WeakReference<PendingIntentRecord> pir)381 private void clearPendingResultForActivity(IBinder activityToken, 382 WeakReference<PendingIntentRecord> pir) { 383 mAtmInternal.clearPendingResultForActivity(activityToken, pir); 384 } 385 dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage)386 void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) { 387 synchronized (mLock) { 388 boolean printed = false; 389 390 pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); 391 392 if (mIntentSenderRecords.size() > 0) { 393 // Organize these by package name, so they are easier to read. 394 final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); 395 final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); 396 final Iterator<WeakReference<PendingIntentRecord>> it 397 = mIntentSenderRecords.values().iterator(); 398 while (it.hasNext()) { 399 WeakReference<PendingIntentRecord> ref = it.next(); 400 PendingIntentRecord rec = ref != null ? ref.get() : null; 401 if (rec == null) { 402 weakRefs.add(ref); 403 continue; 404 } 405 if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { 406 continue; 407 } 408 ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); 409 if (list == null) { 410 list = new ArrayList<>(); 411 byPackage.put(rec.key.packageName, list); 412 } 413 list.add(rec); 414 } 415 for (int i = 0; i < byPackage.size(); i++) { 416 ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); 417 printed = true; 418 pw.print(" * "); pw.print(byPackage.keyAt(i)); 419 pw.print(": "); pw.print(intents.size()); pw.println(" items"); 420 for (int j = 0; j < intents.size(); j++) { 421 pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); 422 if (dumpAll) { 423 intents.get(j).dump(pw, " "); 424 } 425 } 426 } 427 if (weakRefs.size() > 0) { 428 printed = true; 429 pw.println(" * WEAK REFS:"); 430 for (int i = 0; i < weakRefs.size(); i++) { 431 pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); 432 } 433 } 434 } 435 436 final int sizeOfIntentsPerUid = mIntentsPerUid.size(); 437 if (sizeOfIntentsPerUid > 0) { 438 for (int i = 0; i < sizeOfIntentsPerUid; i++) { 439 pw.print(" * UID: "); 440 pw.print(mIntentsPerUid.keyAt(i)); 441 pw.print(" total: "); 442 pw.println(mIntentsPerUid.valueAt(i)); 443 } 444 } 445 446 if (!printed) { 447 pw.println(" (nothing)"); 448 } 449 } 450 } 451 452 /** 453 * Provides some stats tracking of the current state of the PendingIntent queue. 454 * 455 * Data about the pending intent queue is intended to be used for memory impact tracking. 456 * Returned data (one per uid) will consist of instances of PendingIntentStats containing 457 * (I) number of PendingIntents and (II) total size of all bundled extras in the PIs. 458 * 459 * @hide 460 */ dumpPendingIntentStatsForStatsd()461 public List<PendingIntentStats> dumpPendingIntentStatsForStatsd() { 462 List<PendingIntentStats> pendingIntentStats = new ArrayList<>(); 463 464 synchronized (mLock) { 465 if (mIntentSenderRecords.size() > 0) { 466 // First, aggregate PendingIntent data by package uid. 467 final SparseIntArray countsByUid = new SparseIntArray(); 468 final SparseIntArray bundleSizesByUid = new SparseIntArray(); 469 470 for (WeakReference<PendingIntentRecord> reference : mIntentSenderRecords.values()) { 471 if (reference == null || reference.get() == null) { 472 continue; 473 } 474 PendingIntentRecord record = reference.get(); 475 int index = countsByUid.indexOfKey(record.uid); 476 477 if (index < 0) { // ie. the key was not found 478 countsByUid.put(record.uid, 1); 479 bundleSizesByUid.put(record.uid, 480 record.key.requestIntent.getExtrasTotalSize()); 481 } else { 482 countsByUid.put(record.uid, countsByUid.valueAt(index) + 1); 483 bundleSizesByUid.put(record.uid, 484 bundleSizesByUid.valueAt(index) 485 + record.key.requestIntent.getExtrasTotalSize()); 486 } 487 } 488 489 // Now generate the output. 490 for (int i = 0, size = countsByUid.size(); i < size; i++) { 491 pendingIntentStats.add(new PendingIntentStats( 492 countsByUid.keyAt(i), 493 countsByUid.valueAt(i), 494 /* NB: int conversion here */ bundleSizesByUid.valueAt(i) / 1024)); 495 } 496 } 497 } 498 return pendingIntentStats; 499 } 500 501 /** 502 * Increment the number of the PendingIntentRecord for the given uid, log a warning 503 * if there are too many for this uid already. 504 */ 505 @GuardedBy("mLock") incrementUidStatLocked(final PendingIntentRecord pir)506 void incrementUidStatLocked(final PendingIntentRecord pir) { 507 final int uid = pir.uid; 508 final int idx = mIntentsPerUid.indexOfKey(uid); 509 int newCount = 1; 510 if (idx >= 0) { 511 newCount = mIntentsPerUid.valueAt(idx) + 1; 512 mIntentsPerUid.setValueAt(idx, newCount); 513 } else { 514 mIntentsPerUid.put(uid, newCount); 515 } 516 517 // If the number is within the range [threshold - N + 1, threshold], log it into buffer 518 final int lowBound = mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N + 1; 519 RingBuffer<String> recentHistory = null; 520 if (newCount == lowBound) { 521 recentHistory = new RingBuffer(String.class, RECENT_N); 522 mRecentIntentsPerUid.put(uid, recentHistory); 523 } else if (newCount > lowBound && newCount <= mConstants.PENDINGINTENT_WARNING_THRESHOLD) { 524 recentHistory = mRecentIntentsPerUid.get(uid); 525 } 526 if (recentHistory == null) { 527 return; 528 } 529 530 recentHistory.append(pir.key.toString()); 531 532 // Output the log if we are hitting the threshold 533 if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD) { 534 Slog.wtf(TAG, "Too many PendingIntent created for uid " + uid 535 + ", recent " + RECENT_N + ": " + Arrays.toString(recentHistory.toArray())); 536 // Clear the buffer, as we don't want to spam the log when the numbers 537 // are jumping up and down around the threshold. 538 mRecentIntentsPerUid.remove(uid); 539 } 540 } 541 542 /** 543 * Decrement the number of the PendingIntentRecord for the given uid. 544 */ 545 @GuardedBy("mLock") decrementUidStatLocked(final PendingIntentRecord pir)546 void decrementUidStatLocked(final PendingIntentRecord pir) { 547 final int uid = pir.uid; 548 final int idx = mIntentsPerUid.indexOfKey(uid); 549 if (idx >= 0) { 550 final int newCount = mIntentsPerUid.valueAt(idx) - 1; 551 // If we are going below the low threshold, no need to keep logs. 552 if (newCount == mConstants.PENDINGINTENT_WARNING_THRESHOLD - RECENT_N) { 553 mRecentIntentsPerUid.delete(uid); 554 } 555 if (newCount == 0) { 556 mIntentsPerUid.removeAt(idx); 557 } else { 558 mIntentsPerUid.setValueAt(idx, newCount); 559 } 560 } 561 } 562 } 563