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

Commit 3b16cf4f authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Device idle fixes: issue #22209630 and issue #22225665

Issue #22209630: Only allow whitelisted apps to put apps on the temp whitelist

We now check whether the calling app is a system uid or in the whitelist
and, if not, throw an exception.

Issue #22225665: Alarm still goes off in idle mode (doze)

Fix a bug where we were not clearing the calling identity when coming
through the dump command to the service, and as a result when we would
eventually call out to the alarm manager it wouldn't do what we want.
This was only broken when being controlled by the shell.

Also adjust the network policy manager service's handling of device
idle transitions to only toggle the device idle state, which gets rid
of the long delay we have coming out of idle mode.  And add in a bit
of logging around going in/out of idle mode to try to understand where
things may be slow in the future.

Change-Id: I4a41f790e9b0bb31330314b94111557d479f2ba5
parent 80abf887
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -216,6 +216,17 @@ public final class UserHandle implements Parcelable {
        }
    }

    /**
     * Generate a text representation of the uid, breaking out its individual
     * components -- user, app, isolated, etc.
     * @hide
     */
    public static String formatUid(int uid) {
        StringBuilder sb = new StringBuilder();
        formatUid(sb, uid);
        return sb.toString();
    }

    /**
     * Generate a text representation of the uid, breaking out its individual
     * components -- user, app, isolated, etc.
+110 −62
Original line number Diff line number Diff line
@@ -157,16 +157,21 @@ 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.
     */
    private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray();

    /**
     * App IDs that have been white-listed to opt out of power save restrictions.
     */
    private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
    private final SparseBooleanArray mPowerSaveWhitelistAllAppIds = new SparseBooleanArray();

    /**
     * Current app IDs that are in the complete power save white list.  This array can
     * be shared with others because it will not be modified once set.
     */
    private int[] mPowerSaveWhitelistAppIdArray = new int[0];
    private int[] mPowerSaveWhitelistAllAppIdArray = new int[0];

    /**
     * List of end times for UIDs that are temporarily marked as being allowed to access
@@ -478,6 +483,7 @@ public class DeviceIdleController extends SystemService
                    handleWriteConfigFile();
                } break;
                case MSG_REPORT_IDLE_ON: {
                    EventLogTags.writeDeviceIdleOnStart();
                    mLocalPowerManager.setDeviceIdleMode(true);
                    try {
                        mNetworkPolicyManager.setDeviceIdleMode(true);
@@ -485,8 +491,10 @@ public class DeviceIdleController extends SystemService
                    } catch (RemoteException e) {
                    }
                    getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                    EventLogTags.writeDeviceIdleOnComplete();
                } break;
                case MSG_REPORT_IDLE_OFF: {
                    EventLogTags.writeDeviceIdleOffStart("unknown");
                    mLocalPowerManager.setDeviceIdleMode(false);
                    try {
                        mNetworkPolicyManager.setDeviceIdleMode(false);
@@ -494,11 +502,14 @@ public class DeviceIdleController extends SystemService
                    } catch (RemoteException e) {
                    }
                    getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                    EventLogTags.writeDeviceIdleOffComplete();
                } break;
                case MSG_REPORT_ACTIVE: {
                    String activeReason = (String)msg.obj;
                    int activeUid = msg.arg1;
                    boolean needBroadcast = msg.arg2 != 0;
                    EventLogTags.writeDeviceIdleOffStart(
                            activeReason != null ? activeReason : "unknown");
                    mLocalPowerManager.setDeviceIdleMode(false);
                    try {
                        mNetworkPolicyManager.setDeviceIdleMode(false);
@@ -508,6 +519,7 @@ public class DeviceIdleController extends SystemService
                    if (needBroadcast) {
                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
                    }
                    EventLogTags.writeDeviceIdleOffComplete();
                } break;
                case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
                    int uid = msg.arg1;
@@ -557,17 +569,18 @@ public class DeviceIdleController extends SystemService
            getContext().enforceCallingPermission(
                    Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                    "No permission to change device idle whitelist");
            final int callingUid = Binder.getCallingUid();
            userId = ActivityManagerNative.getDefault().handleIncomingUser(
                    Binder.getCallingPid(),
                    Binder.getCallingUid(),
                    callingUid,
                    userId,
                    /*allowAll=*/ false,
                    /*requireFull=*/ false,
                    "addPowerSaveTempWhitelistApp", null);
            final long token = Binder.clearCallingIdentity();
            try {
                DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName,
                        duration, userId);
                DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(callingUid,
                        packageName, duration, userId);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
