Merge "Fix issue #22989030: Separate battery whitelists" into mnc-dev

This commit is contained in:
Dianne Hackborn
2015-08-07 21:58:38 +00:00
committed by Android (Google) Code Review
8 changed files with 411 additions and 63 deletions

View File

@ -76,6 +76,13 @@ public abstract class UsageStatsManagerInternal {
*/ */
public abstract boolean isAppIdle(String packageName, int userId); 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 * @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. * run for a short period of time.

View File

@ -22,10 +22,14 @@ import android.os.UserHandle;
interface IDeviceIdleController { interface IDeviceIdleController {
void addPowerSaveWhitelistApp(String name); void addPowerSaveWhitelistApp(String name);
void removePowerSaveWhitelistApp(String name); void removePowerSaveWhitelistApp(String name);
String[] getSystemPowerWhitelistExceptIdle();
String[] getSystemPowerWhitelist(); String[] getSystemPowerWhitelist();
String[] getFullPowerWhitelistExceptIdle();
String[] getFullPowerWhitelist(); String[] getFullPowerWhitelist();
int[] getAppIdWhitelistExceptIdle();
int[] getAppIdWhitelist(); int[] getAppIdWhitelist();
int[] getAppIdTempWhitelist(); int[] getAppIdTempWhitelist();
boolean isPowerSaveWhitelistExceptIdleApp(String name);
boolean isPowerSaveWhitelistApp(String name); boolean isPowerSaveWhitelistApp(String name);
void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason); void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason); long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);

View File

