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

Commit 354efbc3 authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

Merge changes from topic "bg_app_restrictions"

* changes:
  Expose the bg restriction exemption list as an internal API.
  Add an action button to the notification for bg battery abusive apps
  Exempt certain app behaviors for their background battery usage
  Add tracking on abusive broadcast and service binding requests
  Add exemption cases for app background restrictions
  Monitor long-running foreground services
  Post notification on abusive background current drain
  Allow limited alarms/jobs when background restricted
  Cap the LRU position of broadcast receivers in bg restricted apps
  Add a tracker on background current drains for each uid
  Add background restriction levels definition and its controller
parents 1db9c2ae 8bca883b
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -350,6 +350,21 @@ public class PowerExemptionManager {
     * @hide
     */
    public static final int REASON_MEDIA_SESSION_CALLBACK = 317;
    /**
     * Dialer app.
     * @hide
     */
    public static final int REASON_ROLE_DIALER = 318;
    /**
     * Emergency app.
     * @hide
     */
    public static final int REASON_ROLE_EMERGENCY = 319;
    /**
     * System Module.
     * @hide
     */
    public static final int REASON_SYSTEM_MODULE = 320;

    /** @hide The app requests out-out. */
    public static final int REASON_OPT_OUT_REQUESTED = 1000;
@@ -423,6 +438,9 @@ public class PowerExemptionManager {
            REASON_EVENT_MMS,
            REASON_SHELL,
            REASON_MEDIA_SESSION_CALLBACK,
            REASON_ROLE_DIALER,
            REASON_ROLE_EMERGENCY,
            REASON_SYSTEM_MODULE,
            REASON_OPT_OUT_REQUESTED,
    })
    @Retention(RetentionPolicy.SOURCE)
@@ -726,6 +744,12 @@ public class PowerExemptionManager {
                return "SHELL";
            case REASON_MEDIA_SESSION_CALLBACK:
                return "MEDIA_SESSION_CALLBACK";
            case REASON_ROLE_DIALER:
                return "ROLE_DIALER";
            case REASON_ROLE_EMERGENCY:
                return "ROLE_EMERGENCY";
            case REASON_SYSTEM_MODULE:
                return "SYSTEM_MODULE";
            case REASON_OPT_OUT_REQUESTED:
                return "REASON_OPT_OUT_REQUESTED";
            default:
+25 −3
Original line number Diff line number Diff line
@@ -4,8 +4,8 @@ import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageStatsManager.ForcedReasons;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageStatsManager.SystemForcedReasons;
import android.content.Context;
import android.util.IndentingPrintWriter;

@@ -152,7 +152,7 @@ public interface AppStandbyInternal {
     *                       UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_* reasons.
     */
    void restrictApp(@NonNull String packageName, int userId,
            @SystemForcedReasons int restrictReason);
            @ForcedReasons int restrictReason);

    /**
     * Put the specified app in the
@@ -169,7 +169,29 @@ public interface AppStandbyInternal {
     *                       UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_* reasons.
     */
    void restrictApp(@NonNull String packageName, int userId, int mainReason,
            @SystemForcedReasons int restrictReason);
            @ForcedReasons int restrictReason);

    /**
     * Unrestrict an app if there is no other reason to restrict it.
     *
     * <p>
     * The {@code prevMainReasonRestrict} and {@code prevSubReasonRestrict} are the previous
     * reasons of why it was restricted, but the caller knows that these conditions are not true
     * anymore; therefore if there is no other reasons to restrict it (as there could bemultiple
     * reasons to restrict it), lift the restriction.
     * </p>
     *
     * @param packageName            The package name of the app.
     * @param userId                 The user id that this app runs in.
     * @param prevMainReasonRestrict The main reason that why it was restricted, must be either
     *                               {@link android.app.usage.UsageStatsManager#REASON_MAIN_FORCED_BY_SYSTEM}
     *                               or {@link android.app.usage.UsageStatsManager#REASON_MAIN_FORCED_BY_USER}.
     * @param prevSubReasonRestrict  The subreason that why it was restricted before.
     * @param mainReasonUnrestrict   The main reason that why it could be unrestricted now.
     * @param subReasonUnrestrict    The subreason that why it could be unrestricted now.
     */
    void maybeUnrestrictApp(@NonNull String packageName, int userId, int prevMainReasonRestrict,
            int prevSubReasonRestrict, int mainReasonUnrestrict, int subReasonUnrestrict);

    void addActiveDeviceAdmin(String adminPkg, int userId);

