diff options
13 files changed, 702 insertions, 429 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index be1f2dbc8e4f..294a3ec73efd 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -19,11 +19,14 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; +import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.UserInfo; +import android.os.Bundle; import android.os.IBinder; +import android.os.TransactionTooLargeException; import android.view.RemoteAnimationAdapter; import java.util.ArrayList; @@ -232,4 +235,14 @@ public abstract class ActivityManagerInternal { public abstract void setBooted(boolean booted); public abstract boolean isBooted(); public abstract void finishBooting(); + + public abstract void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid, + long duration, String tag); + public abstract int broadcastIntentInPackage(String packageName, int uid, Intent intent, + String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, + Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, + boolean sticky, int userId); + public abstract ComponentName startServiceInPackage(int uid, Intent service, + String resolvedType, boolean fgRequired, String callingPackage, int userId) + throws TransactionTooLargeException; } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 510d333355a3..461d39d0a29a 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -629,7 +629,7 @@ public final class ActiveServices { return false; } - IIntentSender target = mAm.getIntentSenderLocked( + IIntentSender target = mAm.mPendingIntentController.getIntentSender( ActivityManager.INTENT_SENDER_SERVICE, callingPackage, callingUid, userId, null, null, 0, new Intent[]{service}, new String[]{service.resolveType(mAm.mContext.getContentResolver())}, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8c7fc849b79e..bb579183cd2f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -134,7 +134,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS; -import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; @@ -417,7 +416,6 @@ public class ActivityManagerService extends IActivityManager.Stub private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE; private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; private static final String TAG_UID_OBSERVERS = TAG + POSTFIX_UID_OBSERVERS; - private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION; // Mock "pretend we're idle now" broadcast action to the job scheduler; declared // here so that while the job scheduler can depend on AMS, the other way around @@ -563,6 +561,7 @@ public class ActivityManagerService extends IActivityManager.Stub String mDeviceOwnerName; final UserController mUserController; + final PendingIntentController mPendingIntentController; final AppErrors mAppErrors; @@ -821,12 +820,6 @@ public class ActivityManagerService extends IActivityManager.Stub final SparseArray<UidRecord> mValidateUids = new SparseArray<>(); /** - * Set of IntentSenderRecord objects that are currently active. - */ - final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords - = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>(); - - /** * Fingerprints (hashCode()) of stack traces that we've * already logged DropBox entries for. Guarded by itself. If * something (rogue user app) forces this over @@ -1426,7 +1419,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int UPDATE_TIME_ZONE = 13; static final int PROC_START_TIMEOUT_MSG = 20; static final int KILL_APPLICATION_MSG = 22; - static final int FINALIZE_PENDING_INTENT_MSG = 23; static final int SHOW_STRICT_MODE_VIOLATION_UI_MSG = 26; static final int CHECK_EXCESSIVE_POWER_USE_MSG = 27; static final int CLEAR_DNS_CACHE_MSG = 28; @@ -1445,7 +1437,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int IDLE_UIDS_MSG = 58; static final int HANDLE_TRUST_STORAGE_UPDATE_MSG = 63; static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66; - static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67; static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; @@ -1644,21 +1635,6 @@ public class ActivityManagerService extends IActivityManager.Stub mServices.serviceForegroundCrash( (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY)); } break; - case DISPATCH_PENDING_INTENT_CANCEL_MSG: { - RemoteCallbackList<IResultReceiver> callbacks - = (RemoteCallbackList<IResultReceiver>)msg.obj; - int N = callbacks.beginBroadcast(); - for (int i = 0; i < N; i++) { - try { - callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); - } catch (RemoteException e) { - } - } - callbacks.finishBroadcast(); - // We have to clean up the RemoteCallbackList here, because otherwise it will - // needlessly hold the enclosed callbacks until the remote process dies. - callbacks.kill(); - } break; case UPDATE_TIME_ZONE: { synchronized (ActivityManagerService.this) { for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { @@ -1738,9 +1714,6 @@ public class ActivityManagerService extends IActivityManager.Stub false, userId, reason); } } break; - case FINALIZE_PENDING_INTENT_MSG: { - ((PendingIntentRecord)msg.obj).completeFinalize(); - } break; case CHECK_EXCESSIVE_POWER_USE_MSG: { synchronized (ActivityManagerService.this) { checkExcessivePowerUsageLocked(); @@ -2354,6 +2327,7 @@ public class ActivityManagerService extends IActivityManager.Stub mSystemThread = null; mUiHandler = injector.getUiHandler(null); mUserController = null; + mPendingIntentController = null; mProcStartHandlerThread = null; mProcStartHandler = null; mHiddenApiBlacklist = null; @@ -2438,6 +2412,9 @@ public class ActivityManagerService extends IActivityManager.Stub mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mStackSupervisor = mActivityTaskManager.mStackSupervisor; + mPendingIntentController = new PendingIntentController( + mHandlerThread.getLooper(), mUserController); + mProcessCpuThread = new Thread("CpuTracker") { @Override public void run() { @@ -2508,6 +2485,7 @@ public class ActivityManagerService extends IActivityManager.Stub LocalServices.addService(ActivityManagerInternal.class, new LocalService()); mActivityTaskManager.onActivityManagerInternalAdded(); mUgmInternal.onActivityManagerInternalAdded(); + mPendingIntentController.onActivityManagerInternalAdded(); // Wait for the synchronized block started in mProcessCpuThread, // so that any other access to mProcessCpuTracker from main thread // will be blocked during mProcessCpuTracker initialization. @@ -5511,55 +5489,8 @@ public class ActivityManagerService extends IActivityManager.Stub } if (packageName == null || uninstalling) { - // Remove pending intents. For now we only do this when force - // stopping users, because we have some problems when doing this - // for packages -- app widgets are not currently cleaned up for - // such packages, so they can be left with bad pending intents. - if (mIntentSenderRecords.size() > 0) { - Iterator<WeakReference<PendingIntentRecord>> it - = mIntentSenderRecords.values().iterator(); - while (it.hasNext()) { - WeakReference<PendingIntentRecord> wpir = it.next(); - if (wpir == null) { - it.remove(); - continue; - } - PendingIntentRecord pir = wpir.get(); - if (pir == null) { - it.remove(); - continue; - } - if (packageName == null) { - // Stopping user, remove all objects for the user. - if (pir.key.userId != userId) { - // Not the same user, skip it. - continue; - } - } else { - if (UserHandle.getAppId(pir.uid) != appId) { - // Different app id, skip it. - continue; - } - if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { - // Different user, skip it. - continue; - } - if (!pir.key.packageName.equals(packageName)) { - // Different package, skip it. - continue; - } - } - if (!doit) { - return true; - } - didSomething = true; - it.remove(); - makeIntentSenderCanceledLocked(pir); - if (pir.key.activity != null && pir.key.activity.pendingResults != null) { - pir.key.activity.pendingResults.remove(pir.ref); - } - } - } + didSomething |= mPendingIntentController.removePendingIntentsForPackage( + packageName, userId, appId, doit); } if (doit) { @@ -6342,90 +6273,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } - return getIntentSenderLocked(type, packageName, callingUid, userId, - token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); - + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + return mAtmInternal.getIntentSender(type, packageName, callingUid, userId, + token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); + } + return mPendingIntentController.getIntentSender(type, packageName, callingUid, + userId, token, resultWho, requestCode, intents, resolvedTypes, flags, + bOptions); } catch (RemoteException e) { throw new SecurityException(e); } } } - IIntentSender getIntentSenderLocked(int type, String packageName, - int callingUid, int userId, IBinder token, String resultWho, - int requestCode, Intent[] intents, String[] resolvedTypes, int flags, - Bundle bOptions) { - if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid); - ActivityRecord activity = null; - if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { - activity = ActivityRecord.isInStackLocked(token); - if (activity == null) { - Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); - return null; - } - if (activity.finishing) { - Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); - return null; - } - } - - // We're going to be splicing together extras before sending, so we're - // okay poking into any contained extras. - if (intents != null) { - for (int i = 0; i < intents.length; i++) { - intents[i].setDefusable(true); - } - } - Bundle.setDefusable(bOptions, true); - - final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0; - final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0; - final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0; - flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT - |PendingIntent.FLAG_UPDATE_CURRENT); - - PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, activity, - resultWho, requestCode, intents, resolvedTypes, flags, - SafeActivityOptions.fromBundle(bOptions), userId); - WeakReference<PendingIntentRecord> ref; - ref = mIntentSenderRecords.get(key); - PendingIntentRecord rec = ref != null ? ref.get() : null; - if (rec != null) { - if (!cancelCurrent) { - if (updateCurrent) { - if (rec.key.requestIntent != null) { - rec.key.requestIntent.replaceExtras(intents != null ? - intents[intents.length - 1] : null); - } - if (intents != null) { - intents[intents.length-1] = rec.key.requestIntent; - rec.key.allIntents = intents; - rec.key.allResolvedTypes = resolvedTypes; - } else { - rec.key.allIntents = null; - rec.key.allResolvedTypes = null; - } - } - return rec; - } - makeIntentSenderCanceledLocked(rec); - mIntentSenderRecords.remove(key); - } - if (noCreate) { - return rec; - } - rec = new PendingIntentRecord(this, key, callingUid); - mIntentSenderRecords.put(key, rec.ref); - if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { - if (activity.pendingResults == null) { - activity.pendingResults - = new HashSet<WeakReference<PendingIntentRecord>>(); - } - activity.pendingResults.add(rec.ref); - } - return rec; - } - @Override public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code, Intent intent, String resolvedType, @@ -6465,44 +6325,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void cancelIntentSender(IIntentSender sender) { - if (!(sender instanceof PendingIntentRecord)) { - return; - } - synchronized(this) { - PendingIntentRecord rec = (PendingIntentRecord)sender; - try { - final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, - MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); - if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { - String msg = "Permission Denial: cancelIntentSender() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + " is not allowed to cancel package " - + rec.key.packageName; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } - } catch (RemoteException e) { - throw new SecurityException(e); - } - cancelIntentSenderLocked(rec, true); - } - } - - void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) { - makeIntentSenderCanceledLocked(rec); - mIntentSenderRecords.remove(rec.key); - if (cleanActivity && rec.key.activity != null) { - rec.key.activity.pendingResults.remove(rec.ref); - } - } - - void makeIntentSenderCanceledLocked(PendingIntentRecord rec) { - rec.canceled = true; - RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); - if (callbacks != null) { - mHandler.obtainMessage(DISPATCH_PENDING_INTENT_CANCEL_MSG, callbacks).sendToTarget(); - } + mPendingIntentController.cancelIntentSender(sender); } @Override @@ -10866,7 +10689,7 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println("-------------------------------------------------------------------------------"); } - dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll, dumpPackage); + mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage); pw.println(); if (dumpAll) { pw.println("-------------------------------------------------------------------------------"); @@ -11159,7 +10982,7 @@ public class ActivityManagerService extends IActivityManager.Stub opti++; } synchronized (this) { - dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage); + mPendingIntentController.dumpPendingIntents(pw, true, dumpPackage); } } else if ("processes".equals(cmd) || "p".equals(cmd)) { if (opti < args.length) { @@ -12857,61 +12680,6 @@ public class ActivityManagerService extends IActivityManager.Stub mUgmInternal.dump(pw, dumpAll, dumpPackage); } - void dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args, - int opti, boolean dumpAll, String dumpPackage) { - boolean printed = false; - - pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); - - if (mIntentSenderRecords.size() > 0) { - // Organize these by package name, so they are easier to read. - final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); - final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); - final Iterator<WeakReference<PendingIntentRecord>> it - = mIntentSenderRecords.values().iterator(); - while (it.hasNext()) { - WeakReference<PendingIntentRecord> ref = it.next(); - PendingIntentRecord rec = ref != null ? ref.get() : null; - if (rec == null) { - weakRefs.add(ref); - continue; - } - if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { - continue; - } - ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); - if (list == null) { - list = new ArrayList<>(); - byPackage.put(rec.key.packageName, list); - } - list.add(rec); - } - for (int i = 0; i < byPackage.size(); i++) { - ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); - printed = true; - pw.print(" * "); pw.print(byPackage.keyAt(i)); - pw.print(": "); pw.print(intents.size()); pw.println(" items"); - for (int j = 0; j < intents.size(); j++) { - pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); - if (dumpAll) { - intents.get(j).dump(pw, " "); - } - } - } - if (weakRefs.size() > 0) { - printed = true; - pw.println(" * WEAK REFS:"); - for (int i = 0; i < weakRefs.size(); i++) { - pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); - } - } - } - - if (!printed) { - pw.println(" (nothing)"); - } - } - private static final int dumpProcessList(PrintWriter pw, ActivityManagerService service, List list, String prefix, String normalLabel, String persistentLabel, @@ -15186,24 +14954,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, - boolean fgRequired, String callingPackage, int userId) - throws TransactionTooLargeException { - synchronized(this) { - if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, - "startServiceInPackage: " + service + " type=" + resolvedType); - final long origId = Binder.clearCallingIdentity(); - ComponentName res; - try { - res = mServices.startServiceLocked(null, service, - resolvedType, -1, uid, fgRequired, callingPackage, userId); - } finally { - Binder.restoreCallingIdentity(origId); - } - return res; - } - } - @Override public int stopService(IApplicationThread caller, Intent service, String resolvedType, int userId) { @@ -21091,6 +20841,46 @@ public class ActivityManagerService extends IActivityManager.Stub public void finishBooting() { ActivityManagerService.this.finishBooting(); } + + @Override + public void tempWhitelistForPendingIntent(int callerPid, int callerUid, int targetUid, + long duration, String tag) { + synchronized (ActivityManagerService.this) { + ActivityManagerService.this.tempWhitelistForPendingIntentLocked( + callerPid, callerUid, targetUid, duration, tag); + } + } + + @Override + public int broadcastIntentInPackage(String packageName, int uid, Intent intent, + String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, + Bundle resultExtras, String requiredPermission, Bundle bOptions, boolean serialized, + boolean sticky, int userId) { + synchronized (ActivityManagerService.this) { + return ActivityManagerService.this.broadcastIntentInPackage(packageName, uid, + intent, resolvedType, resultTo, resultCode, resultData, resultExtras, + requiredPermission, bOptions, serialized, sticky, userId); + } + } + + @Override + public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, + boolean fgRequired, String callingPackage, int userId) + throws TransactionTooLargeException { + synchronized(ActivityManagerService.this) { + if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, + "startServiceInPackage: " + service + " type=" + resolvedType); + final long origId = Binder.clearCallingIdentity(); + ComponentName res; + try { + res = mServices.startServiceLocked(null, service, + resolvedType, -1, uid, fgRequired, callingPackage, userId); + } finally { + Binder.restoreCallingIdentity(origId); + } + return res; + } + } } /** diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 35a1eb8ff616..63778a453470 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -4144,7 +4144,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai for (WeakReference<PendingIntentRecord> apr : r.pendingResults) { PendingIntentRecord rec = apr.get(); if (rec != null) { - mService.mAm.cancelIntentSenderLocked(rec, false); + mService.mPendingIntentController.cancelIntentSender(rec, false); } } r.pendingResults = null; diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index 177e2f563a4b..1fb8f871efcd 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -126,7 +126,7 @@ class ActivityStartInterceptor { private IntentSender createIntentSenderForOriginalIntent(int callingUid, int flags) { Bundle activityOptions = deferCrossProfileAppsAnimationIfNecessary(); - final IIntentSender target = mService.mAm.getIntentSenderLocked( + final IIntentSender target = mService.getIntentSenderLocked( INTENT_SENDER_ACTIVITY, mCallingPackage, callingUid, mUserId, null /*token*/, null /*resultCode*/, 0 /*requestCode*/, new Intent[] { mIntent }, new String[] { mResolvedType }, diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 7da0519ef2f0..890aafefdf0f 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -783,7 +783,7 @@ class ActivityStarter { if (aInfo != null) { if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired( aInfo.packageName, userId)) { - IIntentSender target = mService.mAm.getIntentSenderLocked( + IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingUid, userId, null, null, 0, new Intent[]{intent}, new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT @@ -1096,7 +1096,7 @@ class ActivityStarter { } } - IIntentSender target = mService.mAm.getIntentSenderLocked( + IIntentSender target = mService.getIntentSenderLocked( ActivityManager.INTENT_SENDER_ACTIVITY, "android", appCallingUid, userId, null, null, 0, new Intent[] { intent }, new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 4dc28510c5ec..add9f2a7e9d8 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -239,7 +239,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -276,6 +278,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { UriGrantsManagerInternal mUgmInternal; private PackageManagerInternal mPmInternal; private ActivityTaskManagerInternal mInternal; + PendingIntentController mPendingIntentController; /* Global service lock used by the package the owns this service. */ Object mGlobalLock; ActivityStackSupervisor mStackSupervisor; @@ -628,6 +631,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final File systemDir = SystemServiceManager.ensureSystemDir(); mAppWarnings = new AppWarnings(this, mUiContext, mH, mUiHandler, systemDir); mCompatModePackages = new CompatModePackages(this, systemDir, mH); + mPendingIntentController = mAm.mPendingIntentController; mTempConfig.setToDefaults(); mTempConfig.setLocales(LocaleList.getDefault()); @@ -5019,6 +5023,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } + IIntentSender getIntentSenderLocked(int type, String packageName, int callingUid, int userId, + IBinder token, String resultWho, int requestCode, Intent[] intents, + String[] resolvedTypes, int flags, Bundle bOptions) { + + ActivityRecord activity = null; + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + activity = ActivityRecord.isInStackLocked(token); + if (activity == null) { + Slog.w(TAG, "Failed createPendingResult: activity " + token + " not in any stack"); + return null; + } + if (activity.finishing) { + Slog.w(TAG, "Failed createPendingResult: activity " + activity + " is finishing"); + return null; + } + } + + final PendingIntentRecord rec = mPendingIntentController.getIntentSender(type, packageName, + callingUid, userId, token, resultWho, requestCode, intents, resolvedTypes, flags, + bOptions); + final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; + if (noCreate) { + return rec; + } + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + if (activity.pendingResults == null) { + activity.pendingResults = new HashSet<>(); + } + activity.pendingResults.add(rec.ref); + } + return rec; + } + // TODO(b/111541062): Update app time tracking to make it aware of multiple resumed activities private void startTimeTrackingFocusedActivityLocked() { final ActivityRecord resumedActivity = mStackSupervisor.getTopResumedActivity(); @@ -5310,6 +5347,31 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, + String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent) { + synchronized (mGlobalLock) { + return getActivityStartController().startActivitiesInPackage(uid, callingPackage, + intents, resolvedTypes, resultTo, options, userId, validateIncomingUser, + originatingPendingIntent); + } + } + + @Override + public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, + String callingPackage, Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, SafeActivityOptions options, + int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, + PendingIntentRecord originatingPendingIntent) { + synchronized (mGlobalLock) { + return getActivityStartController().startActivityInPackage(uid, realCallingPid, + realCallingUid, callingPackage, intent, resolvedType, resultTo, resultWho, + requestCode, startFlags, options, userId, inTask, reason, + validateIncomingUser, originatingPendingIntent); + } + } + + @Override public int startActivityAsUser(IApplicationThread caller, String callerPacakge, Intent intent, Bundle options, int userId) { return ActivityTaskManagerService.this.startActivityAsUser( @@ -5684,5 +5746,39 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } }); } + + @Override + public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho, + int requestCode, int resultCode, Intent data) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); + if (r != null && r.getStack() != null) { + r.getStack().sendActivityResultLocked(callingUid, r, resultWho, requestCode, + resultCode, data); + } + } + } + + @Override + public void clearPendingResultForActivity(IBinder activityToken, + WeakReference<PendingIntentRecord> pir) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInStackLocked(activityToken); + if (r != null && r.pendingResults != null) { + r.pendingResults.remove(pir); + } + } + } + + @Override + public IIntentSender getIntentSender(int type, String packageName, + int callingUid, int userId, IBinder token, String resultWho, + int requestCode, Intent[] intents, String[] resolvedTypes, int flags, + Bundle bOptions) { + synchronized (mGlobalLock) { + return getIntentSenderLocked(type, packageName, callingUid, userId, token, + resultWho, requestCode, intents, resolvedTypes, flags, bOptions); + } + } } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 1387f457d2ed..de891b971909 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -741,7 +741,7 @@ public final class BroadcastQueue { // Show a permission review UI only for explicit broadcast from a foreground app if (callerForeground && receiverRecord.intent.getComponent() != null) { - IIntentSender target = mService.getIntentSenderLocked( + IIntentSender target = mService.mPendingIntentController.getIntentSender( ActivityManager.INTENT_SENDER_BROADCAST, receiverRecord.callerPackage, receiverRecord.callingUid, receiverRecord.userId, null, null, 0, new Intent[]{receiverRecord.intent}, diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java new file mode 100644 index 000000000000..a9c00a70650c --- /dev/null +++ b/services/core/java/com/android/server/am/PendingIntentController.java @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; +import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; + +import android.app.Activity; +import android.app.ActivityManagerInternal; +import android.app.AppGlobals; +import android.app.PendingIntent; +import android.content.IIntentSender; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Slog; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.LocalServices; +import com.android.server.wm.ActivityTaskManagerInternal; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper class for {@link ActivityManagerService} responsible for managing pending intents. + * + * <p>This class uses {@link #mLock} to synchronize access to internal state and doesn't make use of + * {@link ActivityManagerService} lock since there can be direct calls into this class from outside + * AM. This helps avoid deadlocks. + */ +public class PendingIntentController { + private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentController" : TAG_AM; + private static final String TAG_MU = TAG + POSTFIX_MU; + + /** Lock for internal state. */ + final Object mLock = new Object(); + final Handler mH; + ActivityManagerInternal mAmInternal; + final UserController mUserController; + final ActivityTaskManagerInternal mAtmInternal; + + /** Set of IntentSenderRecord objects that are currently active. */ + final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords + = new HashMap<>(); + + PendingIntentController(Looper looper, UserController userController) { + mH = new Handler(looper); + mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); + mUserController = userController; + } + + void onActivityManagerInternalAdded() { + synchronized (mLock) { + mAmInternal = LocalServices.getService(ActivityManagerInternal.class); + } + } + + PendingIntentRecord getIntentSender(int type, String packageName, int callingUid, int userId, + IBinder token, String resultWho, int requestCode, Intent[] intents, + String[] resolvedTypes, int flags, Bundle bOptions) { + synchronized (mLock) { + if (DEBUG_MU) Slog.v(TAG_MU, "getIntentSender(): uid=" + callingUid); + + // We're going to be splicing together extras before sending, so we're + // okay poking into any contained extras. + if (intents != null) { + for (int i = 0; i < intents.length; i++) { + intents[i].setDefusable(true); + } + } + Bundle.setDefusable(bOptions, true); + + final boolean noCreate = (flags & PendingIntent.FLAG_NO_CREATE) != 0; + final boolean cancelCurrent = (flags & PendingIntent.FLAG_CANCEL_CURRENT) != 0; + final boolean updateCurrent = (flags & PendingIntent.FLAG_UPDATE_CURRENT) != 0; + flags &= ~(PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_CANCEL_CURRENT + | PendingIntent.FLAG_UPDATE_CURRENT); + + PendingIntentRecord.Key key = new PendingIntentRecord.Key(type, packageName, token, + resultWho, requestCode, intents, resolvedTypes, flags, + SafeActivityOptions.fromBundle(bOptions), userId); + WeakReference<PendingIntentRecord> ref; + ref = mIntentSenderRecords.get(key); + PendingIntentRecord rec = ref != null ? ref.get() : null; + if (rec != null) { + if (!cancelCurrent) { + if (updateCurrent) { + if (rec.key.requestIntent != null) { + rec.key.requestIntent.replaceExtras(intents != null ? + intents[intents.length - 1] : null); + } + if (intents != null) { + intents[intents.length - 1] = rec.key.requestIntent; + rec.key.allIntents = intents; + rec.key.allResolvedTypes = resolvedTypes; + } else { + rec.key.allIntents = null; + rec.key.allResolvedTypes = null; + } + } + return rec; + } + makeIntentSenderCanceled(rec); + mIntentSenderRecords.remove(key); + } + if (noCreate) { + return rec; + } + rec = new PendingIntentRecord(this, key, callingUid); + mIntentSenderRecords.put(key, rec.ref); + return rec; + } + } + + boolean removePendingIntentsForPackage(String packageName, int userId, int appId, + boolean doIt) { + + boolean didSomething = false; + synchronized (mLock) { + + // Remove pending intents. For now we only do this when force stopping users, because + // we have some problems when doing this for packages -- app widgets are not currently + // cleaned up for such packages, so they can be left with bad pending intents. + if (mIntentSenderRecords.size() <= 0) { + return false; + } + + Iterator<WeakReference<PendingIntentRecord>> it + = mIntentSenderRecords.values().iterator(); + while (it.hasNext()) { + WeakReference<PendingIntentRecord> wpir = it.next(); + if (wpir == null) { + it.remove(); + continue; + } + PendingIntentRecord pir = wpir.get(); + if (pir == null) { + it.remove(); + continue; + } + if (packageName == null) { + // Stopping user, remove all objects for the user. + if (pir.key.userId != userId) { + // Not the same user, skip it. + continue; + } + } else { + if (UserHandle.getAppId(pir.uid) != appId) { + // Different app id, skip it. + continue; + } + if (userId != UserHandle.USER_ALL && pir.key.userId != userId) { + // Different user, skip it. + continue; + } + if (!pir.key.packageName.equals(packageName)) { + // Different package, skip it. + continue; + } + } + if (!doIt) { + return true; + } + didSomething = true; + it.remove(); + makeIntentSenderCanceled(pir); + if (pir.key.activity != null) { + final Message m = PooledLambda.obtainMessage( + PendingIntentController::clearPendingResultForActivity, this, + pir.key.activity, pir.ref); + mH.sendMessage(m); + } + } + } + + return didSomething; + } + + public void cancelIntentSender(IIntentSender sender) { + if (!(sender instanceof PendingIntentRecord)) { + return; + } + synchronized (mLock) { + final PendingIntentRecord rec = (PendingIntentRecord) sender; + try { + final int uid = AppGlobals.getPackageManager().getPackageUid(rec.key.packageName, + MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getCallingUserId()); + if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) { + String msg = "Permission Denial: cancelIntentSender() from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " is not allowed to cancel package " + rec.key.packageName; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } catch (RemoteException e) { + throw new SecurityException(e); + } + cancelIntentSender(rec, true); + } + } + + public void cancelIntentSender(PendingIntentRecord rec, boolean cleanActivity) { + synchronized (mLock) { + makeIntentSenderCanceled(rec); + mIntentSenderRecords.remove(rec.key); + if (cleanActivity && rec.key.activity != null) { + final Message m = PooledLambda.obtainMessage( + PendingIntentController::clearPendingResultForActivity, this, + rec.key.activity, rec.ref); + mH.sendMessage(m); + } + } + } + + private void makeIntentSenderCanceled(PendingIntentRecord rec) { + rec.canceled = true; + final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked(); + if (callbacks != null) { + final Message m = PooledLambda.obtainMessage( + PendingIntentController::handlePendingIntentCancelled, this, callbacks); + mH.sendMessage(m); + } + } + + private void handlePendingIntentCancelled(RemoteCallbackList<IResultReceiver> callbacks) { + int N = callbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + try { + callbacks.getBroadcastItem(i).send(Activity.RESULT_CANCELED, null); + } catch (RemoteException e) { + // Process is not longer running...whatever. + } + } + callbacks.finishBroadcast(); + // We have to clean up the RemoteCallbackList here, because otherwise it will + // needlessly hold the enclosed callbacks until the remote process dies. + callbacks.kill(); + } + + private void clearPendingResultForActivity(IBinder activityToken, + WeakReference<PendingIntentRecord> pir) { + mAtmInternal.clearPendingResultForActivity(activityToken, pir); + } + + void dumpPendingIntents(PrintWriter pw, boolean dumpAll, String dumpPackage) { + synchronized (mLock) { + boolean printed = false; + + pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)"); + + if (mIntentSenderRecords.size() > 0) { + // Organize these by package name, so they are easier to read. + final ArrayMap<String, ArrayList<PendingIntentRecord>> byPackage = new ArrayMap<>(); + final ArrayList<WeakReference<PendingIntentRecord>> weakRefs = new ArrayList<>(); + final Iterator<WeakReference<PendingIntentRecord>> it + = mIntentSenderRecords.values().iterator(); + while (it.hasNext()) { + WeakReference<PendingIntentRecord> ref = it.next(); + PendingIntentRecord rec = ref != null ? ref.get() : null; + if (rec == null) { + weakRefs.add(ref); + continue; + } + if (dumpPackage != null && !dumpPackage.equals(rec.key.packageName)) { + continue; + } + ArrayList<PendingIntentRecord> list = byPackage.get(rec.key.packageName); + if (list == null) { + list = new ArrayList<>(); + byPackage.put(rec.key.packageName, list); + } + list.add(rec); + } + for (int i = 0; i < byPackage.size(); i++) { + ArrayList<PendingIntentRecord> intents = byPackage.valueAt(i); + printed = true; + pw.print(" * "); pw.print(byPackage.keyAt(i)); + pw.print(": "); pw.print(intents.size()); pw.println(" items"); + for (int j = 0; j < intents.size(); j++) { + pw.print(" #"); pw.print(j); pw.print(": "); pw.println(intents.get(j)); + if (dumpAll) { + intents.get(j).dump(pw, " "); + } + } + } + if (weakRefs.size() > 0) { + printed = true; + pw.println(" * WEAK REFS:"); + for (int i = 0; i < weakRefs.size(); i++) { + pw.print(" #"); pw.print(i); pw.print(": "); pw.println(weakRefs.get(i)); + } + } + } + + if (!printed) { + pw.println(" (nothing)"); + } + } + } +} diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index ee1166e2a6e8..b9c6fa6020c4 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -38,15 +38,16 @@ import android.util.Slog; import android.util.TimeUtils; import com.android.internal.os.IResultReceiver; +import com.android.internal.util.function.pooled.PooledLambda; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.Objects; -final class PendingIntentRecord extends IIntentSender.Stub { +public final class PendingIntentRecord extends IIntentSender.Stub { private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; - final ActivityManagerService owner; + final PendingIntentController controller; final Key key; final int uid; final WeakReference<PendingIntentRecord> ref; @@ -62,7 +63,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { final static class Key { final int type; final String packageName; - final ActivityRecord activity; + final IBinder activity; final String who; final int requestCode; final Intent requestIntent; @@ -76,7 +77,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { private static final int ODD_PRIME_NUMBER = 37; - Key(int _t, String _p, ActivityRecord _a, String _w, + Key(int _t, String _p, IBinder _a, String _w, int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) { type = _t; packageName = _p; @@ -114,6 +115,7 @@ final class PendingIntentRecord extends IIntentSender.Stub { // + Integer.toHexString(hashCode)); } + @Override public boolean equals(Object otherObj) { if (otherObj == null) { return false; @@ -188,11 +190,11 @@ final class PendingIntentRecord extends IIntentSender.Stub { } } - PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { - owner = _owner; + PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) { + controller = _controller; key = _k; uid = _u; - ref = new WeakReference<PendingIntentRecord>(this); + ref = new WeakReference<>(this); } void setWhitelistDurationLocked(IBinder whitelistToken, long duration) { @@ -247,189 +249,196 @@ final class PendingIntentRecord extends IIntentSender.Stub { } int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, - IIntentReceiver finishedReceiver, - String requiredPermission, IBinder resultTo, String resultWho, int requestCode, - int flagsMask, int flagsValues, Bundle options) { + IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, + String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) { if (intent != null) intent.setDefusable(true); if (options != null) options.setDefusable(true); - synchronized (owner) { - if (!canceled) { - sent = true; - if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { - owner.cancelIntentSenderLocked(this, true); - } + Long duration = null; + Intent finalIntent = null; + Intent[] allIntents = null; + String[] allResolvedTypes = null; + SafeActivityOptions mergedOptions = null; + synchronized (controller.mLock) { + if (canceled) { + return ActivityManager.START_CANCELED; + } - Intent finalIntent = key.requestIntent != null - ? new Intent(key.requestIntent) : new Intent(); + sent = true; + if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) { + controller.cancelIntentSender(this, true); + } - final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; - if (!immutable) { - if (intent != null) { - int changes = finalIntent.fillIn(intent, key.flags); - if ((changes & Intent.FILL_IN_DATA) == 0) { - resolvedType = key.requestResolvedType; - } - } else { + finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent(); + + final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; + if (!immutable) { + if (intent != null) { + int changes = finalIntent.fillIn(intent, key.flags); + if ((changes & Intent.FILL_IN_DATA) == 0) { resolvedType = key.requestResolvedType; } - flagsMask &= ~Intent.IMMUTABLE_FLAGS; - flagsValues &= flagsMask; - finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); } else { resolvedType = key.requestResolvedType; } + flagsMask &= ~Intent.IMMUTABLE_FLAGS; + flagsValues &= flagsMask; + finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); + } else { + resolvedType = key.requestResolvedType; + } - final int callingUid = Binder.getCallingUid(); - final int callingPid = Binder.getCallingPid(); + // Extract options before clearing calling identity + mergedOptions = key.options; + if (mergedOptions == null) { + mergedOptions = SafeActivityOptions.fromBundle(options); + } else { + mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); + } - // Extract options before clearing calling identity - SafeActivityOptions mergedOptions = key.options; - if (mergedOptions == null) { - mergedOptions = SafeActivityOptions.fromBundle(options); - } else { - mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); + if (whitelistDuration != null) { + duration = whitelistDuration.get(whitelistToken); + } + + if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY + && key.allIntents != null && key.allIntents.length > 1) { + // Copy all intents and resolved types while we have the controller lock so we can + // use it later when the lock isn't held. + allIntents = new Intent[key.allIntents.length]; + allResolvedTypes = new String[key.allIntents.length]; + System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length); + if (key.allResolvedTypes != null) { + System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, + key.allResolvedTypes.length); } + allIntents[allIntents.length - 1] = finalIntent; + allResolvedTypes[allResolvedTypes.length - 1] = resolvedType; + } - final long origId = Binder.clearCallingIdentity(); - - if (whitelistDuration != null) { - Long duration = whitelistDuration.get(whitelistToken); - if (duration != null) { - int procState = owner.getUidState(callingUid); - if (!ActivityManager.isProcStateBackground(procState)) { - StringBuilder tag = new StringBuilder(64); - tag.append("pendingintent:"); - UserHandle.formatUid(tag, callingUid); - tag.append(":"); - if (finalIntent.getAction() != null) { - tag.append(finalIntent.getAction()); - } else if (finalIntent.getComponent() != null) { - finalIntent.getComponent().appendShortString(tag); - } else if (finalIntent.getData() != null) { - tag.append(finalIntent.getData().toSafeString()); - } - owner.tempWhitelistForPendingIntentLocked(callingPid, - callingUid, uid, duration, tag.toString()); - } else { - Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" - + procState); - } + } + // We don't hold the controller lock beyond this point as we will be calling into AM and WM. + + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final long origId = Binder.clearCallingIdentity(); + + int res = START_SUCCESS; + try { + if (duration != null) { + int procState = controller.mAmInternal.getUidProcessState(callingUid); + if (!ActivityManager.isProcStateBackground(procState)) { + StringBuilder tag = new StringBuilder(64); + tag.append("pendingintent:"); + UserHandle.formatUid(tag, callingUid); + tag.append(":"); + if (finalIntent.getAction() != null) { + tag.append(finalIntent.getAction()); + } else if (finalIntent.getComponent() != null) { + finalIntent.getComponent().appendShortString(tag); + } else if (finalIntent.getData() != null) { + tag.append(finalIntent.getData().toSafeString()); } + controller.mAmInternal.tempWhitelistForPendingIntent(callingPid, callingUid, + uid, duration, tag.toString()); + } else { + Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" + procState); } + } - boolean sendFinish = finishedReceiver != null; - int userId = key.userId; - if (userId == UserHandle.USER_CURRENT) { - userId = owner.mUserController.getCurrentOrTargetUserId(); - } - int res = START_SUCCESS; - switch (key.type) { - case ActivityManager.INTENT_SENDER_ACTIVITY: - try { - // Note when someone has a pending intent, even from different - // users, then there's no need to ensure the calling user matches - // the target user, so validateIncomingUser is always false below. - - if (key.allIntents != null && key.allIntents.length > 1) { - Intent[] allIntents = new Intent[key.allIntents.length]; - String[] allResolvedTypes = new String[key.allIntents.length]; - System.arraycopy(key.allIntents, 0, allIntents, 0, - key.allIntents.length); - if (key.allResolvedTypes != null) { - System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, - key.allResolvedTypes.length); - } - allIntents[allIntents.length-1] = finalIntent; - allResolvedTypes[allResolvedTypes.length-1] = resolvedType; - - res = owner.mActivityTaskManager.getActivityStartController().startActivitiesInPackage( - uid, key.packageName, allIntents, allResolvedTypes, - resultTo, mergedOptions, userId, - false /* validateIncomingUser */, - this /* originatingPendingIntent */); - } else { - res = owner.mActivityTaskManager.getActivityStartController().startActivityInPackage(uid, - callingPid, callingUid, key.packageName, finalIntent, - resolvedType, resultTo, resultWho, requestCode, 0, - mergedOptions, userId, null, "PendingIntentRecord", - false /* validateIncomingUser */, - this /* originatingPendingIntent */); - } - } catch (RuntimeException e) { - Slog.w(TAG, "Unable to send startActivity intent", e); - } - break; - case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: - final ActivityStack stack = key.activity.getStack(); - if (stack != null) { - stack.sendActivityResultLocked(-1, key.activity, key.who, - key.requestCode, code, finalIntent); - } - break; - case ActivityManager.INTENT_SENDER_BROADCAST: - try { - // If a completion callback has been requested, require - // that the broadcast be delivered synchronously - int sent = owner.broadcastIntentInPackage(key.packageName, uid, - finalIntent, resolvedType, finishedReceiver, code, null, null, - requiredPermission, options, (finishedReceiver != null), - false, userId); - if (sent == ActivityManager.BROADCAST_SUCCESS) { - sendFinish = false; - } - } catch (RuntimeException e) { - Slog.w(TAG, "Unable to send startActivity intent", e); + boolean sendFinish = finishedReceiver != null; + int userId = key.userId; + if (userId == UserHandle.USER_CURRENT) { + userId = controller.mUserController.getCurrentOrTargetUserId(); + } + + switch (key.type) { + case ActivityManager.INTENT_SENDER_ACTIVITY: + try { + // Note when someone has a pending intent, even from different + // users, then there's no need to ensure the calling user matches + // the target user, so validateIncomingUser is always false below. + + if (key.allIntents != null && key.allIntents.length > 1) { + res = controller.mAtmInternal.startActivitiesInPackage( + uid, key.packageName, allIntents, allResolvedTypes, resultTo, + mergedOptions, userId, false /* validateIncomingUser */, + this /* originatingPendingIntent */); + } else { + res = controller.mAtmInternal.startActivityInPackage( + uid, callingPid, callingUid, key.packageName, finalIntent, + resolvedType, resultTo, resultWho, requestCode, 0, + mergedOptions, userId, null, "PendingIntentRecord", + false /* validateIncomingUser */, + this /* originatingPendingIntent */); } - break; - case ActivityManager.INTENT_SENDER_SERVICE: - case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: - try { - owner.startServiceInPackage(uid, finalIntent, resolvedType, - key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, - key.packageName, userId); - } catch (RuntimeException e) { - Slog.w(TAG, "Unable to send startService intent", e); - } catch (TransactionTooLargeException e) { - res = ActivityManager.START_CANCELED; + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to send startActivity intent", e); + } + break; + case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: + controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who, + key.requestCode, code, finalIntent); + break; + case ActivityManager.INTENT_SENDER_BROADCAST: + try { + // If a completion callback has been requested, require + // that the broadcast be delivered synchronously + int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName, + uid, finalIntent, resolvedType, finishedReceiver, code, null, null, + requiredPermission, options, (finishedReceiver != null), + false, userId); + if (sent == ActivityManager.BROADCAST_SUCCESS) { + sendFinish = false; } - break; - } - - if (sendFinish && res != ActivityManager.START_CANCELED) { + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to send startActivity intent", e); + } + break; + case ActivityManager.INTENT_SENDER_SERVICE: + case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: try { - finishedReceiver.performReceive(new Intent(finalIntent), 0, - null, null, false, false, key.userId); - } catch (RemoteException e) { + controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType, + key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, + key.packageName, userId); + } catch (RuntimeException e) { + Slog.w(TAG, "Unable to send startService intent", e); + } catch (TransactionTooLargeException e) { + res = ActivityManager.START_CANCELED; } - } - - Binder.restoreCallingIdentity(origId); + break; + } - return res; + if (sendFinish && res != ActivityManager.START_CANCELED) { + try { + finishedReceiver.performReceive(new Intent(finalIntent), 0, + null, null, false, false, key.userId); + } catch (RemoteException e) { + } } + } finally { + Binder.restoreCallingIdentity(origId); } - return ActivityManager.START_CANCELED; + + return res; } @Override protected void finalize() throws Throwable { try { if (!canceled) { - owner.mHandler.sendMessage(owner.mHandler.obtainMessage( - ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); + controller.mH.sendMessage(PooledLambda.obtainMessage( + PendingIntentRecord::completeFinalize, this)); } } finally { super.finalize(); } } - public void completeFinalize() { - synchronized(owner) { - WeakReference<PendingIntentRecord> current = - owner.mIntentSenderRecords.get(key); + private void completeFinalize() { + synchronized(controller.mLock) { + WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key); if (current == ref) { - owner.mIntentSenderRecords.remove(key); + controller.mIntentSenderRecords.remove(key); } } } diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java index f7de7f475b7b..fa0cb47ade02 100644 --- a/services/core/java/com/android/server/am/SafeActivityOptions.java +++ b/services/core/java/com/android/server/am/SafeActivityOptions.java @@ -44,7 +44,7 @@ import com.android.internal.annotations.VisibleForTesting; * the inner options. Also supports having two set of options: Once from the original caller, and * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}. */ -class SafeActivityOptions { +public class SafeActivityOptions { private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_AM; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 9b42d65483df..ef8cb1c07969 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -129,7 +129,8 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; -class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { +// TODO: Make package private again once move to WM package is complete. +public class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7d2fc15a28c5..bcf9212464db 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -22,6 +22,7 @@ import android.app.AppProtoEnums; import android.app.IActivityManager; import android.app.IApplicationThread; import android.content.ComponentName; +import android.content.IIntentSender; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; @@ -32,8 +33,12 @@ import android.service.voice.IVoiceInteractionSession; import android.util.SparseIntArray; import com.android.internal.app.IVoiceInteractor; +import com.android.server.am.PendingIntentRecord; +import com.android.server.am.SafeActivityOptions; +import com.android.server.am.TaskRecord; import com.android.server.am.WindowProcessController; +import java.lang.ref.WeakReference; import java.util.List; /** @@ -178,6 +183,27 @@ public abstract class ActivityTaskManagerInternal { int userId, Intent[] intents, Bundle bOptions); /** + * Start intents as a package. + * + * @param uid Make a call as if this UID did. + * @param callingPackage Make a call as if this package did. + * @param intents Intents to start. + * @param userId Start the intents on this user. + * @param validateIncomingUser Set true to skip checking {@code userId} with the calling UID. + * @param originatingPendingIntent PendingIntentRecord that originated this activity start or + * null if not originated by PendingIntent + */ + public abstract int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents, + String[] resolvedTypes, IBinder resultTo, SafeActivityOptions options, int userId, + boolean validateIncomingUser, PendingIntentRecord originatingPendingIntent); + + public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid, + String callingPackage, Intent intent, String resolvedType, IBinder resultTo, + String resultWho, int requestCode, int startFlags, SafeActivityOptions options, + int userId, TaskRecord inTask, String reason, boolean validateIncomingUser, + PendingIntentRecord originatingPendingIntent); + + /** * Start activity {@code intent} without calling user-id check. * * - DO NOT call it with the calling UID cleared. @@ -297,4 +323,13 @@ public abstract class ActivityTaskManagerInternal { * @param displayId The ID of the display showing the IME. */ public abstract void onImeWindowSetOnDisplay(int pid, int displayId); + + public abstract void sendActivityResult(int callingUid, IBinder activityToken, + String resultWho, int requestCode, int resultCode, Intent data); + public abstract void clearPendingResultForActivity( + IBinder activityToken, WeakReference<PendingIntentRecord> pir); + public abstract IIntentSender getIntentSender(int type, String packageName, + int callingUid, int userId, IBinder token, String resultWho, + int requestCode, Intent[] intents, String[] resolvedTypes, int flags, + Bundle bOptions); } |