Merge "Suppress all background-state services in user-forced app standby" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
431cd97bd8
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user