Merge "Suppress all background-state services in user-forced app standby" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-03-21 19:45:59 +00:00
committed by Android (Google) Code Review
4 changed files with 148 additions and 48 deletions

View File

@@ -261,6 +261,12 @@ public class AppStateTracker {
// we need to deliver the allow-while-idle alarms for this uid, package
unblockAllUnrestrictedAlarms();
}
if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
Slog.v(TAG, "Package " + packageName + "/" + uid
+ " toggled into fg service restriction");
stopForegroundServicesForUidPackage(uid, packageName);
}
}
/**
@@ -353,6 +359,13 @@ public class AppStateTracker {
public void updateJobsForUidPackage(int uid, String packageName, boolean isNowActive) {
}
/**
* Called when an app goes into forced app standby and its foreground
* services need to be removed from that state.
*/
public void stopForegroundServicesForUidPackage(int uid, String packageName) {
}
/**
* Called when the job restrictions for multiple UIDs might have changed, so the alarm
* manager should re-evaluate all restrictions for all blocked jobs.
@@ -1056,6 +1069,16 @@ public class AppStateTracker {
hasForegroundExemption);
}
/**
* @return whether foreground services should be suppressed in the background
* due to forced app standby for the given app
*/
public boolean areForegroundServicesRestricted(int uid, @NonNull String packageName) {
synchronized (mLock) {
return isRunAnyRestrictedLocked(uid, packageName);
}
}
/**
* @return whether force-app-standby is effective for a UID package-name.
*/

View File

