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

Commit 4a503b1e authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #22989030: Separate battery whitelists

We now have a new whitelist you can put apps in, which
opts them out of the old battery saver mode and new app idle,
but doesn't keep them from going in to doze.  This is for a few
special cases that we had previously whitelisted for battery saver,
and inherited to the new modes...  ultimately we should figure out
how to get these apps out of the whitelist completely, but this
will help for now.

Apps in this new whitelist are not shown in the UI, because they
are still significantly restricted by not being able to operate
normally in doze.  This also means they are still visible in the
list of all apps for the user to be able to put them on/off the
complete whitelist if that is what they really want.

In the course of doing this, I needed to clean up code in the
network policy manager to better separate management of the
two firewall rules that now have different whitelists applied
to them.  This also hopefully just generally simplifies and cleans
up that code.  Hopefully!

Change-Id: I92e15f2f85899571dd8b049b5e3eb1354f55f353
parent 1d7c3254
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -76,6 +76,13 @@ public abstract class UsageStatsManagerInternal {
     */
    public abstract boolean isAppIdle(String packageName, int userId);

    /**
     * Returns all of the uids for a given user where all packages associating with that uid
     * are in the app idle state -- there are no associated apps that are not idle.  This means
     * all of the returned uids can be safely considered app idle.
     */
    public abstract int[] getIdleUidsForUser(int userId);

    /**
     * @return True if currently app idle parole mode is on.  This means all idle apps are allow to
     * run for a short period of time.
+4 −0
Original line number Diff line number Diff line
@@ -22,10 +22,14 @@ import android.os.UserHandle;
interface IDeviceIdleController {
    void addPowerSaveWhitelistApp(String name);
    void removePowerSaveWhitelistApp(String name);
    String[] getSystemPowerWhitelistExceptIdle();
    String[] getSystemPowerWhitelist();
    String[] getFullPowerWhitelistExceptIdle();
    String[] getFullPowerWhitelist();
    int[] getAppIdWhitelistExceptIdle();
    int[] getAppIdWhitelist();
    int[] getAppIdTempWhitelist();
    boolean isPowerSaveWhitelistExceptIdleApp(String name);
    boolean isPowerSaveWhitelistApp(String name);
    void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
    long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
+8 −0
Original line number Diff line number Diff line
@@ -183,6 +183,14 @@ public class SparseIntArray implements Cloneable {
        return mValues[index];
    }

    /**
     * Directly set the value at a particular index.
     * @hide
     */
    public void setValueAt(int index, int value) {
        mValues[index] = value;
    }

    /**
     * Returns the index for which {@link #keyAt} would return the
     * specified key, or a negative number if the specified
+1 −1
Original line number Diff line number Diff line
@@ -141,6 +141,6 @@

    <!-- These are the standard packages that are white-listed to always have internet
         access while in power save mode, even if they aren't in the foreground. -->
    <allow-in-power-save package="com.android.providers.downloads" />
    <allow-in-power-save-except-idle package="com.android.providers.downloads" />

</permissions>
+202 −17
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ public class DeviceIdleController extends SystemService
    private Display mCurDisplay;
    private AnyMotionDetector mAnyMotionDetector;
    private boolean mEnabled;
    private boolean mForceIdle;
    private boolean mScreenOn;
    private boolean mCharging;
    private boolean mSigMotionActive;
@@ -151,7 +152,14 @@ public class DeviceIdleController extends SystemService
    public final AtomicFile mConfigFile;

    /**
     * Package names the system has white-listed to opt out of power save restrictions.
     * Package names the system has white-listed to opt out of power save restrictions,
     * except for device idle mode.
     */
    private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>();

    /**
     * Package names the system has white-listed to opt out of power save restrictions for
     * all modes.
     */
    private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>();

@@ -160,11 +168,30 @@ public class DeviceIdleController extends SystemService
     */
    private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();

    /**
     * App IDs of built-in system apps that have been white-listed except for idle modes.
     */
    private final SparseBooleanArray mPowerSaveWhitelistSystemAppIdsExceptIdle
            = new SparseBooleanArray();

    /**
     * App IDs of built-in system apps that have been white-listed.
     */
    private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray();

    /**
     * App IDs that have been white-listed to opt out of power save restrictions, except
     * for device idle modes.
     */
    private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray();

    /**
     * Current app IDs that are in the complete power save white list, but shouldn't be
     * excluded from idle modes.  This array can be shared with others because it will not be
     * modified once set.
     */
    private int[] mPowerSaveWhitelistExceptIdleAppIdArray = new int[0];

    /**
     * App IDs that have been white-listed to opt out of power save restrictions.
     */
@@ -583,14 +610,26 @@ public class DeviceIdleController extends SystemService
            removePowerSaveWhitelistAppInternal(name);
        }

        @Override public String[] getSystemPowerWhitelistExceptIdle() {
            return getSystemPowerWhitelistExceptIdleInternal();
        }

        @Override public String[] getSystemPowerWhitelist() {
            return getSystemPowerWhitelistInternal();
        }

        @Override public String[] getFullPowerWhitelistExceptIdle() {
            return getFullPowerWhitelistExceptIdleInternal();
        }

        @Override public String[] getFullPowerWhitelist() {
            return getFullPowerWhitelistInternal();
        }

        @Override public int[] getAppIdWhitelistExceptIdle() {
            return getAppIdWhitelistExceptIdleInternal();
        }

        @Override public int[] getAppIdWhitelist() {
            return getAppIdWhitelistInternal();
        }
