Merge "Optimize bg check flow."

This commit is contained in:
Dianne Hackborn
2017-01-24 00:05:34 +00:00
committed by Android (Google) Code Review
10 changed files with 96 additions and 117 deletions

View File

@@ -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;

View File

@@ -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();

View File

@@ -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);

View File

@@ -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" />

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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 "

View File

@@ -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");

View File

@@ -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();