@@ -56,6 +56,8 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.NeededUriGrants;
import com.android.server.am.proto.ActiveServicesProto;
@@ -164,6 +166,44 @@ public final class ActiveServices {
}
};
/**
* Watch for apps being put into forced app standby, so we can step their fg
* services down.
*/
class ForcedStandbyListener extends AppStateTracker.Listener {
@Override
public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
synchronized (mAm) {
final ServiceMap smap = getServiceMapLocked(UserHandle.getUserId(uid));
final int N = smap.mServicesByName.size();
final ArrayList<ServiceRecord> toStop = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
final ServiceRecord r = smap.mServicesByName.valueAt(i);
if (uid == r.serviceInfo.applicationInfo.uid
|| packageName.equals(r.serviceInfo.packageName)) {
if (r.isForeground) {
toStop.add(r);
}
}
}
// Now stop them all
final int numToStop = toStop.size();
if (numToStop > 0 && DEBUG_FOREGROUND_SERVICE) {
Slog.i(TAG, "Package " + packageName + "/" + uid
+ " entering FAS with foreground services");
}
for (int i = 0; i < numToStop; i++) {
final ServiceRecord r = toStop.get(i);
if (DEBUG_FOREGROUND_SERVICE) {
Slog.i(TAG, " Stopping fg for service " + r);
}
setServiceForegroundInnerLocked(r, 0, null, 0);
}
}
}
}
/**
* Information about an app that is currently running one or more foreground services.
* (This maps directly to the running apps we show in the notification.)
@@ -302,6 +342,11 @@ public final class ActiveServices {
? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 8;
}
void systemServicesReady() {
AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
ast.addListener(new ForcedStandbyListener());
}
ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) {
// TODO: Deal with global services
if (DEBUG_MU)
@@ -327,6 +372,12 @@ public final class ActiveServices {
return getServiceMapLocked(callingUser).mServicesByName;
}
private boolean appRestrictedAnyInBackground(final int uid, final String packageName) {
final int mode = mAm.mAppOpsService.checkOperation(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
return (mode != AppOpsManager.MODE_ALLOWED);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
@@ -365,13 +416,24 @@ public final class ActiveServices {
return null;
}
// If the app has strict background restrictions, we treat any service
// start analogously to the legacy-app forced-restrictions case.
boolean forcedStandby = false;
if (appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "Forcing bg-only service start only for "
+ r.name.flattenToShortString());
}
forcedStandby = true;
}
// If this isn't a direct-to-foreground start, check our ability to kick off an
// arbitrary service
if (!r.startRequested && !fgRequired) {
if (forcedStandby || (!r.startRequested && !fgRequired)) {
// 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.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false);
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
@@ -625,7 +687,7 @@ public final class ActiveServices {
ServiceRecord service = services.mServicesByName.valueAt(i);
if (service.appInfo.uid == uid && service.startRequested) {
if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName,
service.appInfo.targetSdkVersion, -1, false, false)
service.appInfo.targetSdkVersion, -1, false, false, false)
!= ActivityManager.APP_START_MODE_NORMAL) {
if (stopping == null) {
stopping = new ArrayList<>();
@@ -1019,7 +1081,10 @@ public final class ActiveServices {
}
}
private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
/**
* @param id Notification ID. Zero === exit foreground state for the given service.
*/
private void setServiceForegroundInnerLocked(final ServiceRecord r, int id,
Notification notification, int flags) {
if (id != 0) {
if (notification == null) {
@@ -1061,44 +1126,56 @@ public final class ActiveServices {
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
}
if (r.foregroundId != id) {
cancelForegroundNotificationLocked(r);
r.foregroundId = id;
}
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
r.foregroundNoti = notification;
if (!r.isForeground) {
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
if (active == null) {
active = new ActiveForegroundApp();
active.mPackageName = r.packageName;
active.mUid = r.appInfo.uid;
active.mShownWhileScreenOn = mScreenOn;
if (r.app != null) {
active.mAppOnTop = active.mShownWhileTop =
r.app.uidRecord.curProcState
<= ActivityManager.PROCESS_STATE_TOP;
}
active.mStartTime = active.mStartVisibleTime
= SystemClock.elapsedRealtime();
smap.mActiveForegroundApps.put(r.packageName, active);
requestUpdateActiveForegroundAppsLocked(smap, 0);
}
active.mNumActive++;
// Apps under strict background restrictions simply don't get to have foreground
// services, so now that we've enforced the startForegroundService() contract
// we only do the machinery of making the service foreground when the app
// is not restricted.
if (!appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
if (r.foregroundId != id) {
cancelForegroundNotificationLocked(r);
r.foregroundId = id;
}
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
r.foregroundNoti = notification;
if (!r.isForeground) {
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
if (active == null) {
active = new ActiveForegroundApp();
active.mPackageName = r.packageName;
active.mUid = r.appInfo.uid;
active.mShownWhileScreenOn = mScreenOn;
if (r.app != null) {
active.mAppOnTop = active.mShownWhileTop =
r.app.uidRecord.curProcState
<= ActivityManager.PROCESS_STATE_TOP;
}
active.mStartTime = active.mStartVisibleTime
= SystemClock.elapsedRealtime();
smap.mActiveForegroundApps.put(r.packageName, active);
requestUpdateActiveForegroundAppsLocked(smap, 0);
}
active.mNumActive++;
}
r.isForeground = true;
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
}
r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
}
getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
} else {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
}
r.isForeground = true;
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
}
r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
}
getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
} else {
if (r.isForeground) {
final ServiceMap smap = getServiceMapLocked(r.userId);
@@ -1106,7 +1183,8 @@ public final class ActiveServices {
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED, r.appInfo.uid, r.shortName,
StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
r.appInfo.uid, r.shortName,
StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__EXIT);
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);

View File

@@ -123,7 +123,6 @@ import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICAT
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -205,7 +204,6 @@ import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -390,8 +388,8 @@ import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.View;
import android.view.WindowManager;
import android.view.autofill.AutofillManagerInternal;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -2853,6 +2851,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
}
}
@@ -9118,7 +9117,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public boolean isAppStartModeDisabled(int uid, String packageName) {
synchronized (this) {
return getAppStartModeLocked(uid, packageName, 0, -1, false, true)
return getAppStartModeLocked(uid, packageName, 0, -1, false, true, false)
== ActivityManager.APP_START_MODE_DISABLED;
}
}
@@ -9194,12 +9193,12 @@ public class ActivityManagerService extends IActivityManager.Stub
}
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
UidRecord uidRec = mActiveUids.get(uid);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+ (uidRec != null ? uidRec.idle : false));
if (uidRec == null || alwaysRestrict || uidRec.idle) {
if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
boolean ephemeral;
if (uidRec == null) {
ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(

View File

@@ -1258,7 +1258,7 @@ public final class BroadcastQueue {
if (!skip) {
final int allowed = mService.getAppStartModeLocked(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false);
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, 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