@@ -599,6 +638,10 @@ public class DeviceIdleController extends SystemService
            return getAppIdTempWhitelistInternal();
        }

        @Override public boolean isPowerSaveWhitelistExceptIdleApp(String name) {
            return isPowerSaveWhitelistExceptIdleAppInternal(name);
        }

        @Override public boolean isPowerSaveWhitelistApp(String name) {
            return isPowerSaveWhitelistAppInternal(name);
        }
@@ -679,6 +722,19 @@ public class DeviceIdleController extends SystemService
            mEnabled = getContext().getResources().getBoolean(
                    com.android.internal.R.bool.config_enableAutoPowerModes);
            SystemConfig sysConfig = SystemConfig.getInstance();
            ArraySet<String> allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle();
            for (int i=0; i<allowPowerExceptIdle.size(); i++) {
                String pkg = allowPowerExceptIdle.valueAt(i);
                try {
                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
                        int appid = UserHandle.getAppId(ai.uid);
                        mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
                        mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
                    }
                } catch (PackageManager.NameNotFoundException e) {
                }
            }
            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
            for (int i=0; i<allowPower.size(); i++) {
                String pkg = allowPower.valueAt(i);
@@ -686,6 +742,10 @@ public class DeviceIdleController extends SystemService
                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
                        int appid = UserHandle.getAppId(ai.uid);
                        // These apps are on both the whitelist-except-idle as well
                        // as the full whitelist, so they apply in all cases.
                        mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid);
                        mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true);
                        mPowerSaveWhitelistApps.put(ai.packageName, appid);
                        mPowerSaveWhitelistSystemAppIds.put(appid, true);
                    }