@@ -586,7 +599,7 @@ public class DeviceIdleController extends SystemService

    public final class LocalService {
        public void addPowerSaveTempWhitelistAppDirect(int appId, long duration) {
            DeviceIdleController.this.addPowerSaveTempWhitelistAppDirectInternal(appId, duration);
            addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration);
        }
    }

@@ -614,8 +627,9 @@ public class DeviceIdleController extends SystemService
                try {
                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
                        mPowerSaveWhitelistApps.put(ai.packageName,
                                UserHandle.getAppId(ai.uid));
                        int appid = UserHandle.getAppId(ai.uid);
                        mPowerSaveWhitelistApps.put(ai.packageName, appid);
                        mPowerSaveWhitelistSystemAppIds.put(appid, true);
                    }
                } catch (PackageManager.NameNotFoundException e) {
                }
@@ -667,14 +681,15 @@ public class DeviceIdleController extends SystemService
                mSensingAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intentSensing, 0);

                mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
                mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);

                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_BATTERY_CHANGED);
                filter.addAction(ACTION_STEP_IDLE_STATE);
                getContext().registerReceiver(mReceiver, filter);

                mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
                mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);

                mDisplayManager.registerDisplayListener(mDisplayListener, null);
                updateDisplayLocked();
@@ -747,7 +762,7 @@ public class DeviceIdleController extends SystemService

    public int[] getAppIdWhitelistInternal() {
        synchronized (this) {
            return mPowerSaveWhitelistAppIdArray;
            return mPowerSaveWhitelistAllAppIdArray;
        }
    }

@@ -761,12 +776,12 @@ public class DeviceIdleController extends SystemService
     * Adds an app to the temporary whitelist and resets the endTime for granting the
     * app an exemption to access network and acquire wakelocks.
     */
    public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration,
            int userId) {
    public void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName,
            long duration, int userId) {
        try {
            int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
            int appId = UserHandle.getAppId(uid);
            addPowerSaveTempWhitelistAppDirectInternal(appId, duration);
            addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration);
        } catch (NameNotFoundException e) {
        }
    }
@@ -775,9 +790,17 @@ public class DeviceIdleController extends SystemService
     * Adds an app to the temporary whitelist and resets the endTime for granting the
     * app an exemption to access network and acquire wakelocks.
     */
    public void addPowerSaveTempWhitelistAppDirectInternal(int appId, long duration) {
    public void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int appId,
            long duration) {
        final long timeNow = SystemClock.elapsedRealtime();
        synchronized (this) {
            int callingAppId = UserHandle.getAppId(callingUid);
            if (callingAppId >= Process.FIRST_APPLICATION_UID) {
                if (!mPowerSaveWhitelistSystemAppIds.get(callingAppId)) {
                    throw new SecurityException("Calling app " + UserHandle.formatUid(callingUid)
                            + " is not on whitelist");
                }
            }
            duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
            long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
            // Set the new end time
@@ -1026,25 +1049,25 @@ public class DeviceIdleController extends SystemService
    }

    private void updateWhitelistAppIdsLocked() {
        mPowerSaveWhitelistAppIds.clear();
        mPowerSaveWhitelistAllAppIds.clear();
        for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) {
            mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true);
            mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true);
        }
        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
            mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
            mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
        }
        int size = mPowerSaveWhitelistAppIds.size();
        int size = mPowerSaveWhitelistAllAppIds.size();
        int[] appids = new int[size];
        for (int i = 0; i < size; i++) {
            appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
            appids[i] = mPowerSaveWhitelistAllAppIds.keyAt(i);
        }
        mPowerSaveWhitelistAppIdArray = appids;
        mPowerSaveWhitelistAllAppIdArray = appids;
        if (mLocalPowerManager != null) {
            if (DEBUG) {
                Slog.d(TAG, "Setting wakelock whitelist to "
                        + Arrays.toString(mPowerSaveWhitelistAppIdArray));
                        + Arrays.toString(mPowerSaveWhitelistAllAppIdArray));
            }
            mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
            mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
        }
    }

