Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 431cd97b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 2f81559d c7933aca
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -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.
     */
+117 −39
Original line number Diff line number Diff line
@@ -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,6 +1126,12 @@ public final class ActiveServices {
                mAm.mHandler.removeMessages(
                        ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
            }

            // 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;
@@ -1089,7 +1160,8 @@ public final class ActiveServices {
                        active.mNumActive++;
                    }
                    r.isForeground = true;
                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__ENTER);
                }
                r.postNotification();
@@ -1099,6 +1171,11 @@ public final class ActiveServices {
                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);
                }
            }
        } 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);
+5 −6
Original line number Diff line number Diff line
@@ -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(
+1 −1
Original line number Diff line number Diff line
@@ -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