Merge "Optimize bg check flow."
This commit is contained in:
committed by
Android (Google) Code Review
commit
5f1a2a34d9
@@ -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;
|
||||
|
||||
|
||||
@@ -1341,8 +1341,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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -7284,18 +7285,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8020,65 +8026,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;
|
||||
}
|
||||
}
|
||||
|
||||
// !!! 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");
|
||||
}
|
||||
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);
|
||||
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, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
|
||||
Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
|
||||
}
|
||||
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_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;
|
||||
}
|
||||
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) {
|
||||
@@ -8108,11 +8091,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="
|
||||
@@ -8130,27 +8113,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user