Merge "Temporarily whitelist an app for network during doze" into mnc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ff3b76d046
@@ -71,6 +71,7 @@ package android {
|
||||
field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
|
||||
field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
|
||||
field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
|
||||
field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
|
||||
field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
|
||||
field public static final java.lang.String CHANGE_WIFI_MULTICAST_STATE = "android.permission.CHANGE_WIFI_MULTICAST_STATE";
|
||||
field public static final java.lang.String CHANGE_WIFI_STATE = "android.permission.CHANGE_WIFI_STATE";
|
||||
@@ -6332,6 +6333,7 @@ package android.app.usage {
|
||||
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
|
||||
method public android.app.usage.UsageEvents queryEvents(long, long);
|
||||
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
|
||||
method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
|
||||
field public static final int INTERVAL_BEST = 4; // 0x4
|
||||
field public static final int INTERVAL_DAILY = 0; // 0x0
|
||||
field public static final int INTERVAL_MONTHLY = 2; // 0x2
|
||||
|
||||
@@ -32,4 +32,5 @@ interface IUsageStatsManager {
|
||||
UsageEvents queryEvents(long beginTime, long endTime, String callingPackage);
|
||||
void setAppInactive(String packageName, boolean inactive, int userId);
|
||||
boolean isAppInactive(String packageName, int userId);
|
||||
void whitelistAppTemporarily(String packageName, long duration, int userId);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.app.usage;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.RemoteException;
|
||||
@@ -245,4 +246,25 @@ public final class UsageStatsManager {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
* Temporarily whitelist the specified app for a short duration. This is to allow an app
|
||||
* receiving a high priority message to be able to access the network and acquire wakelocks
|
||||
* even if the device is in power-save mode or the app is currently considered inactive.
|
||||
* The caller must hold the CHANGE_DEVICE_IDLE_TEMP_WHITELIST permission.
|
||||
* @param packageName The package name of the app to whitelist.
|
||||
* @param duration Duration to whitelist the app for, in milliseconds. It is recommended that
|
||||
* this be limited to 10s of seconds. Requested duration will be clamped to a few minutes.
|
||||
* @param user The user for whom the package should be whitelisted. Passing in a user that is
|
||||
* not the same as the caller's process will require the INTERACT_ACROSS_USERS permission.
|
||||
* @see #isAppInactive(String)
|
||||
*/
|
||||
@SystemApi
|
||||
public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) {
|
||||
try {
|
||||
mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
|
||||
} catch (RemoteException re) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.os;
|
||||
|
||||
import android.os.UserHandle;
|
||||
|
||||
/** @hide */
|
||||
interface IDeviceIdleController {
|
||||
void addPowerSaveWhitelistApp(String name);
|
||||
@@ -23,5 +25,7 @@ interface IDeviceIdleController {
|
||||
String[] getSystemPowerWhitelist();
|
||||
String[] getFullPowerWhitelist();
|
||||
int[] getAppIdWhitelist();
|
||||
int[] getAppIdTempWhitelist();
|
||||
boolean isPowerSaveWhitelistApp(String name);
|
||||
void addPowerSaveTempWhitelistApp(String name, long duration, int userId);
|
||||
}
|
||||
|
||||
@@ -927,6 +927,14 @@ public final class PowerManager {
|
||||
public static final String ACTION_POWER_SAVE_WHITELIST_CHANGED
|
||||
= "android.os.action.POWER_SAVE_WHITELIST_CHANGED";
|
||||
|
||||
/**
|
||||
* @hide Intent that is broadcast when the set of temporarily whitelisted apps has changed.
|
||||
* This broadcast is only sent to registered receivers.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED
|
||||
= "android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED";
|
||||
|
||||
/**
|
||||
* Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
|
||||
* This broadcast is only sent to registered receivers.
|
||||
|
||||
@@ -137,6 +137,8 @@ public abstract class PowerManagerInternal {
|
||||
|
||||
public abstract void setDeviceIdleWhitelist(int[] appids);
|
||||
|
||||
public abstract void setDeviceIdleTempWhitelist(int[] appids);
|
||||
|
||||
public abstract void updateUidProcState(int uid, int procState);
|
||||
|
||||
public abstract void uidGone(int uid);
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
|
||||
<protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
|
||||
<protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
|
||||
<protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
|
||||
|
||||
<protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
|
||||
|
||||
@@ -2136,6 +2137,12 @@
|
||||
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
|
||||
access the network and acquire wakelocks.
|
||||
<p>Not for use by third-party applications. -->
|
||||
<permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"
|
||||
android:protectionLevel="system|signature" />
|
||||
|
||||
<!-- @SystemApi Allows an application to collect battery statistics -->
|
||||
<permission android:name="android.permission.BATTERY_STATS"
|
||||
android:protectionLevel="signature|system|development" />
|
||||
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
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.PackageManager.NameNotFoundException;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.TriggerEvent;
|
||||
@@ -47,7 +52,9 @@ import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseLongArray;
|
||||
import android.util.TimeUtils;
|
||||
import android.util.Xml;
|
||||
import android.view.Display;
|
||||
@@ -55,6 +62,7 @@ import android.view.Display;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.os.AtomicFile;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.FastXmlSerializer;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.server.am.BatteryStatsService;
|
||||
@@ -72,6 +80,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Keeps track of device idleness and drives low power mode based on that.
|
||||
@@ -79,7 +88,8 @@ import java.nio.charset.StandardCharsets;
|
||||
public class DeviceIdleController extends SystemService {
|
||||
private static final String TAG = "DeviceIdleController";
|
||||
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean COMPRESS_TIME = false;
|
||||
|
||||
public static final String SERVICE_NAME = "deviceidle";
|
||||
|
||||
@@ -94,29 +104,31 @@ public class DeviceIdleController extends SystemService {
|
||||
* immediately after going inactive just because we don't want to be continually running
|
||||
* the significant motion sensor whenever the screen is off.
|
||||
*/
|
||||
private static final long DEFAULT_INACTIVE_TIMEOUT = !DEBUG ? 30*60*1000L
|
||||
: 2 * 60 * 1000L;
|
||||
private static final long DEFAULT_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
|
||||
: 3 * 60 * 1000L;
|
||||
/**
|
||||
* This is the time, after seeing motion, that we wait after becoming inactive from
|
||||
* that until we start looking for motion again.
|
||||
*/
|
||||
private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !DEBUG ? 10*60*1000L
|
||||
private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
|
||||
: 60 * 1000L;
|
||||
/**
|
||||
* This is the time, after the inactive timeout elapses, that we will wait looking
|
||||
* for significant motion until we truly consider the device to be idle.
|
||||
*/
|
||||
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = !DEBUG ? 30*60*1000L
|
||||
: 2 * 60 * 1000L;
|
||||
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
|
||||
: 3 * 60 * 1000L;
|
||||
/**
|
||||
* This is the initial time, after being idle, that we will allow ourself to be back
|
||||
* in the IDLE_PENDING state allowing the system to run normally until we return to idle.
|
||||
*/
|
||||
private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
|
||||
private static final long DEFAULT_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 5*60*1000L
|
||||
: 30 * 1000L;
|
||||
/**
|
||||
* Maximum pending idle timeout (time spent running) we will be allowed to use.
|
||||
*/
|
||||
private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
|
||||
private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
|
||||
: 60 * 1000L;
|
||||
/**
|
||||
* Scaling factor to apply to current pending idle timeout each time we cycle through
|
||||
* that state.
|
||||
@@ -126,13 +138,13 @@ public class DeviceIdleController extends SystemService {
|
||||
* This is the initial time that we want to sit in the idle state before waking up
|
||||
* again to return to pending idle and allowing normal work to run.
|
||||
*/
|
||||
private static final long DEFAULT_IDLE_TIMEOUT = !DEBUG ? 60*60*1000L
|
||||
: 5 * 60 * 1000L;
|
||||
private static final long DEFAULT_IDLE_TIMEOUT = !COMPRESS_TIME ? 60*60*1000L
|
||||
: 6 * 60 * 1000L;
|
||||
/**
|
||||
* Maximum idle duration we will be allowed to use.
|
||||
*/
|
||||
private static final long DEFAULT_MAX_IDLE_TIMEOUT = !DEBUG ? 6*60*60*1000L
|
||||
: 10 * 60 * 1000L;
|
||||
private static final long DEFAULT_MAX_IDLE_TIMEOUT = !COMPRESS_TIME ? 6*60*60*1000L
|
||||
: 30 * 60 * 1000L;
|
||||
/**
|
||||
* Scaling factor to apply to current idle timeout each time we cycle through that state.
|
||||
*/
|
||||
@@ -141,8 +153,13 @@ public class DeviceIdleController extends SystemService {
|
||||
* This is the minimum time we will allow until the next upcoming alarm for us to
|
||||
* actually go in to idle mode.
|
||||
*/
|
||||
private static final long DEFAULT_MIN_TIME_TO_ALARM = !DEBUG ? 60*60*1000L
|
||||
: 5 * 60 * 1000L;
|
||||
private static final long DEFAULT_MIN_TIME_TO_ALARM = !COMPRESS_TIME ? 60*60*1000L
|
||||
: 6 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* Max amount of time to temporarily whitelist an app when it receives a high priority tickle.
|
||||
*/
|
||||
private static final long MAX_TEMP_APP_WHITELIST_DURATION = 5 * 60 * 1000L;
|
||||
|
||||
private AlarmManager mAlarmManager;
|
||||
private IBatteryStats mBatteryStats;
|
||||
@@ -210,6 +227,17 @@ public class DeviceIdleController extends SystemService {
|
||||
*/
|
||||
private int[] mPowerSaveWhitelistAppIdArray = new int[0];
|
||||
|
||||
/**
|
||||
* List of end times for UIDs that are temporarily marked as being allowed to access
|
||||
* the network and acquire wakelocks. Times are in milliseconds.
|
||||
*/
|
||||
private SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray();
|
||||
|
||||
/**
|
||||
* Current app IDs of temporarily whitelist apps for high-priority messages.
|
||||
*/
|
||||
private int[] mTempWhitelistAppIdArray = new int[0];
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override public void onReceive(Context context, Intent intent) {
|
||||
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
|
||||
@@ -252,6 +280,7 @@ public class DeviceIdleController extends SystemService {
|
||||
static final int MSG_REPORT_IDLE_ON = 2;
|
||||
static final int MSG_REPORT_IDLE_OFF = 3;
|
||||
static final int MSG_REPORT_ACTIVE = 4;
|
||||
static final int MSG_TEMP_APP_WHITELIST_TIMEOUT = 5;
|
||||
|
||||
final class MyHandler extends Handler {
|
||||
MyHandler(Looper looper) {
|
||||
@@ -294,6 +323,10 @@ public class DeviceIdleController extends SystemService {
|
||||
getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
|
||||
}
|
||||
} break;
|
||||
case MSG_TEMP_APP_WHITELIST_TIMEOUT: {
|
||||
int uid = msg.arg1;
|
||||
checkTempAppWhitelistTimeout(uid);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,10 +358,39 @@ public class DeviceIdleController extends SystemService {
|
||||
return getAppIdWhitelistInternal();
|
||||
}
|
||||
|
||||
@Override public int[] getAppIdTempWhitelist() {
|
||||
return getAppIdTempWhitelistInternal();
|
||||
}
|
||||
|
||||
@Override public boolean isPowerSaveWhitelistApp(String name) {
|
||||
return isPowerSaveWhitelistAppInternal(name);
|
||||
}
|
||||
|
||||
@Override public void addPowerSaveTempWhitelistApp(String packageName, long duration,
|
||||
int userId) throws RemoteException {
|
||||
getContext().enforceCallingPermission(
|
||||
Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
|
||||
"No permission to change device idle whitelist");
|
||||
userId = ActivityManagerNative.getDefault().handleIncomingUser(
|
||||
Binder.getCallingPid(),
|
||||
Binder.getCallingUid(),
|
||||
userId,
|
||||
/*allowAll=*/ false,
|
||||
/*requireFull=*/ false,
|
||||
"addAppBrieflyToWhitelist", null);
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
PackageInfo pi = AppGlobals.getPackageManager()
|
||||
.getPackageInfo(packageName, 0, userId);
|
||||
if (pi == null) return;
|
||||
DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName,
|
||||
duration, userId);
|
||||
} catch (RemoteException re) {
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
DeviceIdleController.this.dump(fd, pw, args);
|
||||
}
|
||||
@@ -481,6 +543,70 @@ public class DeviceIdleController extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getAppIdTempWhitelistInternal() {
|
||||
synchronized (this) {
|
||||
return mTempWhitelistAppIdArray;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an app to the temporary whitelist and resets the endTime for granting the
|
||||
* app an exemption to access network and acquire wakelocks.
|
||||
*/
|
||||
public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration,
|
||||
int userId) {
|
||||
if (duration > MAX_TEMP_APP_WHITELIST_DURATION) {
|
||||
duration = MAX_TEMP_APP_WHITELIST_DURATION;
|
||||
}
|
||||
try {
|
||||
int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
|
||||
int appId = UserHandle.getAppId(uid);
|
||||
final long timeNow = System.currentTimeMillis();
|
||||
synchronized (this) {
|
||||
long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
|
||||
// Set the new end time
|
||||
mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
|
||||
}
|
||||
if (currentEndTime == 0) {
|
||||
// No pending timeout for the app id, post a delayed message
|
||||
postTempActiveTimeoutMessage(appId, duration);
|
||||
updateTempWhitelistAppIdsLocked();
|
||||
reportTempWhitelistChangedLocked();
|
||||
}
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private void postTempActiveTimeoutMessage(int uid, long delay) {
|
||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0),
|
||||
delay);
|
||||
}
|
||||
|
||||
void checkTempAppWhitelistTimeout(int uid) {
|
||||
final long timeNow = System.currentTimeMillis();
|
||||
synchronized (this) {
|
||||
long endTime = mTempWhitelistAppIdEndTimes.get(uid);
|
||||
if (endTime == 0) {
|
||||
// Nothing to do
|
||||
return;
|
||||
}
|
||||
if (timeNow >= endTime) {
|
||||
mTempWhitelistAppIdEndTimes.delete(uid);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
|
||||
}
|
||||
updateTempWhitelistAppIdsLocked();
|
||||
reportTempWhitelistChangedLocked();
|
||||
} else {
|
||||
// Need more time
|
||||
postTempActiveTimeoutMessage(uid, endTime - timeNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateDisplayLocked() {
|
||||
mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
|
||||
// We consider any situation where the display is showing something to be it on,
|
||||
@@ -659,14 +785,41 @@ public class DeviceIdleController extends SystemService {
|
||||
}
|
||||
mPowerSaveWhitelistAppIdArray = appids;
|
||||
if (mLocalPowerManager != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Setting wakelock whitelist to "
|
||||
+ Arrays.toString(mPowerSaveWhitelistAppIdArray));
|
||||
}
|
||||
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAppIdArray);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTempWhitelistAppIdsLocked() {
|
||||
final int size = mTempWhitelistAppIdEndTimes.size();
|
||||
if (mTempWhitelistAppIdArray.length != size) {
|
||||
mTempWhitelistAppIdArray = new int[size];
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
mTempWhitelistAppIdArray[i] = mTempWhitelistAppIdEndTimes.keyAt(i);
|
||||
}
|
||||
if (mLocalPowerManager != null) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Setting wakelock temp whitelist to "
|
||||
+ Arrays.toString(mTempWhitelistAppIdArray));
|
||||
}
|
||||
mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
|
||||
}
|
||||
}
|
||||
|
||||
private void reportPowerSaveWhitelistChangedLocked() {
|
||||
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
getContext().sendBroadcast(intent);
|
||||
getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
|
||||
}
|
||||
|
||||
private void reportTempWhitelistChangedLocked() {
|
||||
Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||
getContext().sendBroadcastAsUser(intent, UserHandle.OWNER);
|
||||
}
|
||||
|
||||
void readConfigFileLocked() {
|
||||
@@ -817,11 +970,18 @@ public class DeviceIdleController extends SystemService {
|
||||
}
|
||||
|
||||
if (args != null) {
|
||||
int userId = UserHandle.USER_OWNER;
|
||||
for (int i=0; i<args.length; i++) {
|
||||
String arg = args[i];
|
||||
if ("-h".equals(arg)) {
|
||||
dumpHelp(pw);
|
||||
return;
|
||||
} else if ("-u".equals(arg)) {
|
||||
i++;
|
||||
if (i < args.length) {
|
||||
arg = args[i];
|
||||
userId = Integer.parseInt(arg);
|
||||
}
|
||||
} else if ("-a".equals(arg)) {
|
||||
// Ignore, we always dump all.
|
||||
} else if ("step".equals(arg)) {
|
||||
@@ -873,6 +1033,17 @@ public class DeviceIdleController extends SystemService {
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if ("tempwhitelist".equals(arg)) {
|
||||
i++;
|
||||
if (i >= args.length) {
|
||||
pw.println("At least one package name must be specified");
|
||||
return;
|
||||
}
|
||||
while (i < args.length) {
|
||||
arg = args[i];
|
||||
i++;
|
||||
addPowerSaveTempWhitelistAppInternal(arg, 10000L, userId);
|
||||
}
|
||||
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
|
||||
pw.println("Unknown option: " + arg);
|
||||
return;
|
||||
|
||||
@@ -283,9 +283,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
/**
|
||||
* UIDs that have been white-listed to always be able to have network access
|
||||
* in power save mode.
|
||||
* TODO: An int array might be sufficient
|
||||
*/
|
||||
private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
|
||||
|
||||
private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();
|
||||
|
||||
/** Set of ifaces that are metered. */
|
||||
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
|
||||
/** Set of over-limit templates that have been notified. */
|
||||
@@ -371,6 +374,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void updatePowerSaveTempWhitelistLocked() {
|
||||
try {
|
||||
final int[] whitelist = mDeviceIdleController.getAppIdTempWhitelist();
|
||||
mPowerSaveTempWhitelistAppIds.clear();
|
||||
if (whitelist != null) {
|
||||
for (int uid : whitelist) {
|
||||
mPowerSaveTempWhitelistAppIds.put(uid, true);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void systemReady() {
|
||||
if (!isBandwidthControlEnabled()) {
|
||||
Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
|
||||
@@ -392,6 +408,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
if (mRestrictPower != enabled) {
|
||||
mRestrictPower = enabled;
|
||||
updateRulesForGlobalChangeLocked(true);
|
||||
updateRulesForTempWhitelistChangeLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,6 +421,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
|
||||
if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) {
|
||||
updateRulesForGlobalChangeLocked(true);
|
||||
updateRulesForTempWhitelistChangeLocked();
|
||||
updateNotificationsLocked();
|
||||
}
|
||||
}
|
||||
@@ -428,6 +446,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
// listen for changes to power save whitelist
|
||||
final IntentFilter whitelistFilter = new IntentFilter(
|
||||
PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
|
||||
whitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
|
||||
mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
|
||||
|
||||
// watch for network interfaces to be claimed
|
||||
@@ -496,8 +515,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
|
||||
synchronized (mRulesLock) {
|
||||
updatePowerSaveWhitelistLocked();
|
||||
updateRulesForGlobalChangeLocked(false);
|
||||
if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(intent.getAction())) {
|
||||
updatePowerSaveWhitelistLocked();
|
||||
updateRulesForGlobalChangeLocked(false);
|
||||
} else {
|
||||
updatePowerSaveTempWhitelistLocked();
|
||||
updateRulesForTempWhitelistChangeLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2019,6 +2043,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void updateRulesForTempWhitelistChangeLocked() {
|
||||
final List<UserInfo> users = mUserManager.getUsers();
|
||||
for (UserInfo user : users) {
|
||||
for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
|
||||
int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
|
||||
int uid = UserHandle.getUid(user.id, appId);
|
||||
updateRulesForUidLocked(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isUidValidForRules(int uid) {
|
||||
// allow rules on specific system services, and any apps
|
||||
if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
|
||||
@@ -2065,8 +2100,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
|
||||
// derive active rules based on policy and active state
|
||||
|
||||
int appId = UserHandle.getAppId(uid);
|
||||
int uidRules = RULE_ALLOW_ALL;
|
||||
if (uidIdle && !mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid))) {
|
||||
if (uidIdle && !mPowerSaveWhitelistAppIds.get(appId)
|
||||
&& !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
|
||||
@@ -2077,7 +2114,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
||||
uidRules = RULE_REJECT_METERED;
|
||||
}
|
||||
} else if (mRestrictPower || mDeviceIdleMode) {
|
||||
final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
|
||||
final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId)
|
||||
|| mPowerSaveTempWhitelistAppIds.get(appId);
|
||||
if (!whitelisted && !uidForeground
|
||||
&& (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
|
||||
// uid is in background, restrict power use mode is on (so we want to
|
||||
|
||||
@@ -438,6 +438,9 @@ public final class PowerManagerService extends SystemService
|
||||
// Set of app ids that we will always respect the wake locks for.
|
||||
int[] mDeviceIdleWhitelist = new int[0];
|
||||
|
||||
// Set of app ids that are temporarily allowed to acquire wakelocks due to high-pri message
|
||||
int[] mDeviceIdleTempWhitelist = new int[0];
|
||||
|
||||
private final SparseIntArray mUidState = new SparseIntArray();
|
||||
|
||||
// True if theater mode is enabled
|
||||
@@ -2320,6 +2323,15 @@ public final class PowerManagerService extends SystemService
|
||||
}
|
||||
}
|
||||
|
||||
void setDeviceIdleTempWhitelistInternal(int[] appids) {
|
||||
synchronized (mLock) {
|
||||
mDeviceIdleTempWhitelist = appids;
|
||||
if (mDeviceIdleMode) {
|
||||
updateWakeLockDisabledStatesLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateUidProcStateInternal(int uid, int procState) {
|
||||
synchronized (mLock) {
|
||||
mUidState.put(uid, procState);
|
||||
@@ -2372,6 +2384,7 @@ public final class PowerManagerService extends SystemService
|
||||
// for application uids that are not whitelisted.
|
||||
if (appid >= Process.FIRST_APPLICATION_UID &&
|
||||
Arrays.binarySearch(mDeviceIdleWhitelist, appid) < 0 &&
|
||||
Arrays.binarySearch(mDeviceIdleTempWhitelist, appid) < 0 &&
|
||||
mUidState.get(wakeLock.mOwnerUid,
|
||||
ActivityManager.PROCESS_STATE_CACHED_EMPTY)
|
||||
> ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
|
||||
@@ -2579,6 +2592,7 @@ public final class PowerManagerService extends SystemService
|
||||
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
|
||||
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
|
||||
pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
|
||||
pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
|
||||
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
|
||||
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
|
||||
pw.println(" mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
|
||||
@@ -3477,6 +3491,11 @@ public final class PowerManagerService extends SystemService
|
||||
setDeviceIdleWhitelistInternal(appids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeviceIdleTempWhitelist(int[] appids) {
|
||||
setDeviceIdleTempWhitelistInternal(appids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUidProcState(int uid, int procState) {
|
||||
updateUidProcStateInternal(uid, procState);
|
||||
|
||||
@@ -90,23 +90,24 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
static final String TAG = "UsageStatsService";
|
||||
|
||||
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
static final boolean DEBUG = false;
|
||||
private static final boolean COMPRESS_TIME = false;
|
||||
|
||||
private static final long TEN_SECONDS = 10 * 1000;
|
||||
private static final long ONE_MINUTE = 60 * 1000;
|
||||
private static final long TWENTY_MINUTES = 20 * 60 * 1000;
|
||||
private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
|
||||
private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
|
||||
private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
|
||||
|
||||
static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 4
|
||||
static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = COMPRESS_TIME ? ONE_MINUTE * 4
|
||||
: 12 * 60 * ONE_MINUTE; // 12 hours of screen-on time sans dream-time
|
||||
static final long DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 8
|
||||
static final long DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS = COMPRESS_TIME ? ONE_MINUTE * 8
|
||||
: 2L * 24 * 60 * ONE_MINUTE; // 2 days
|
||||
static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE
|
||||
static final long DEFAULT_CHECK_IDLE_INTERVAL = COMPRESS_TIME ? ONE_MINUTE
|
||||
: 8 * 60 * ONE_MINUTE; // 8 hours
|
||||
static final long DEFAULT_PAROLE_INTERVAL = DEBUG ? ONE_MINUTE * 10
|
||||
static final long DEFAULT_PAROLE_INTERVAL = COMPRESS_TIME ? ONE_MINUTE * 10
|
||||
: 24 * 60 * ONE_MINUTE; // 24 hours between paroles
|
||||
static final long DEFAULT_PAROLE_DURATION = DEBUG ? ONE_MINUTE
|
||||
static final long DEFAULT_PAROLE_DURATION = COMPRESS_TIME ? ONE_MINUTE
|
||||
: 10 * ONE_MINUTE; // 10 minutes
|
||||
|
||||
// Handler message types.
|
||||
@@ -338,7 +339,6 @@ public class UsageStatsService extends SystemService implements
|
||||
|
||||
/** Check all running users' apps to see if they enter an idle state. */
|
||||
void checkIdleStates() {
|
||||
if (DEBUG) Slog.d(TAG, "Checking idle state");
|
||||
final int[] runningUsers;
|
||||
try {
|
||||
runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
|
||||
@@ -993,6 +993,12 @@ public class UsageStatsService extends SystemService implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void whitelistAppTemporarily(String packageName, long duration, int userId)
|
||||
throws RemoteException {
|
||||
mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||
|
||||
Reference in New Issue
Block a user