diff options
10 files changed, 95 insertions, 116 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 1d4b038f2d82..c1a888d28428 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -520,17 +520,17 @@ public class ActivityManager { /** @hide Flag for registerUidObserver: report uid has become active. */ public static final int UID_OBSERVER_ACTIVE = 1<<3; - /** @hide Mode for {@link IActivityManager#getAppStartMode}: normal free-to-run operation. */ + /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. */ public static final int APP_START_MODE_NORMAL = 0; - /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later. */ + /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later. */ public static final int APP_START_MODE_DELAYED = 1; - /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later, with + /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later, with * rigid errors (throwing exception). */ public static final int APP_START_MODE_DELAYED_RIGID = 2; - /** @hide Mode for {@link IActivityManager#getAppStartMode}: disable/cancel pending + /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: disable/cancel pending * launches; this is the mode for ephemeral apps. */ public static final int APP_START_MODE_DISABLED = 3; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5e7d46fe05aa..1b31cc5ea41f 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1342,8 +1342,8 @@ class ContextImpl extends Context { } try { final Intent intent = ActivityManager.getService().registerReceiver( - mMainThread.getApplicationThread(), mBasePackageName, - rd, filter, broadcastPermission, userId); + mMainThread.getApplicationThread(), mBasePackageName, rd, filter, + broadcastPermission, userId); if (intent != null) { intent.setExtrasClassLoader(getClassLoader()); intent.prepareToEnterProcess(); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 135c2a4eef91..ec7c1709b3c5 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -475,7 +475,7 @@ interface IActivityManager { void suppressResizeConfigChanges(boolean suppress); void moveTasksToFullscreenStack(int fromStackId, boolean onTop); boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds); - int getAppStartMode(int uid, in String packageName); + boolean isAppStartModeDisabled(int uid, in String packageName); boolean unlockUser(int userid, in byte[] token, in byte[] secret, in IProgressListener listener); boolean isInMultiWindowMode(in IBinder token); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index fede34d2ced3..f72d091607ac 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -131,6 +131,9 @@ <!-- Assist --> <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" /> + <!-- Doze mode temp whitelisting for notification dispatching. --> + <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" /> + <!-- Listen for keyboard attachment / detachment --> <uses-permission android:name="android.permission.TABLET_MODE" /> diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 581aa05d7d32..0e07ec0e27f4 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -504,8 +504,8 @@ class AlarmManagerService extends SystemService { for (int i = alarms.size()-1; i >= 0; i--) { Alarm alarm = alarms.get(i); try { - if (alarm.uid == uid && ActivityManager.getService().getAppStartMode( - uid, alarm.packageName) == ActivityManager.APP_START_MODE_DISABLED) { + if (alarm.uid == uid && ActivityManager.getService().isAppStartModeDisabled( + uid, alarm.packageName)) { alarms.remove(i); didRemove = true; if (alarm.alarmClock != null) { @@ -1089,8 +1089,7 @@ class AlarmManagerService extends SystemService { operation, directReceiver, listenerTag, workSource, flags, alarmClock, callingUid, callingPackage); try { - if (ActivityManager.getService().getAppStartMode(callingUid, callingPackage) - == ActivityManager.APP_START_MODE_DISABLED) { + if (ActivityManager.getService().isAppStartModeDisabled(callingUid, callingPackage)) { Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a + " -- package not allowed to start"); return; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4b89b404f9b6..4ab09c4d8ae3 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -349,8 +349,8 @@ public final class ActiveServices { try { // Before going further -- if this app is not allowed to start services in the // background, then at this point we aren't going to let it period. - final int allowed = mAm.checkAllowBackgroundLocked( - r.appInfo.uid, r.packageName, callingPid, false); + final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName, + r.appInfo.targetSdkVersion, callingPid, false, false); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { Slog.w(TAG, "Background start not allowed: service " + service + " to " + r.name.flattenToShortString() @@ -607,8 +607,9 @@ public final class ActiveServices { for (int i=services.mServicesByName.size()-1; i>=0; i--) { ServiceRecord service = services.mServicesByName.valueAt(i); if (service.appInfo.uid == uid && service.startRequested) { - if (mAm.checkAllowBackgroundLocked(service.appInfo.uid, service.packageName, - -1, false) != ActivityManager.APP_START_MODE_NORMAL) { + if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName, + service.appInfo.targetSdkVersion, -1, false, false) + != ActivityManager.APP_START_MODE_NORMAL) { if (stopping == null) { stopping = new ArrayList<>(); stopping.add(service); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 75ae43b02329..2bec90d7313b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; import static android.Manifest.permission.READ_FRAME_BUFFER; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; +import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; @@ -7283,18 +7284,23 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.d(TAG, "tempWhitelistAppForPowerSave(" + callerPid + ", " + callerUid + ", " + targetUid + ", " + duration + ")"); } - synchronized (mPidsSelfLocked) { - final ProcessRecord pr = mPidsSelfLocked.get(callerPid); - if (pr == null) { - Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " + callerPid); - return; - } - if (!pr.whitelistManager) { - if (DEBUG_WHITELISTS) { - Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid + ": pid " - + callerPid + " is not allowed"); + + if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid) + != PackageManager.PERMISSION_GRANTED) { + synchronized (mPidsSelfLocked) { + final ProcessRecord pr = mPidsSelfLocked.get(callerPid); + if (pr == null) { + Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " + + callerPid); + return; + } + if (!pr.whitelistManager) { + if (DEBUG_WHITELISTS) { + Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid + + ": pid " + callerPid + " is not allowed"); + } + return; } - return; } } @@ -8019,65 +8025,42 @@ public class ActivityManagerService extends IActivityManager.Stub return readMet && writeMet; } - public int getAppStartMode(int uid, String packageName) { + public boolean isAppStartModeDisabled(int uid, String packageName) { synchronized (this) { - return checkAllowBackgroundLocked(uid, packageName, -1, false); + return getAppStartModeLocked(uid, packageName, 0, -1, false, true) + == ActivityManager.APP_START_MODE_DISABLED; } } // Unified app-op and target sdk check - int appRestrictedInBackgroundLocked(int uid, String packageName) { - if (packageName == null) { - packageName = mPackageManagerInt.getNameForUid(uid); - if (packageName == null) { - Slog.w(TAG, "No package known for uid " + uid); - return ActivityManager.APP_START_MODE_NORMAL; + int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) { + // Apps that target O+ are always subject to background check + if (mEnforceBackgroundCheck && packageTargetSdk >= Build.VERSION_CODES.O) { + if (DEBUG_BACKGROUND_CHECK) { + Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted"); } + return ActivityManager.APP_START_MODE_DELAYED_RIGID; } - - // !!! TODO: cache the package/versionCode lookups to fast path this - ApplicationInfo app = getPackageManagerInternalLocked().getApplicationInfo(packageName, - UserHandle.getUserId(uid)); - if (app != null) { - // Apps that target O+ are always subject to background check - if (mEnforceBackgroundCheck && app.targetSdkVersion >= Build.VERSION_CODES.O) { - if (DEBUG_BACKGROUND_CHECK) { - Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted"); - } + // ...and legacy apps get an AppOp check + int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, + uid, packageName); + if (DEBUG_BACKGROUND_CHECK) { + Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop); + } + switch (appop) { + case AppOpsManager.MODE_ALLOWED: + return ActivityManager.APP_START_MODE_NORMAL; + case AppOpsManager.MODE_IGNORED: + return ActivityManager.APP_START_MODE_DELAYED; + default: return ActivityManager.APP_START_MODE_DELAYED_RIGID; - } - // ...and legacy apps get an AppOp check - int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, - uid, packageName); - if (DEBUG_BACKGROUND_CHECK) { - Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop); - } - switch (appop) { - case AppOpsManager.MODE_ALLOWED: - return ActivityManager.APP_START_MODE_NORMAL; - case AppOpsManager.MODE_IGNORED: - return ActivityManager.APP_START_MODE_DELAYED; - default: - return ActivityManager.APP_START_MODE_DELAYED_RIGID; - } - } else { - Slog.w(TAG, "Unknown app " + packageName + " / " + uid); } - return ActivityManager.APP_START_MODE_NORMAL; } // Service launch is available to apps with run-in-background exemptions but // some other background operations are not. If we're doing a check // of service-launch policy, allow those callers to proceed unrestricted. - int appServicesRestrictedInBackgroundLocked(int uid, String packageName) { - if (packageName == null) { - packageName = mPackageManagerInt.getNameForUid(uid); - if (packageName == null) { - Slog.w(TAG, "No package known for uid " + uid); - return ActivityManager.APP_START_MODE_NORMAL; - } - } - + int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) { // Persistent app? NB: expects that persistent uids are always active. final UidRecord uidRec = mActiveUids.get(uid); if (uidRec != null && uidRec.persistent) { @@ -8107,11 +8090,11 @@ public class ActivityManagerService extends IActivityManager.Stub } // None of the service-policy criteria apply, so we apply the common criteria - return appRestrictedInBackgroundLocked(uid, packageName); + return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk); } - int checkAllowBackgroundLocked(int uid, String packageName, int callingPid, - boolean alwaysRestrict) { + int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk, + int callingPid, boolean alwaysRestrict, boolean disabledOnly) { UidRecord uidRec = mActiveUids.get(uid); if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg=" + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle=" @@ -8129,27 +8112,37 @@ public class ActivityManagerService extends IActivityManager.Stub // We are hard-core about ephemeral apps not running in the background. return ActivityManager.APP_START_MODE_DISABLED; } else { - /** Don't want to allow this exception in the final background check impl? - if (callingPid >= 0) { - ProcessRecord proc; - synchronized (mPidsSelfLocked) { - proc = mPidsSelfLocked.get(callingPid); - } - if (proc != null && proc.curProcState - < ActivityManager.PROCESS_STATE_RECEIVER) { - // Whoever is instigating this is in the foreground, so we will allow it - // to go through. - return ActivityManager.APP_START_MODE_NORMAL; - } + if (disabledOnly) { + // The caller is only interested in whether app starts are completely + // disabled for the given package (that is, it is an instant app). So + // we don't need to go further, which is all just seeing if we should + // apply a "delayed" mode for a regular app. + return ActivityManager.APP_START_MODE_NORMAL; } - */ - final int startMode = (alwaysRestrict) - ? appRestrictedInBackgroundLocked(uid, packageName) - : appServicesRestrictedInBackgroundLocked(uid, packageName); + ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk) + : appServicesRestrictedInBackgroundLocked(uid, packageName, + packageTargetSdk); if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg=" + packageName + " startMode=" + startMode + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid)); + if (startMode == ActivityManager.APP_START_MODE_DELAYED) { + // This is an old app that has been forced into a "compatible as possible" + // mode of background check. To increase compatibility, we will allow other + // foreground apps to cause its services to start. + if (callingPid >= 0) { + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(callingPid); + } + if (proc != null && proc.curProcState + < ActivityManager.PROCESS_STATE_RECEIVER) { + // Whoever is instigating this is in the foreground, so we will allow it + // to go through. + return ActivityManager.APP_START_MODE_NORMAL; + } + } + } return startMode; } } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 61e555bd8b21..ee2467a925c1 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -592,22 +592,6 @@ public final class BroadcastQueue { + " (uid " + r.callingUid + ")"); skip = true; } - if (!skip) { - final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid, - filter.packageName, -1, false); - if (false && allowed == ActivityManager.APP_START_MODE_DISABLED) { - // XXX should we really not allow this? It means that while we are - // keeping an ephemeral app cached, its registered receivers will stop - // receiving broadcasts after it goes idle... so if it comes back to - // the foreground, it won't know what the current state of those broadcasts is. - Slog.w(TAG, "Background execution not allowed: receiving " - + r.intent - + " to " + filter.receiverList.app - + " (pid=" + filter.receiverList.pid - + ", uid=" + filter.receiverList.uid + ")"); - skip = true; - } - } if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, filter.receiverList.uid)) { @@ -1156,13 +1140,14 @@ public final class BroadcastQueue { info.activityInfo.applicationInfo.uid, false); if (!skip) { - final int allowed = mService.checkAllowBackgroundLocked( - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1, true); + final int allowed = mService.getAppStartModeLocked( + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, + info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { // We won't allow this receiver to be launched if the app has been // completely disabled from launches, or it was not explicitly sent // to it and the app is in a state that should not receive it - // (depending on how checkAllowBackgroundLocked has determined that). + // (depending on how getAppStartModeLocked has determined that). if (allowed == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Background execution disabled: receiving " + r.intent + " to " diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 11a3f1189129..5b539ff1976d 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -1019,8 +1019,7 @@ public class SyncManager { final int owningUid = syncAdapterInfo.uid; final String owningPackage = syncAdapterInfo.componentName.getPackageName(); try { - if (ActivityManager.getService().getAppStartMode(owningUid, - owningPackage) == ActivityManager.APP_START_MODE_DISABLED) { + if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) { Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":" + syncAdapterInfo.componentName + " -- package not allowed to start"); diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index f42c5be0ebf9..a7480133972a 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -566,8 +566,8 @@ public final class JobSchedulerService extends com.android.server.SystemService String tag) { JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag); try { - if (ActivityManager.getService().getAppStartMode(uId, - job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) { + if (ActivityManager.getService().isAppStartModeDisabled(uId, + job.getService().getPackageName())) { Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString() + " -- package not allowed to start"); return JobScheduler.RESULT_FAILURE; @@ -1201,9 +1201,8 @@ public final class JobSchedulerService extends com.android.server.SystemService public void process(JobStatus job) { if (isReadyToBeExecutedLocked(job)) { try { - if (ActivityManager.getService().getAppStartMode(job.getUid(), - job.getJob().getService().getPackageName()) - == ActivityManager.APP_START_MODE_DISABLED) { + if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(), + job.getJob().getService().getPackageName())) { Slog.w(TAG, "Aborting job " + job.getUid() + ":" + job.getJob().toString() + " -- package not allowed to start"); mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget(); |