@@ -783,17 +843,45 @@ public class DeviceIdleController extends SystemService
        return false;
    }

    public String[] getSystemPowerWhitelistExceptIdleInternal() {
        synchronized (this) {
            int size = mPowerSaveWhitelistAppsExceptIdle.size();
            String[] apps = new String[size];
            for (int i = 0; i < size; i++) {
                apps[i] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
            }
            return apps;
        }
    }

    public String[] getSystemPowerWhitelistInternal() {
        synchronized (this) {
            int size = mPowerSaveWhitelistApps.size();
            String[] apps = new String[size];
            for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
            for (int i = 0; i < size; i++) {
                apps[i] = mPowerSaveWhitelistApps.keyAt(i);
            }
            return apps;
        }
    }

    public String[] getFullPowerWhitelistExceptIdleInternal() {
        synchronized (this) {
            int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
            String[] apps = new String[size];
            int cur = 0;
            for (int i = 0; i < mPowerSaveWhitelistAppsExceptIdle.size(); i++) {
                apps[cur] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
                cur++;
            }
            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
                apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
                cur++;
            }
            return apps;
        }
    }

    public String[] getFullPowerWhitelistInternal() {
        synchronized (this) {
            int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
@@ -811,6 +899,13 @@ public class DeviceIdleController extends SystemService
        }
    }

    public boolean isPowerSaveWhitelistExceptIdleAppInternal(String packageName) {
        synchronized (this) {
            return mPowerSaveWhitelistAppsExceptIdle.containsKey(packageName)
                    || mPowerSaveWhitelistUserApps.containsKey(packageName);
        }
    }

    public boolean isPowerSaveWhitelistAppInternal(String packageName) {
        synchronized (this) {
            return mPowerSaveWhitelistApps.containsKey(packageName)
@@ -818,6 +913,12 @@ public class DeviceIdleController extends SystemService
        }
    }

    public int[] getAppIdWhitelistExceptIdleInternal() {
        synchronized (this) {
            return mPowerSaveWhitelistExceptIdleAppIdArray;
        }
    }

    public int[] getAppIdWhitelistInternal() {
        synchronized (this) {
            return mPowerSaveWhitelistAllAppIdArray;
@@ -921,6 +1022,9 @@ public class DeviceIdleController extends SystemService
                    Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
                }
                updateTempWhitelistAppIdsLocked();
                if (mNetworkPolicyTempWhitelistCallback != null) {
                    mHandler.post(mNetworkPolicyTempWhitelistCallback);
                }
                reportTempWhitelistChangedLocked();
                try {
                    mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
@@ -949,23 +1053,31 @@ public class DeviceIdleController extends SystemService
        if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn);
        if (!screenOn && mScreenOn) {
            mScreenOn = false;
            if (!mForceIdle) {
                becomeInactiveIfAppropriateLocked();
            }
        } else if (screenOn) {
            mScreenOn = true;
            if (!mForceIdle) {
                becomeActiveLocked("screen", Process.myUid());
            }
        }
    }

    void updateChargingLocked(boolean charging) {
        if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
        if (!charging && mCharging) {
            mCharging = false;
            if (!mForceIdle) {
                becomeInactiveIfAppropriateLocked();
            }
        } else if (charging) {
            mCharging = charging;
            if (!mForceIdle) {
                becomeActiveLocked("charging", Process.myUid());
            }
        }
    }

    void scheduleReportActiveLocked(String activeReason, int activeUid) {
        Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid,
@@ -989,7 +1101,7 @@ public class DeviceIdleController extends SystemService

    void becomeInactiveIfAppropriateLocked() {
        if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
        if (!mScreenOn && !mCharging && mEnabled && mState == STATE_ACTIVE) {
        if (((!mScreenOn && !mCharging) || mForceIdle) && mEnabled && mState == STATE_ACTIVE) {
            // Screen has turned off; we are now going to become inactive and start
            // waiting to see if we will ultimately go idle.
            mState = STATE_INACTIVE;
@@ -1010,6 +1122,15 @@ public class DeviceIdleController extends SystemService
        becomeInactiveIfAppropriateLocked();
    }

    void exitForceIdleLocked() {
        if (mForceIdle) {
            mForceIdle = false;
            if (mScreenOn || mCharging) {
                becomeActiveLocked("exit-force-idle", Process.myUid());
            }
        }
    }

    void stepIdleStateLocked() {
        if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
        EventLogTags.writeDeviceIdleStep();
@@ -1138,20 +1259,28 @@ public class DeviceIdleController extends SystemService
          mNextAlarmTime, mSensingAlarmIntent);
    }

    private void updateWhitelistAppIdsLocked() {
        mPowerSaveWhitelistAllAppIds.clear();
        for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) {
            mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true);
    private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
            ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
        outAppIds.clear();
        for (int i=0; i<systemApps.size(); i++) {
            outAppIds.put(systemApps.valueAt(i), true);
        }
        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
            mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
        for (int i=0; i<userApps.size(); i++) {
            outAppIds.put(userApps.valueAt(i), true);
        }
        int size = mPowerSaveWhitelistAllAppIds.size();
        int size = outAppIds.size();
        int[] appids = new int[size];
        for (int i = 0; i < size; i++) {
            appids[i] = mPowerSaveWhitelistAllAppIds.keyAt(i);
            appids[i] = outAppIds.keyAt(i);
        }
        return appids;
    }
        mPowerSaveWhitelistAllAppIdArray = appids;

    private void updateWhitelistAppIdsLocked() {
        mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(mPowerSaveWhitelistAppsExceptIdle,
                mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
        mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
                mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
        if (mLocalPowerManager != null) {
            if (DEBUG) {
                Slog.d(TAG, "Setting wakelock whitelist to "
@@ -1320,6 +1449,9 @@ public class DeviceIdleController extends SystemService
        pw.println("Commands:");
        pw.println("  step");
        pw.println("    Immediately step to next state, without waiting for alarm.");
        pw.println("  force-idle");
        pw.println("    Force directly into idle mode, regardless of other device state.");
        pw.println("    Use \"step\" to get out.");
        pw.println("  disable");
        pw.println("    Completely disable device idle mode.");
        pw.println("  enable");
@@ -1362,6 +1494,7 @@ public class DeviceIdleController extends SystemService
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
                        try {
                            exitForceIdleLocked();
                            stepIdleStateLocked();
                            pw.print("Stepped to: "); pw.println(stateToString(mState));
                        } finally {
@@ -1369,6 +1502,33 @@ public class DeviceIdleController extends SystemService
                        }
                    }
                    return;
                } else if ("force-idle".equals(arg)) {
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
                        try {
                            if (!mEnabled) {
                                pw.println("Unable to go idle; not enabled");
                                return;
                            }
                            mForceIdle = true;
                            becomeInactiveIfAppropriateLocked();
                            int curState = mState;
                            while (curState != STATE_IDLE) {
                                stepIdleStateLocked();
                                if (curState == mState) {
                                    pw.print("Unable to go idle; stopped at ");
                                    pw.println(stateToString(mState));
                                    exitForceIdleLocked();
                                    return;
                                }
                                curState = mState;
                            }
                            pw.println("Now forced in to idle mode");
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                    return;
                } else if ("disable".equals(arg)) {
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
@@ -1387,6 +1547,7 @@ public class DeviceIdleController extends SystemService
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
                        try {
                            exitForceIdleLocked();
                            if (!mEnabled) {
                                mEnabled = true;
                                becomeInactiveIfAppropriateLocked();
@@ -1431,6 +1592,12 @@ public class DeviceIdleController extends SystemService
                            }
                        } else {
                            synchronized (this) {
                                for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
                                    pw.print("system-excidle,");
                                    pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
                                    pw.print(",");
                                    pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
                                }
                                for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
                                    pw.print("system,");
                                    pw.print(mPowerSaveWhitelistApps.keyAt(j));
@@ -1481,7 +1648,15 @@ public class DeviceIdleController extends SystemService
        synchronized (this) {
            mConstants.dump(pw);

            int size = mPowerSaveWhitelistApps.size();
            int size = mPowerSaveWhitelistAppsExceptIdle.size();
            if (size > 0) {
                pw.println("  Whitelist (except idle) system apps:");
                for (int i = 0; i < size; i++) {
                    pw.print("    ");
                    pw.println(mPowerSaveWhitelistAppsExceptIdle.keyAt(i));
                }
            }
            size = mPowerSaveWhitelistApps.size();
            if (size > 0) {
                pw.println("  Whitelist system apps:");
                for (int i = 0; i < size; i++) {
@@ -1497,6 +1672,15 @@ public class DeviceIdleController extends SystemService
                    pw.println(mPowerSaveWhitelistUserApps.keyAt(i));
                }
            }
            size = mPowerSaveWhitelistExceptIdleAppIds.size();
            if (size > 0) {
                pw.println("  Whitelist (except idle) all app ids:");
                for (int i = 0; i < size; i++) {
                    pw.print("    ");
                    pw.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i));
                    pw.println();
                }
            }
            size = mPowerSaveWhitelistAllAppIds.size();
            if (size > 0) {
                pw.println("  Whitelist all app ids:");
@@ -1531,6 +1715,7 @@ public class DeviceIdleController extends SystemService
            }

            pw.print("  mEnabled="); pw.println(mEnabled);
            pw.print("  mForceIdle="); pw.println(mForceIdle);
            pw.print("  mSigMotionSensor="); pw.println(mSigMotionSensor);
            pw.print("  mCurDisplay="); pw.println(mCurDisplay);
            pw.print("  mScreenOn="); pw.println(mScreenOn);
Loading