@@ -1245,26 +1268,41 @@ public class DeviceIdleController extends SystemService
                    // Ignore, we always dump all.
                } else if ("step".equals(arg)) {
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
                        try {
                            stepIdleStateLocked();
                            pw.print("Stepped to: "); pw.println(stateToString(mState));
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                    return;
                } else if ("disable".equals(arg)) {
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
                        try {
                            if (mEnabled) {
                                mEnabled = false;
                                becomeActiveLocked("disabled", Process.myUid());
                                pw.println("Idle mode disabled");
                            }
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                    return;
                } else if ("enable".equals(arg)) {
                    synchronized (this) {
                        long token = Binder.clearCallingIdentity();
                        try {
                            if (!mEnabled) {
                                mEnabled = true;
                                becomeInactiveIfAppropriateLocked();
                                pw.println("Idle mode enabled");
                            }
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                    return;
                } else if ("enabled".equals(arg)) {
@@ -1273,6 +1311,8 @@ public class DeviceIdleController extends SystemService
                    }
                    return;
                } else if ("whitelist".equals(arg)) {
                    long token = Binder.clearCallingIdentity();
                    try {
                        i++;
                        while (i < args.length) {
                            arg = args[i];
@@ -1296,8 +1336,13 @@ public class DeviceIdleController extends SystemService
                                }
                            }
                        }
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                    return;
                } else if ("tempwhitelist".equals(arg)) {
                    long token = Binder.clearCallingIdentity();
                    try {
                        i++;
                        if (i >= args.length) {
                            pw.println("At least one package name must be specified");
@@ -1306,7 +1351,10 @@ public class DeviceIdleController extends SystemService
                        while (i < args.length) {
                            arg = args[i];
                            i++;
                        addPowerSaveTempWhitelistAppInternal(arg, 10000L, userId);
                            addPowerSaveTempWhitelistAppInternal(0, arg, 10000L, userId);
                        }
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                    pw.println("Unknown option: " + arg);
@@ -1337,12 +1385,12 @@ public class DeviceIdleController extends SystemService
                    pw.println(mPowerSaveWhitelistUserApps.keyAt(i));
                }
            }
            size = mPowerSaveWhitelistAppIds.size();
            size = mPowerSaveWhitelistAllAppIds.size();
            if (size > 0) {
                pw.println("  Whitelist app ids:");
                pw.println("  Whitelist all app ids:");
                for (int i = 0; i < size; i++) {
                    pw.print("    ");
                    pw.print(mPowerSaveWhitelistAppIds.keyAt(i));
                    pw.print(mPowerSaveWhitelistAllAppIds.keyAt(i));
                    pw.println();
                }
            }
+8 −2
Original line number Diff line number Diff line
@@ -183,6 +183,12 @@ option java_package com.android.server
34000 device_idle (state|1|5), (reason|3)
34001 device_idle_step
34002 device_idle_wake_from_idle (is_idle|1|5), (reason|3)
34003 device_idle_on_start
34004 device_idle_on_phase (what|3)
34005 device_idle_on_complete
34006 device_idle_off_start (reason|3)
34007 device_idle_off_phase (what|3)
34008 device_idle_off_complete

# ---------------------------
# DisplayManagerService.java
@@ -224,8 +230,8 @@ option java_package com.android.server
# ---------------------------
# IdleMaintenanceService.java
# ---------------------------
2753 idle_maintenance_window_start (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5)
2754 idle_maintenance_window_finish (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5)
51500 idle_maintenance_window_start (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5)
51501 idle_maintenance_window_finish (time|2|3), (lastUserActivity|2|3), (batteryLevel|1|6), (batteryCharging|1|5)

# ---------------------------
# MountService.java
+7 −1
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ import android.util.SparseIntArray;
import android.util.TrustedTime;
import android.util.Xml;

import com.android.server.EventLogTags;
import libcore.io.IoUtils;

import com.android.internal.R;
@@ -1764,7 +1765,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            if (mDeviceIdleMode != enabled) {
                mDeviceIdleMode = enabled;
                if (mSystemReady) {
                    updateRulesForGlobalChangeLocked(true);
                    updateRulesForDeviceIdleLocked();
                }
                if (enabled) {
                    EventLogTags.writeDeviceIdleOnPhase("net");
                } else {
                    EventLogTags.writeDeviceIdleOffPhase("net");
                }
            }
        }
+5 −0
Original line number Diff line number Diff line
@@ -2311,6 +2311,11 @@ public final class PowerManagerService extends SystemService
            if (mDeviceIdleMode != enabled) {
                mDeviceIdleMode = enabled;
                updateWakeLockDisabledStatesLocked();
                if (enabled) {
                    EventLogTags.writeDeviceIdleOnPhase("power");
                } else {
                    EventLogTags.writeDeviceIdleOffPhase("power");
                }
            }
        }
    }