From 4a503b1ece485d44c15eb02ec2bcd464b46e6f7f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 6 Aug 2015 22:19:06 -0700 Subject: [PATCH] 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 --- .../app/usage/UsageStatsManagerInternal.java | 7 + .../android/os/IDeviceIdleController.aidl | 4 + core/java/android/util/SparseIntArray.java | 8 + data/etc/platform.xml | 2 +- .../android/server/DeviceIdleController.java | 219 ++++++++++++++++-- .../java/com/android/server/SystemConfig.java | 20 ++ .../net/NetworkPolicyManagerService.java | 136 +++++++---- .../server/usage/UsageStatsService.java | 78 ++++++- 8 files changed, 411 insertions(+), 63 deletions(-) diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 9113426da1297..948ea1effae72 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -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. diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl index d3eec1ed2198e..f55883ae7a70b 100644 --- a/core/java/android/os/IDeviceIdleController.aidl +++ b/core/java/android/os/IDeviceIdleController.aidl @@ -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); diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 2b85a219861a4..e5c729d3dd44e 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -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 diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 579d2df03b572..350310cab42c7 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -141,6 +141,6 @@ - + diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 7561c7d78b6db..e678bbc8b40ef 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -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 mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>(); + + /** + * Package names the system has white-listed to opt out of power save restrictions for + * all modes. */ private final ArrayMap mPowerSaveWhitelistApps = new ArrayMap<>(); @@ -160,11 +168,30 @@ public class DeviceIdleController extends SystemService */ private final ArrayMap 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 allowPowerExceptIdle = sysConfig.getAllowInPowerSaveExceptIdle(); + for (int i=0; i allowPower = sysConfig.getAllowInPowerSave(); for (int i=0; i 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); diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index ad5406ce17936..cd6134705f017 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -83,6 +83,11 @@ public class SystemConfig { // system configuration files. final ArrayMap mPermissions = new ArrayMap<>(); + // These are the packages that are white-listed to be able to run in the + // background while in power save mode (but not whitelisted from device idle modes), + // as read from the configuration files. + final ArraySet mAllowInPowerSaveExceptIdle = new ArraySet<>(); + // These are the packages that are white-listed to be able to run in the // background while in power save mode, as read from the configuration files. final ArraySet mAllowInPowerSave = new ArraySet<>(); @@ -123,6 +128,10 @@ public class SystemConfig { return mPermissions; } + public ArraySet getAllowInPowerSaveExceptIdle() { + return mAllowInPowerSaveExceptIdle; + } + public ArraySet getAllowInPowerSave() { return mAllowInPowerSave; } @@ -329,6 +338,17 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); continue; + } else if ("allow-in-power-save-except-idle".equals(name) && !onlyFeatures) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, " without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInPowerSaveExceptIdle.add(pkgname); + } + XmlUtils.skipCurrentTag(parser); + continue; + } else if ("allow-in-power-save".equals(name) && !onlyFeatures) { String pkgname = parser.getAttributeValue(null, "package"); if (pkgname == null) { diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 46bda8ccfd892..c0d0d13006cee 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -39,6 +39,7 @@ import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; +import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE; @@ -46,7 +47,6 @@ import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; -import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.dumpPolicy; import static android.net.NetworkPolicyManager.dumpRules; @@ -282,6 +282,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Set of states for the child firewall chains. True if the chain is active. */ final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray(); + /** + * UIDs that have been white-listed to always be able to have network access + * in power save mode, except device idle (doze) still applies. + * TODO: An int array might be sufficient + */ + private final SparseBooleanArray mPowerSaveWhitelistExceptIdleAppIds = new SparseBooleanArray(); + /** * UIDs that have been white-listed to always be able to have network access * in power save mode. @@ -302,9 +309,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Foreground at UID granularity. */ final SparseIntArray mUidState = new SparseIntArray(); - /** The current maximum process state that we are considering to be foreground. */ - private int mCurForegroundState = ActivityManager.PROCESS_STATE_TOP; - private final RemoteCallbackList mListeners = new RemoteCallbackList<>(); @@ -365,7 +369,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updatePowerSaveWhitelistLocked() { try { - final int[] whitelist = mDeviceIdleController.getAppIdWhitelist(); + int[] whitelist = mDeviceIdleController.getAppIdWhitelistExceptIdle(); + mPowerSaveWhitelistExceptIdleAppIds.clear(); + if (whitelist != null) { + for (int uid : whitelist) { + mPowerSaveWhitelistExceptIdleAppIds.put(uid, true); + } + } + whitelist = mDeviceIdleController.getAppIdWhitelist(); mPowerSaveWhitelistAppIds.clear(); if (whitelist != null) { for (int uid : whitelist) { @@ -425,7 +436,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mRestrictPower != enabled) { mRestrictPower = enabled; updateRulesForGlobalChangeLocked(true); - updateRulesForTempWhitelistChangeLocked(); } } } @@ -437,9 +447,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { readPolicyLocked(); if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) { - updateRulesForGlobalChangeLocked(true); - updateRulesForTempWhitelistChangeLocked(); + updateRulesForGlobalChangeLocked(false); updateNotificationsLocked(); + } else { + // If we are not in any special mode, we just need to make sure the current + // app idle state is updated. + updateRulesForAppIdleLocked(); } } @@ -1907,7 +1920,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print("Restrict background: "); fout.println(mRestrictBackground); fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Device idle: "); fout.println(mDeviceIdleMode); - fout.print("Current foreground state: "); fout.println(mCurForegroundState); fout.println("Network policies:"); fout.increaseIndent(); for (int i = 0; i < mNetworkPolicy.size(); i++) { @@ -1931,6 +1943,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } fout.decreaseIndent(); + size = mPowerSaveWhitelistExceptIdleAppIds.size(); + if (size > 0) { + fout.println("Power save whitelist (except idle) app ids:"); + fout.increaseIndent(); + for (int i = 0; i < size; i++) { + fout.print("UID="); + fout.print(mPowerSaveWhitelistExceptIdleAppIds.keyAt(i)); + fout.print(": "); + fout.print(mPowerSaveWhitelistExceptIdleAppIds.valueAt(i)); + fout.println(); + } + fout.decreaseIndent(); + } + size = mPowerSaveWhitelistAppIds.size(); if (size > 0) { fout.println("Power save whitelist app ids:"); @@ -1960,7 +1986,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); fout.print(" state="); fout.print(state); - fout.print(state <= mCurForegroundState ? " (fg)" : " (bg)"); + fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)"); fout.print(" rules="); final int rulesIndex = mUidRules.indexOfKey(uid); @@ -1988,7 +2014,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { boolean isUidForegroundLocked(int uid) { // only really in foreground when screen is also on return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY) - <= mCurForegroundState; + <= ActivityManager.PROCESS_STATE_TOP; } /** @@ -2024,8 +2050,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) { - final boolean oldForeground = oldUidState <= mCurForegroundState; - final boolean newForeground = newUidState <= mCurForegroundState; + final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP; + final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP; if (oldForeground != newForeground) { updateRulesForUidLocked(uid); } @@ -2049,7 +2075,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // only update rules for anyone with foreground activities final int size = mUidState.size(); for (int i = 0; i < size; i++) { - if (mUidState.valueAt(i) <= mCurForegroundState) { + if (mUidState.valueAt(i) <= ActivityManager.PROCESS_STATE_TOP) { final int uid = mUidState.keyAt(i); updateRulesForUidLocked(uid); } @@ -2069,9 +2095,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int ui = users.size() - 1; ui >= 0; ui--) { UserInfo user = users.get(ui); for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { - int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); - int uid = UserHandle.getUid(user.id, appId); - uidRules.put(uid, FIREWALL_RULE_ALLOW); + if (mPowerSaveTempWhitelistAppIds.valueAt(i)) { + int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); + int uid = UserHandle.getUid(user.id, appId); + uidRules.put(uid, FIREWALL_RULE_ALLOW); + } } for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) { int appId = mPowerSaveWhitelistAppIds.keyAt(i); @@ -2089,6 +2117,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode); } + void updateRuleForDeviceIdleLocked(int uid) { + if (mDeviceIdleMode) { + int appId = UserHandle.getAppId(uid); + if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId) + || isProcStateAllowedWhileIdle(mUidState.get(uid))) { + setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW); + } else { + setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT); + } + } + } + + void updateRulesForAppIdleLocked() { + // Fully update the app idle firewall chain. + SparseIntArray uidRules = new SparseIntArray(); + final List users = mUserManager.getUsers(); + for (int ui = users.size() - 1; ui >= 0; ui--) { + UserInfo user = users.get(ui); + int[] idleUids = mUsageStats.getIdleUidsForUser(user.id); + for (int uid : idleUids) { + if (!mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid), false)) { + uidRules.put(uid, FIREWALL_RULE_DENY); + } + } + } + setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules); + } + + void updateRuleForAppIdleLocked(int uid) { + if (!isUidValidForRules(uid)) return; + + int appId = UserHandle.getAppId(uid); + if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)) { + setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY); + } else { + setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); + } + } + void updateRulesForAppIdleParoleLocked() { boolean enableChain = !mUsageStats.isAppIdleParoleOn(); enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain); @@ -2101,14 +2168,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) { final PackageManager pm = mContext.getPackageManager(); - // If we are in restrict power mode, we allow all important apps - // to have data access. Otherwise, we restrict data access to only - // the top apps. - mCurForegroundState = (!mRestrictBackground && mRestrictPower) - ? ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE - : ActivityManager.PROCESS_STATE_TOP; - updateRulesForDeviceIdleLocked(); + updateRulesForAppIdleLocked(); // update rules for all installed applications final List users = mUserManager.getUsers(); @@ -2138,10 +2199,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (UserInfo user : users) { for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); - boolean isAllow = mPowerSaveTempWhitelistAppIds.valueAt(i); int uid = UserHandle.getUid(user.id, appId); - updateRulesForUidLocked(uid); - setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, !isAllow); + updateRuleForAppIdleLocked(uid); + updateRuleForDeviceIdleLocked(uid); } } } @@ -2188,16 +2248,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final boolean uidForeground = isUidForegroundLocked(uid); - final boolean uidIdle = isUidIdle(uid); // derive active rules based on policy and active state int appId = UserHandle.getAppId(uid); int uidRules = RULE_ALLOW_ALL; - if (uidIdle && !mPowerSaveWhitelistAppIds.get(appId) - && !mPowerSaveTempWhitelistAppIds.get(appId)) { - uidRules = RULE_REJECT_ALL; - } else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { + if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { // uid in background, and policy says to block metered data uidRules = RULE_REJECT_METERED; } else if (mRestrictBackground) { @@ -2206,7 +2262,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { uidRules = RULE_REJECT_METERED; } } else if (mRestrictPower) { - final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId) + final boolean whitelisted = mPowerSaveWhitelistExceptIdleAppIds.get(appId) || mPowerSaveTempWhitelistAppIds.get(appId); if (!whitelisted && !uidForeground && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) { @@ -2232,13 +2288,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setUidNetworkRules(uid, rejectMetered); } - // Update firewall rules if necessary - final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0; - final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0; - if (oldFirewallReject != firewallReject) { - setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject); - } - // dispatch changed rule to existing listeners if (oldRules != uidRules) { mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget(); @@ -2260,7 +2309,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { try { int uid = mContext.getPackageManager().getPackageUid(packageName, userId); synchronized (mRulesLock) { - updateRulesForUidLocked(uid); + updateRuleForAppIdleLocked(uid); } } catch (NameNotFoundException nnfe) { } @@ -2422,10 +2471,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Add or remove a uid to the firewall blacklist for all network ifaces. */ - private void setUidFirewallRule(int chain, int uid, boolean rejectOnAll) { + private void setUidFirewallRule(int chain, int uid, int rule) { try { - mNetworkManager.setFirewallUidRule(chain, uid, - rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW); + mNetworkManager.setFirewallUidRule(chain, uid, rule); } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting firewall uid rules", e); } catch (RemoteException e) { diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index a433ec45191c8..85f0665010f16 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -35,6 +35,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; @@ -65,6 +66,7 @@ import android.util.AtomicFile; import android.util.KeyValueListParser; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.util.TimeUtils; import android.view.Display; @@ -799,7 +801,10 @@ public class UsageStatsService extends SystemService implements } if (packageName.equals("android")) return false; try { - if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) { + // We allow all whitelisted apps, including those that don't want to be whitelisted + // for idle mode, because app idle (aka app standby) is really not as big an issue + // for controlling who participates vs. doze mode. + if (mDeviceIdleController.isPowerSaveWhitelistExceptIdleApp(packageName)) { return false; } } catch (RemoteException re) { @@ -825,6 +830,72 @@ public class UsageStatsService extends SystemService implements return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime); } + int[] getIdleUidsForUser(int userId) { + if (!mAppIdleEnabled) { + return new int[0]; + } + + final long timeNow; + final UserUsageStatsService userService; + final long screenOnTime; + synchronized (mLock) { + timeNow = checkAndGetTimeLocked(); + userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow); + screenOnTime = getScreenOnTimeLocked(timeNow); + } + + List apps; + try { + ParceledListSlice slice + = AppGlobals.getPackageManager().getInstalledApplications(0, userId); + apps = slice.getList(); + } catch (RemoteException e) { + return new int[0]; + } + + // State of each uid. Key is the uid. Value lower 16 bits is the number of apps + // associated with that uid, upper 16 bits is the number of those apps that is idle. + SparseIntArray uidStates = new SparseIntArray(); + + // Now resolve all app state. Iterating over all apps, keeping track of how many + // we find for each uid and how many of those are idle. + for (int i = apps.size()-1; i >= 0; i--) { + ApplicationInfo ai = apps.get(i); + + // Check whether this app is idle. + boolean idle = isAppIdleFiltered(ai.packageName, userId, userService, timeNow, + screenOnTime); + + int index = uidStates.indexOfKey(ai.uid); + if (index < 0) { + uidStates.put(ai.uid, 1 + (idle ? 1<<16 : 0)); + } else { + int value = uidStates.valueAt(index); + uidStates.setValueAt(index, value + 1 + (idle ? 1<<16 : 0)); + } + } + + int numIdle = 0; + for (int i = uidStates.size() - 1; i >= 0; i--) { + int value = uidStates.valueAt(i); + if ((value&0x7fff) == (value>>16)) { + numIdle++; + } + } + + int[] res = new int[numIdle]; + numIdle = 0; + for (int i = uidStates.size() - 1; i >= 0; i--) { + int value = uidStates.valueAt(i); + if ((value&0x7fff) == (value>>16)) { + res[numIdle] = uidStates.keyAt(i); + numIdle++; + } + } + + return res; + } + void setAppIdle(String packageName, boolean idle, int userId) { if (packageName == null) return; @@ -1283,6 +1354,11 @@ public class UsageStatsService extends SystemService implements return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1); } + @Override + public int[] getIdleUidsForUser(int userId) { + return UsageStatsService.this.getIdleUidsForUser(userId); + } + @Override public boolean isAppIdleParoleOn() { return mAppIdleParoled;