+49 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.AppBackgroundRestrictionListener;
import android.app.AppOpsManager;
import android.app.AppOpsManager.PackageOps;
import android.app.IActivityManager;
@@ -280,6 +281,14 @@ public class AppStateTrackerImpl implements AppStateTracker {
        }
    }

    private final AppBackgroundRestrictionListener mAppBackgroundRestrictionListener =
            new AppBackgroundRestrictionListener() {
        @Override
        public void onAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) {
            mHandler.notifyAutoRestrictedBucketFeatureFlagChanged(autoRestrictedBucket);
        }
    };

    /**
     * Listener for any state changes that affect any app's eligibility to run.
     */
@@ -369,6 +378,18 @@ public class AppStateTrackerImpl implements AppStateTracker {
            updateAllAlarms();
        }

        /**
         * Called when toggling the feature flag of moving to restricted standby bucket
         * automatically on background-restricted.
         */
        private void onAutoRestrictedBucketFeatureFlagChanged(AppStateTrackerImpl sender,
                boolean autoRestrictedBucket) {
            updateAllJobs();
            if (autoRestrictedBucket) {
                unblockAllUnrestrictedAlarms();
            }
        }

        /**
         * Called when the job restrictions for multiple UIDs might have changed, so the job
         * scheduler should re-evaluate all restrictions for all jobs.
@@ -499,6 +520,8 @@ public class AppStateTrackerImpl implements AppStateTracker {
                    mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
            mStandbyTracker = new StandbyTracker();
            mAppStandbyInternal.addListener(mStandbyTracker);
            mActivityManagerInternal.addAppBackgroundRestrictionListener(
                    mAppBackgroundRestrictionListener);

            try {
                mIActivityManager.registerUidObserver(new UidObserver(),
@@ -802,6 +825,7 @@ public class AppStateTrackerImpl implements AppStateTracker {
        private static final int MSG_USER_REMOVED = 8;
        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;
        private static final int MSG_EXEMPTED_BUCKET_CHANGED = 10;
        private static final int MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED = 11;

        private static final int MSG_ON_UID_ACTIVE = 12;
        private static final int MSG_ON_UID_GONE = 13;
@@ -849,6 +873,12 @@ public class AppStateTrackerImpl implements AppStateTracker {
            obtainMessage(MSG_EXEMPTED_BUCKET_CHANGED).sendToTarget();
        }

        public void notifyAutoRestrictedBucketFeatureFlagChanged(boolean autoRestrictedBucket) {
            removeMessages(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED);
            obtainMessage(MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED,
                    autoRestrictedBucket ? 1 : 0, 0).sendToTarget();
        }

        public void doUserRemoved(int userId) {
            obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
        }
@@ -952,6 +982,13 @@ public class AppStateTrackerImpl implements AppStateTracker {
                    handleUserRemoved(msg.arg1);
                    return;

                case MSG_AUTO_RESTRICTED_BUCKET_FEATURE_FLAG_CHANGED:
                    final boolean autoRestrictedBucket = msg.arg1 == 1;
                    for (Listener l : cloneListeners()) {
                        l.onAutoRestrictedBucketFeatureFlagChanged(sender, autoRestrictedBucket);
                    }
                    return;

                case MSG_ON_UID_ACTIVE:
                    handleUidActive(msg.arg1);
                    return;
@@ -1120,7 +1157,12 @@ public class AppStateTrackerImpl implements AppStateTracker {
            if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) {
                return false;
            }
            return (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName));
            // If apps will be put into restricted standby bucket automatically on user-forced
            // app standby, instead of blocking alarms completely, let the restricted standby bucket
            // policy take care of it.
            return (mForcedAppStandbyEnabled
                    && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                    && isRunAnyRestrictedLocked(uid, packageName));
        }
    }

@@ -1161,7 +1203,12 @@ public class AppStateTrackerImpl implements AppStateTracker {
                    || ArrayUtils.contains(mTempExemptAppIds, appId)) {
                return false;
            }
            if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
            // If apps will be put into restricted standby bucket automatically on user-forced
            // app standby, instead of blocking jobs completely, let the restricted standby bucket
            // policy take care of it.
            if (mForcedAppStandbyEnabled
                    && !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                    && isRunAnyRestrictedLocked(uid, packageName)) {
                return true;
            }
            if (hasForegroundExemption) {
+6 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.job.controllers;
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;

import android.app.ActivityManagerInternal;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -59,6 +60,7 @@ public final class BackgroundJobsController extends StateController {
    static final int KNOWN_ACTIVE = 1;
    static final int KNOWN_INACTIVE = 2;

    private final ActivityManagerInternal mActivityManagerInternal;
    private final AppStateTrackerImpl mAppStateTracker;

    private final UpdateJobFunctor mUpdateJobFunctor = new UpdateJobFunctor();
@@ -66,6 +68,8 @@ public final class BackgroundJobsController extends StateController {
    public BackgroundJobsController(JobSchedulerService service) {
        super(service);

        mActivityManagerInternal = (ActivityManagerInternal) Objects.requireNonNull(
                LocalServices.getService(ActivityManagerInternal.class));
        mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull(
                LocalServices.getService(AppStateTracker.class));
        mAppStateTracker.addListener(mForceAppStandbyListener);
@@ -216,7 +220,8 @@ public final class BackgroundJobsController extends StateController {
        }
        boolean didChange =
                jobStatus.setBackgroundNotRestrictedConstraintSatisfied(nowElapsed, canRun,
                        !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName));
                        !mActivityManagerInternal.isBgAutoRestrictedBucketFeatureFlagEnabled()
                        && !mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, packageName));
        didChange |= jobStatus.setUidActive(isActive);
        return didChange;
    }
+19 −10
Original line number Diff line number Diff line
@@ -63,8 +63,8 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.usage.AppStandbyInfo;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager.ForcedReasons;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageStatsManager.SystemForcedReasons;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
@@ -1406,13 +1406,13 @@ public class AppStandbyController

    @Override
    public void restrictApp(@NonNull String packageName, int userId,
            @SystemForcedReasons int restrictReason) {
            @ForcedReasons int restrictReason) {
        restrictApp(packageName, userId, REASON_MAIN_FORCED_BY_SYSTEM, restrictReason);
    }

    @Override
    public void restrictApp(@NonNull String packageName, int userId, int mainReason,
            @SystemForcedReasons int restrictReason) {
            @ForcedReasons int restrictReason) {
        if (mainReason != REASON_MAIN_FORCED_BY_SYSTEM
                && mainReason != REASON_MAIN_FORCED_BY_USER) {
            Slog.e(TAG, "Tried to restrict app " + packageName + " for an unsupported reason");
@@ -1799,27 +1799,36 @@ public class AppStandbyController
     * bucket if it was forced into the bucket by the system because it was buggy.
     */
    @VisibleForTesting
    void maybeUnrestrictBuggyApp(String packageName, int userId) {
    void maybeUnrestrictBuggyApp(@NonNull String packageName, int userId) {
        maybeUnrestrictApp(packageName, userId,
                REASON_MAIN_FORCED_BY_SYSTEM, REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY,
                REASON_MAIN_DEFAULT, REASON_SUB_DEFAULT_APP_UPDATE);
    }

    @Override
    public void maybeUnrestrictApp(@NonNull String packageName, int userId,
            int prevMainReasonRestrict, int prevSubReasonRestrict,
            int mainReasonUnrestrict, int subReasonUnrestrict) {
        synchronized (mAppIdleLock) {
            final long elapsedRealtime = mInjector.elapsedRealtime();
            final AppIdleHistory.AppUsageHistory app =
                    mAppIdleHistory.getAppUsageHistory(packageName, userId, elapsedRealtime);
            if (app.currentBucket != STANDBY_BUCKET_RESTRICTED
                    || (app.bucketingReason & REASON_MAIN_MASK) != REASON_MAIN_FORCED_BY_SYSTEM) {
                    || (app.bucketingReason & REASON_MAIN_MASK) != prevMainReasonRestrict) {
                return;
            }

            final int newBucket;
            final int newReason;
            if ((app.bucketingReason & REASON_SUB_MASK) == REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY) {
                // If bugginess was the only reason the app should be restricted, then lift it out.
            if ((app.bucketingReason & REASON_SUB_MASK) == prevSubReasonRestrict) {
                // If it was the only reason the app should be restricted, then lift it out.
                newBucket = STANDBY_BUCKET_RARE;
                newReason = REASON_MAIN_DEFAULT | REASON_SUB_DEFAULT_APP_UPDATE;
                newReason = mainReasonUnrestrict | subReasonUnrestrict;
            } else {
                // There's another reason the app was restricted. Remove the buggy bit and call
                // There's another reason the app was restricted. Remove the subreason bit and call
                // it a day.
                newBucket = STANDBY_BUCKET_RESTRICTED;
                newReason = app.bucketingReason & ~REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
                newReason = app.bucketingReason & ~prevSubReasonRestrict;
            }
            mAppIdleHistory.setAppStandbyBucket(
                    packageName, userId, elapsedRealtime, newBucket, newReason);
Loading