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