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;