@ -183,6 +183,14 @@ public class SparseIntArray implements Cloneable {
return mValues[index]; 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 * Returns the index for which {@link #keyAt} would return the
* specified key, or a negative number if the specified * specified key, or a negative number if the specified

View File

@ -141,6 +141,6 @@
<!-- These are the standard packages that are white-listed to always have internet <!-- 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. --> 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> </permissions>

View File

@ -113,6 +113,7 @@ public class DeviceIdleController extends SystemService
private Display mCurDisplay; private Display mCurDisplay;
private AnyMotionDetector mAnyMotionDetector; private AnyMotionDetector mAnyMotionDetector;
private boolean mEnabled; private boolean mEnabled;
private boolean mForceIdle;
private boolean mScreenOn; private boolean mScreenOn;
private boolean mCharging; private boolean mCharging;
private boolean mSigMotionActive; private boolean mSigMotionActive;
@ -151,7 +152,14 @@ public class DeviceIdleController extends SystemService
public final AtomicFile mConfigFile; 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<>(); 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<>(); 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. * App IDs of built-in system apps that have been white-listed.
*/ */
private final SparseBooleanArray mPowerSaveWhitelistSystemAppIds = new SparseBooleanArray(); 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. * 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); removePowerSaveWhitelistAppInternal(name);
} }
@Override public String[] getSystemPowerWhitelistExceptIdle() {
return getSystemPowerWhitelistExceptIdleInternal();
}
@Override public String[] getSystemPowerWhitelist() { @Override public String[] getSystemPowerWhitelist() {
return getSystemPowerWhitelistInternal(); return getSystemPowerWhitelistInternal();
} }
@Override public String[] getFullPowerWhitelistExceptIdle() {
return getFullPowerWhitelistExceptIdleInternal();
}
@Override public String[] getFullPowerWhitelist() { @Override public String[] getFullPowerWhitelist() {
return getFullPowerWhitelistInternal(); return getFullPowerWhitelistInternal();
} }
@Override public int[] getAppIdWhitelistExceptIdle() {
return getAppIdWhitelistExceptIdleInternal();
}
@Override public int[] getAppIdWhitelist() { @Override public int[] getAppIdWhitelist() {
return getAppIdWhitelistInternal(); return getAppIdWhitelistInternal();
} }
@ -599,6 +638,10 @@ public class DeviceIdleController extends SystemService
return getAppIdTempWhitelistInternal(); return getAppIdTempWhitelistInternal();
} }
@Override public boolean isPowerSaveWhitelistExceptIdleApp(String name) {
return isPowerSaveWhitelistExceptIdleAppInternal(name);
}
@Override public boolean isPowerSaveWhitelistApp(String name) { @Override public boolean isPowerSaveWhitelistApp(String name) {
return isPowerSaveWhitelistAppInternal(name); return isPowerSaveWhitelistAppInternal(name);
} }
@ -679,6 +722,19 @@ public class DeviceIdleController extends SystemService
mEnabled = getContext().getResources().getBoolean( mEnabled = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_enableAutoPowerModes); com.android.internal.R.bool.config_enableAutoPowerModes);
SystemConfig sysConfig = SystemConfig.getInstance(); 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(); ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
for (int i=0; i<allowPower.size(); i++) { for (int i=0; i<allowPower.size(); i++) {
String pkg = allowPower.valueAt(i); String pkg = allowPower.valueAt(i);
@ -686,6 +742,10 @@ public class DeviceIdleController extends SystemService
ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
int appid = UserHandle.getAppId(ai.uid); 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); mPowerSaveWhitelistApps.put(ai.packageName, appid);
mPowerSaveWhitelistSystemAppIds.put(appid, true); mPowerSaveWhitelistSystemAppIds.put(appid, true);
} }
@ -783,17 +843,45 @@ public class DeviceIdleController extends SystemService
return false; 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() { public String[] getSystemPowerWhitelistInternal() {
synchronized (this) { synchronized (this) {
int size = mPowerSaveWhitelistApps.size(); int size = mPowerSaveWhitelistApps.size();
String[] apps = new String[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); apps[i] = mPowerSaveWhitelistApps.keyAt(i);
} }
return apps; 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() { public String[] getFullPowerWhitelistInternal() {
synchronized (this) { synchronized (this) {
int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size(); 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) { public boolean isPowerSaveWhitelistAppInternal(String packageName) {
synchronized (this) { synchronized (this) {
return mPowerSaveWhitelistApps.containsKey(packageName) return mPowerSaveWhitelistApps.containsKey(packageName)
@ -818,6 +913,12 @@ public class DeviceIdleController extends SystemService
} }
} }
public int[] getAppIdWhitelistExceptIdleInternal() {
synchronized (this) {
return mPowerSaveWhitelistExceptIdleAppIdArray;
}
}
public int[] getAppIdWhitelistInternal() { public int[] getAppIdWhitelistInternal() {
synchronized (this) { synchronized (this) {
return mPowerSaveWhitelistAllAppIdArray; return mPowerSaveWhitelistAllAppIdArray;
@ -921,6 +1022,9 @@ public class DeviceIdleController extends SystemService
Slog.d(TAG, "Removing UID " + uid + " from temp whitelist"); Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
} }
updateTempWhitelistAppIdsLocked(); updateTempWhitelistAppIdsLocked();
if (mNetworkPolicyTempWhitelistCallback != null) {
mHandler.post(mNetworkPolicyTempWhitelistCallback);
}
reportTempWhitelistChangedLocked(); reportTempWhitelistChangedLocked();
try { try {
mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH, mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
@ -949,10 +1053,14 @@ public class DeviceIdleController extends SystemService
if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn); if (DEBUG) Slog.d(TAG, "updateDisplayLocked: screenOn=" + screenOn);
if (!screenOn && mScreenOn) { if (!screenOn && mScreenOn) {
mScreenOn = false; mScreenOn = false;
becomeInactiveIfAppropriateLocked(); if (!mForceIdle) {
becomeInactiveIfAppropriateLocked();
}
} else if (screenOn) { } else if (screenOn) {
mScreenOn = true; mScreenOn = true;
becomeActiveLocked("screen", Process.myUid()); if (!mForceIdle) {
becomeActiveLocked("screen", Process.myUid());
}
} }
} }
@ -960,10 +1068,14 @@ public class DeviceIdleController extends SystemService
if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging); if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
if (!charging && mCharging) { if (!charging && mCharging) {
mCharging = false; mCharging = false;
becomeInactiveIfAppropriateLocked(); if (!mForceIdle) {
becomeInactiveIfAppropriateLocked();
}
} else if (charging) { } else if (charging) {
mCharging = charging; mCharging = charging;
becomeActiveLocked("charging", Process.myUid()); if (!mForceIdle) {
becomeActiveLocked("charging", Process.myUid());
}
} }
} }
@ -989,7 +1101,7 @@ public class DeviceIdleController extends SystemService
void becomeInactiveIfAppropriateLocked() { void becomeInactiveIfAppropriateLocked() {
if (DEBUG) Slog.d(TAG, "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 // Screen has turned off; we are now going to become inactive and start
// waiting to see if we will ultimately go idle. // waiting to see if we will ultimately go idle.
mState = STATE_INACTIVE; mState = STATE_INACTIVE;
@ -1010,6 +1122,15 @@ public class DeviceIdleController extends SystemService
becomeInactiveIfAppropriateLocked(); becomeInactiveIfAppropriateLocked();
} }
void exitForceIdleLocked() {
if (mForceIdle) {
mForceIdle = false;
if (mScreenOn || mCharging) {
becomeActiveLocked("exit-force-idle", Process.myUid());
}
}
}
void stepIdleStateLocked() { void stepIdleStateLocked() {
if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState); if (DEBUG) Slog.d(TAG, "stepIdleStateLocked: mState=" + mState);
EventLogTags.writeDeviceIdleStep(); EventLogTags.writeDeviceIdleStep();
@ -1138,20 +1259,28 @@ public class DeviceIdleController extends SystemService
mNextAlarmTime, mSensingAlarmIntent); mNextAlarmTime, mSensingAlarmIntent);
} }
private void updateWhitelistAppIdsLocked() { private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
mPowerSaveWhitelistAllAppIds.clear(); ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) { outAppIds.clear();
mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true); for (int i=0; i<systemApps.size(); i++) {
outAppIds.put(systemApps.valueAt(i), true);
} }
for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) { for (int i=0; i<userApps.size(); i++) {
mPowerSaveWhitelistAllAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true); outAppIds.put(userApps.valueAt(i), true);
} }
int size = mPowerSaveWhitelistAllAppIds.size(); int size = outAppIds.size();
int[] appids = new int[size]; int[] appids = new int[size];
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
appids[i] = mPowerSaveWhitelistAllAppIds.keyAt(i); appids[i] = outAppIds.keyAt(i);
} }
mPowerSaveWhitelistAllAppIdArray = appids; return appids;
}
private void updateWhitelistAppIdsLocked() {
mPowerSaveWhitelistExceptIdleAppIdArray = buildAppIdArray(mPowerSaveWhitelistAppsExceptIdle,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
if (mLocalPowerManager != null) { if (mLocalPowerManager != null) {
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Setting wakelock whitelist to " Slog.d(TAG, "Setting wakelock whitelist to "
@ -1320,6 +1449,9 @@ public class DeviceIdleController extends SystemService
pw.println("Commands:"); pw.println("Commands:");
pw.println(" step"); pw.println(" step");
pw.println(" Immediately step to next state, without waiting for alarm."); 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(" disable");
pw.println(" Completely disable device idle mode."); pw.println(" Completely disable device idle mode.");
pw.println(" enable"); pw.println(" enable");
@ -1362,6 +1494,7 @@ public class DeviceIdleController extends SystemService
synchronized (this) { synchronized (this) {
long token = Binder.clearCallingIdentity(); long token = Binder.clearCallingIdentity();
try { try {
exitForceIdleLocked();
stepIdleStateLocked(); stepIdleStateLocked();
pw.print("Stepped to: "); pw.println(stateToString(mState)); pw.print("Stepped to: "); pw.println(stateToString(mState));
} finally { } finally {
@ -1369,6 +1502,33 @@ public class DeviceIdleController extends SystemService
} }
} }
return; 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)) { } else if ("disable".equals(arg)) {
synchronized (this) { synchronized (this) {
long token = Binder.clearCallingIdentity(); long token = Binder.clearCallingIdentity();
@ -1387,6 +1547,7 @@ public class DeviceIdleController extends SystemService
synchronized (this) { synchronized (this) {
long token = Binder.clearCallingIdentity(); long token = Binder.clearCallingIdentity();
try { try {
exitForceIdleLocked();
if (!mEnabled) { if (!mEnabled) {
mEnabled = true; mEnabled = true;
becomeInactiveIfAppropriateLocked(); becomeInactiveIfAppropriateLocked();
@ -1431,6 +1592,12 @@ public class DeviceIdleController extends SystemService
} }
} else { } else {
synchronized (this) { 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++) { for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
pw.print("system,"); pw.print("system,");
pw.print(mPowerSaveWhitelistApps.keyAt(j)); pw.print(mPowerSaveWhitelistApps.keyAt(j));
@ -1481,7 +1648,15 @@ public class DeviceIdleController extends SystemService
synchronized (this) { synchronized (this) {
mConstants.dump(pw); 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) { if (size > 0) {
pw.println(" Whitelist system apps:"); pw.println(" Whitelist system apps:");
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -1497,6 +1672,15 @@ public class DeviceIdleController extends SystemService
pw.println(mPowerSaveWhitelistUserApps.keyAt(i)); 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(); size = mPowerSaveWhitelistAllAppIds.size();
if (size > 0) { if (size > 0) {
pw.println(" Whitelist all app ids:"); pw.println(" Whitelist all app ids:");
@ -1531,6 +1715,7 @@ public class DeviceIdleController extends SystemService
} }
pw.print(" mEnabled="); pw.println(mEnabled); pw.print(" mEnabled="); pw.println(mEnabled);
pw.print(" mForceIdle="); pw.println(mForceIdle);
pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay); pw.print(" mCurDisplay="); pw.println(mCurDisplay);
pw.print(" mScreenOn="); pw.println(mScreenOn); pw.print(" mScreenOn="); pw.println(mScreenOn);

View File

@ -83,6 +83,11 @@ public class SystemConfig {
// system configuration files. // system configuration files.
final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>(); final ArrayMap<String, PermissionEntry> 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<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
// These are the packages that are white-listed to be able to run in the // 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. // background while in power save mode, as read from the configuration files.
final ArraySet<String> mAllowInPowerSave = new ArraySet<>(); final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
@ -123,6 +128,10 @@ public class SystemConfig {
return mPermissions; return mPermissions;
} }
public ArraySet<String> getAllowInPowerSaveExceptIdle() {
return mAllowInPowerSaveExceptIdle;
}
public ArraySet<String> getAllowInPowerSave() { public ArraySet<String> getAllowInPowerSave() {
return mAllowInPowerSave; return mAllowInPowerSave;
} }
@ -329,6 +338,17 @@ public class SystemConfig {
XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser);
continue; continue;
} else if ("allow-in-power-save-except-idle".equals(name) && !onlyFeatures) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
+ permFile + " at " + parser.getPositionDescription());
} else {
mAllowInPowerSaveExceptIdle.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("allow-in-power-save".equals(name) && !onlyFeatures) { } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
String pkgname = parser.getAttributeValue(null, "package"); String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) { if (pkgname == null) {

View File

@ -39,6 +39,7 @@ import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; 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_ALLOW;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE; 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.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; 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.computeLastCycleBoundary;
import static android.net.NetworkPolicyManager.dumpPolicy; import static android.net.NetworkPolicyManager.dumpPolicy;
import static android.net.NetworkPolicyManager.dumpRules; 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. */ /** Set of states for the child firewall chains. True if the chain is active. */
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray(); 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 * UIDs that have been white-listed to always be able to have network access
* in power save mode. * in power save mode.
@ -302,9 +309,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Foreground at UID granularity. */ /** Foreground at UID granularity. */
final SparseIntArray mUidState = new SparseIntArray(); 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<INetworkPolicyListener> private final RemoteCallbackList<INetworkPolicyListener>
mListeners = new RemoteCallbackList<>(); mListeners = new RemoteCallbackList<>();
@ -365,7 +369,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updatePowerSaveWhitelistLocked() { void updatePowerSaveWhitelistLocked() {
try { 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(); mPowerSaveWhitelistAppIds.clear();
if (whitelist != null) { if (whitelist != null) {
for (int uid : whitelist) { for (int uid : whitelist) {
@ -425,7 +436,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (mRestrictPower != enabled) { if (mRestrictPower != enabled) {
mRestrictPower = enabled; mRestrictPower = enabled;
updateRulesForGlobalChangeLocked(true); updateRulesForGlobalChangeLocked(true);
updateRulesForTempWhitelistChangeLocked();
} }
} }
} }
@ -437,9 +447,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
readPolicyLocked(); readPolicyLocked();
if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) { if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) {
updateRulesForGlobalChangeLocked(true); updateRulesForGlobalChangeLocked(false);
updateRulesForTempWhitelistChangeLocked();
updateNotificationsLocked(); 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 background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower); fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode); fout.print("Device idle: "); fout.println(mDeviceIdleMode);
fout.print("Current foreground state: "); fout.println(mCurForegroundState);
fout.println("Network policies:"); fout.println("Network policies:");
fout.increaseIndent(); fout.increaseIndent();
for (int i = 0; i < mNetworkPolicy.size(); i++) { for (int i = 0; i < mNetworkPolicy.size(); i++) {
@ -1931,6 +1943,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
} }
fout.decreaseIndent(); 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(); size = mPowerSaveWhitelistAppIds.size();
if (size > 0) { if (size > 0) {
fout.println("Power save whitelist app ids:"); 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); int state = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
fout.print(" state="); fout.print(" state=");
fout.print(state); fout.print(state);
fout.print(state <= mCurForegroundState ? " (fg)" : " (bg)"); fout.print(state <= ActivityManager.PROCESS_STATE_TOP ? " (fg)" : " (bg)");
fout.print(" rules="); fout.print(" rules=");
final int rulesIndex = mUidRules.indexOfKey(uid); final int rulesIndex = mUidRules.indexOfKey(uid);
@ -1988,7 +2014,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
boolean isUidForegroundLocked(int uid) { boolean isUidForegroundLocked(int uid) {
// only really in foreground when screen is also on // only really in foreground when screen is also on
return mScreenOn && mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY) 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) { void updateRulesForUidStateChangeLocked(int uid, int oldUidState, int newUidState) {
final boolean oldForeground = oldUidState <= mCurForegroundState; final boolean oldForeground = oldUidState <= ActivityManager.PROCESS_STATE_TOP;
final boolean newForeground = newUidState <= mCurForegroundState; final boolean newForeground = newUidState <= ActivityManager.PROCESS_STATE_TOP;
if (oldForeground != newForeground) { if (oldForeground != newForeground) {
updateRulesForUidLocked(uid); updateRulesForUidLocked(uid);
} }
@ -2049,7 +2075,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// only update rules for anyone with foreground activities // only update rules for anyone with foreground activities
final int size = mUidState.size(); final int size = mUidState.size();
for (int i = 0; i < size; i++) { 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); final int uid = mUidState.keyAt(i);
updateRulesForUidLocked(uid); updateRulesForUidLocked(uid);
} }
@ -2069,9 +2095,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (int ui = users.size() - 1; ui >= 0; ui--) { for (int ui = users.size() - 1; ui >= 0; ui--) {
UserInfo user = users.get(ui); UserInfo user = users.get(ui);
for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); if (mPowerSaveTempWhitelistAppIds.valueAt(i)) {
int uid = UserHandle.getUid(user.id, appId); int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
uidRules.put(uid, FIREWALL_RULE_ALLOW); int uid = UserHandle.getUid(user.id, appId);
uidRules.put(uid, FIREWALL_RULE_ALLOW);
}
} }
for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) { for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) {
int appId = mPowerSaveWhitelistAppIds.keyAt(i); int appId = mPowerSaveWhitelistAppIds.keyAt(i);
@ -2089,6 +2117,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode); 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<UserInfo> 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() { void updateRulesForAppIdleParoleLocked() {
boolean enableChain = !mUsageStats.isAppIdleParoleOn(); boolean enableChain = !mUsageStats.isAppIdleParoleOn();
enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain); enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
@ -2101,14 +2168,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) { void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
final PackageManager pm = mContext.getPackageManager(); 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(); updateRulesForDeviceIdleLocked();
updateRulesForAppIdleLocked();
// update rules for all installed applications // update rules for all installed applications
final List<UserInfo> users = mUserManager.getUsers(); final List<UserInfo> users = mUserManager.getUsers();
@ -2138,10 +2199,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (UserInfo user : users) { for (UserInfo user : users) {
for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
boolean isAllow = mPowerSaveTempWhitelistAppIds.valueAt(i);
int uid = UserHandle.getUid(user.id, appId); int uid = UserHandle.getUid(user.id, appId);
updateRulesForUidLocked(uid); updateRuleForAppIdleLocked(uid);
setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, !isAllow); updateRuleForDeviceIdleLocked(uid);
} }
} }
} }
@ -2188,16 +2248,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
final boolean uidForeground = isUidForegroundLocked(uid); final boolean uidForeground = isUidForegroundLocked(uid);
final boolean uidIdle = isUidIdle(uid);
// derive active rules based on policy and active state // derive active rules based on policy and active state
int appId = UserHandle.getAppId(uid); int appId = UserHandle.getAppId(uid);
int uidRules = RULE_ALLOW_ALL; int uidRules = RULE_ALLOW_ALL;
if (uidIdle && !mPowerSaveWhitelistAppIds.get(appId) if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
&& !mPowerSaveTempWhitelistAppIds.get(appId)) {
uidRules = RULE_REJECT_ALL;
} else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
// uid in background, and policy says to block metered data // uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED; uidRules = RULE_REJECT_METERED;
} else if (mRestrictBackground) { } else if (mRestrictBackground) {
@ -2206,7 +2262,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
uidRules = RULE_REJECT_METERED; uidRules = RULE_REJECT_METERED;
} }
} else if (mRestrictPower) { } else if (mRestrictPower) {
final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId) final boolean whitelisted = mPowerSaveWhitelistExceptIdleAppIds.get(appId)
|| mPowerSaveTempWhitelistAppIds.get(appId); || mPowerSaveTempWhitelistAppIds.get(appId);
if (!whitelisted && !uidForeground if (!whitelisted && !uidForeground
&& (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) { && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
@ -2232,13 +2288,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
setUidNetworkRules(uid, rejectMetered); 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 // dispatch changed rule to existing listeners
if (oldRules != uidRules) { if (oldRules != uidRules) {
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget(); mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
@ -2260,7 +2309,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
try { try {
int uid = mContext.getPackageManager().getPackageUid(packageName, userId); int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
synchronized (mRulesLock) { synchronized (mRulesLock) {
updateRulesForUidLocked(uid); updateRuleForAppIdleLocked(uid);
} }
} catch (NameNotFoundException nnfe) { } 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. * 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 { try {
mNetworkManager.setFirewallUidRule(chain, uid, mNetworkManager.setFirewallUidRule(chain, uid, rule);
rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting firewall uid rules", e); Log.wtf(TAG, "problem setting firewall uid rules", e);
} catch (RemoteException e) { } catch (RemoteException e) {

View File

@ -35,6 +35,7 @@ import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice; import android.content.pm.ParceledListSlice;
@ -65,6 +66,7 @@ import android.util.AtomicFile;
import android.util.KeyValueListParser; import android.util.KeyValueListParser;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils; import android.util.TimeUtils;
import android.view.Display; import android.view.Display;
@ -799,7 +801,10 @@ public class UsageStatsService extends SystemService implements
} }
if (packageName.equals("android")) return false; if (packageName.equals("android")) return false;
try { 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; return false;
} }
} catch (RemoteException re) { } catch (RemoteException re) {
@ -825,6 +830,72 @@ public class UsageStatsService extends SystemService implements
return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime); 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<ApplicationInfo> apps;
try {
ParceledListSlice<ApplicationInfo> 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) { void setAppIdle(String packageName, boolean idle, int userId) {
if (packageName == null) return; if (packageName == null) return;
@ -1283,6 +1354,11 @@ public class UsageStatsService extends SystemService implements
return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1); return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
} }
@Override
public int[] getIdleUidsForUser(int userId) {
return UsageStatsService.this.getIdleUidsForUser(userId);
}
@Override @Override
public boolean isAppIdleParoleOn() { public boolean isAppIdleParoleOn() {
return mAppIdleParoled; return mAppIdleParoled;