* commit 'b5148fd6099ae0d6a1979dc98a3ff6ac96558b1e': system_server: optimize app idle parole state change
This commit is contained in:
@@ -76,6 +76,12 @@ public abstract class UsageStatsManagerInternal {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean isAppIdle(String packageName, int userId);
|
public abstract boolean isAppIdle(String packageName, 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.
|
||||||
|
*/
|
||||||
|
public abstract boolean isAppIdleParoleOn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up a listener for changes to packages being accessed.
|
* Sets up a listener for changes to packages being accessed.
|
||||||
* @param listener A listener within the system process.
|
* @param listener A listener within the system process.
|
||||||
@@ -90,8 +96,9 @@ public abstract class UsageStatsManagerInternal {
|
|||||||
public abstract void removeAppIdleStateChangeListener(
|
public abstract void removeAppIdleStateChangeListener(
|
||||||
AppIdleStateChangeListener listener);
|
AppIdleStateChangeListener listener);
|
||||||
|
|
||||||
public interface AppIdleStateChangeListener {
|
public static abstract class AppIdleStateChangeListener {
|
||||||
void onAppIdleStateChanged(String packageName, int userId, boolean idle);
|
public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle);
|
||||||
|
public abstract void onParoleStateChanged(boolean isParoleOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,9 +214,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
*/
|
*/
|
||||||
@GuardedBy("mQuotaLock")
|
@GuardedBy("mQuotaLock")
|
||||||
private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
|
private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
|
||||||
|
/** Set of states for the child firewall chains. True if the chain is active. */
|
||||||
private boolean mStandbyChainEnabled = false;
|
@GuardedBy("mQuotaLock")
|
||||||
private boolean mDozableChainEnabled = false;
|
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
|
||||||
|
|
||||||
private Object mIdleTimerLock = new Object();
|
private Object mIdleTimerLock = new Object();
|
||||||
/** Set of interfaces with active idle timers. */
|
/** Set of interfaces with active idle timers. */
|
||||||
@@ -307,9 +307,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void systemReady() {
|
public void systemReady() {
|
||||||
// init firewall states
|
|
||||||
mDozableChainEnabled = false;
|
|
||||||
mStandbyChainEnabled = true;
|
|
||||||
prepareNativeDaemon();
|
prepareNativeDaemon();
|
||||||
if (DBG) Slog.d(TAG, "Prepared");
|
if (DBG) Slog.d(TAG, "Prepared");
|
||||||
}
|
}
|
||||||
@@ -611,7 +608,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
uidFirewallRules.valueAt(i));
|
uidFirewallRules.valueAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mStandbyChainEnabled) {
|
if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) {
|
||||||
setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
|
setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -625,7 +622,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
uidFirewallRules.valueAt(i));
|
uidFirewallRules.valueAt(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mDozableChainEnabled) {
|
if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
|
||||||
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
|
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2013,24 +2010,31 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
@Override
|
@Override
|
||||||
public void setFirewallChainEnabled(int chain, boolean enable) {
|
public void setFirewallChainEnabled(int chain, boolean enable) {
|
||||||
enforceSystemUid();
|
enforceSystemUid();
|
||||||
final String operation = enable ? "enable_chain" : "disable_chain";
|
synchronized (mQuotaLock) {
|
||||||
try {
|
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
|
||||||
String chainName;
|
mFirewallChainStates.get(chain) == enable) {
|
||||||
switch(chain) {
|
// All is the same, nothing to do.
|
||||||
case FIREWALL_CHAIN_STANDBY:
|
return;
|
||||||
chainName = FIREWALL_CHAIN_NAME_STANDBY;
|
}
|
||||||
mStandbyChainEnabled = enable;
|
mFirewallChainStates.put(chain, enable);
|
||||||
break;
|
|
||||||
case FIREWALL_CHAIN_DOZABLE:
|
final String operation = enable ? "enable_chain" : "disable_chain";
|
||||||
chainName = FIREWALL_CHAIN_NAME_DOZABLE;
|
try {
|
||||||
mDozableChainEnabled = enable;
|
String chainName;
|
||||||
break;
|
switch(chain) {
|
||||||
default:
|
case FIREWALL_CHAIN_STANDBY:
|
||||||
throw new IllegalArgumentException("Bad child chain: " + chain);
|
chainName = FIREWALL_CHAIN_NAME_STANDBY;
|
||||||
|
break;
|
||||||
|
case FIREWALL_CHAIN_DOZABLE:
|
||||||
|
chainName = FIREWALL_CHAIN_NAME_DOZABLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Bad child chain: " + chain);
|
||||||
|
}
|
||||||
|
mConnector.execute("firewall", operation, chainName);
|
||||||
|
} catch (NativeDaemonConnectorException e) {
|
||||||
|
throw e.rethrowAsParcelableException();
|
||||||
}
|
}
|
||||||
mConnector.execute("firewall", operation, chainName);
|
|
||||||
} catch (NativeDaemonConnectorException e) {
|
|
||||||
throw e.rethrowAsParcelableException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2048,27 +2052,29 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
@Override
|
@Override
|
||||||
public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
|
public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
|
||||||
enforceSystemUid();
|
enforceSystemUid();
|
||||||
SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
|
synchronized (mQuotaLock) {
|
||||||
SparseIntArray newRules = new SparseIntArray();
|
SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
|
||||||
// apply new set of rules
|
SparseIntArray newRules = new SparseIntArray();
|
||||||
for (int index = uids.length - 1; index >= 0; --index) {
|
// apply new set of rules
|
||||||
int uid = uids[index];
|
for (int index = uids.length - 1; index >= 0; --index) {
|
||||||
int rule = rules[index];
|
int uid = uids[index];
|
||||||
setFirewallUidRule(chain, uid, rule);
|
int rule = rules[index];
|
||||||
newRules.put(uid, rule);
|
setFirewallUidRule(chain, uid, rule);
|
||||||
}
|
newRules.put(uid, rule);
|
||||||
// collect the rules to remove.
|
}
|
||||||
SparseIntArray rulesToRemove = new SparseIntArray();
|
// collect the rules to remove.
|
||||||
for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
|
SparseIntArray rulesToRemove = new SparseIntArray();
|
||||||
int uid = uidFirewallRules.keyAt(index);
|
for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
|
||||||
if (newRules.indexOfKey(uid) < 0) {
|
int uid = uidFirewallRules.keyAt(index);
|
||||||
rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
|
if (newRules.indexOfKey(uid) < 0) {
|
||||||
|
rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// remove dead rules
|
||||||
|
for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
|
||||||
|
int uid = rulesToRemove.keyAt(index);
|
||||||
|
setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// remove dead rules
|
|
||||||
for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
|
|
||||||
int uid = rulesToRemove.keyAt(index);
|
|
||||||
setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2094,34 +2100,43 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String ruleName;
|
String ruleName = getFirewallRuleName(chain, rule);
|
||||||
if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
|
String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
|
||||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
|
|
||||||
ruleName = "allow";
|
|
||||||
} else {
|
|
||||||
ruleName = "deny";
|
|
||||||
}
|
|
||||||
} else { // Blacklist mode
|
|
||||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
|
|
||||||
ruleName = "deny";
|
|
||||||
} else {
|
|
||||||
ruleName = "allow";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
|
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
|
||||||
uidFirewallRules.delete(uid);
|
uidFirewallRules.delete(uid);
|
||||||
} else {
|
} else {
|
||||||
uidFirewallRules.put(uid, rule);
|
uidFirewallRules.put(uid, rule);
|
||||||
}
|
}
|
||||||
mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
|
|
||||||
ruleName);
|
if (!ruleName.equals(oldRuleName)) {
|
||||||
|
mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
|
||||||
|
ruleName);
|
||||||
|
}
|
||||||
} catch (NativeDaemonConnectorException e) {
|
} catch (NativeDaemonConnectorException e) {
|
||||||
throw e.rethrowAsParcelableException();
|
throw e.rethrowAsParcelableException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @NonNull String getFirewallRuleName(int chain, int rule) {
|
||||||
|
String ruleName;
|
||||||
|
if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
|
||||||
|
if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
|
||||||
|
ruleName = "allow";
|
||||||
|
} else {
|
||||||
|
ruleName = "deny";
|
||||||
|
}
|
||||||
|
} else { // Blacklist mode
|
||||||
|
if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
|
||||||
|
ruleName = "deny";
|
||||||
|
} else {
|
||||||
|
ruleName = "allow";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ruleName;
|
||||||
|
}
|
||||||
|
|
||||||
private @NonNull SparseIntArray getUidFirewallRules(int chain) {
|
private @NonNull SparseIntArray getUidFirewallRules(int chain) {
|
||||||
switch (chain) {
|
switch (chain) {
|
||||||
case FIREWALL_CHAIN_STANDBY:
|
case FIREWALL_CHAIN_STANDBY:
|
||||||
@@ -2272,7 +2287,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
pw.println("]");
|
pw.println("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.println("UID firewall standby chain enabled: " + mStandbyChainEnabled);
|
pw.println("UID firewall standby chain enabled: " +
|
||||||
|
mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
|
||||||
synchronized (mUidFirewallStandbyRules) {
|
synchronized (mUidFirewallStandbyRules) {
|
||||||
pw.print("UID firewall standby rule: [");
|
pw.print("UID firewall standby rule: [");
|
||||||
final int size = mUidFirewallStandbyRules.size();
|
final int size = mUidFirewallStandbyRules.size();
|
||||||
@@ -2285,7 +2301,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
|
|||||||
pw.println("]");
|
pw.println("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.println("UID firewall dozable chain enabled: " + mDozableChainEnabled);
|
pw.println("UID firewall dozable chain enabled: " +
|
||||||
|
mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
|
||||||
synchronized (mUidFirewallDozableRules) {
|
synchronized (mUidFirewallDozableRules) {
|
||||||
pw.print("UID firewall dozable rule: [");
|
pw.print("UID firewall dozable rule: [");
|
||||||
final int size = mUidFirewallDozableRules.size();
|
final int size = mUidFirewallDozableRules.size();
|
||||||
|
|||||||
@@ -18,11 +18,6 @@ package com.android.server.content;
|
|||||||
|
|
||||||
import android.app.usage.UsageStatsManagerInternal;
|
import android.app.usage.UsageStatsManagerInternal;
|
||||||
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
|
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.BatteryManager;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
@@ -31,53 +26,32 @@ import com.android.server.LocalServices;
|
|||||||
* Helper to listen for app idle and charging status changes and restart backed off
|
* Helper to listen for app idle and charging status changes and restart backed off
|
||||||
* sync operations.
|
* sync operations.
|
||||||
*/
|
*/
|
||||||
class AppIdleMonitor implements AppIdleStateChangeListener {
|
class AppIdleMonitor extends AppIdleStateChangeListener {
|
||||||
|
|
||||||
private final SyncManager mSyncManager;
|
private final SyncManager mSyncManager;
|
||||||
private final UsageStatsManagerInternal mUsageStats;
|
private final UsageStatsManagerInternal mUsageStats;
|
||||||
final BatteryManager mBatteryManager;
|
private boolean mAppIdleParoleOn;
|
||||||
/** Is the device currently plugged into power. */
|
|
||||||
private boolean mPluggedIn;
|
|
||||||
|
|
||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
AppIdleMonitor(SyncManager syncManager) {
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
onPluggedIn(mBatteryManager.isCharging());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AppIdleMonitor(SyncManager syncManager, Context context) {
|
|
||||||
mSyncManager = syncManager;
|
mSyncManager = syncManager;
|
||||||
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||||
|
mAppIdleParoleOn = mUsageStats.isAppIdleParoleOn();
|
||||||
|
|
||||||
mUsageStats.addAppIdleStateChangeListener(this);
|
mUsageStats.addAppIdleStateChangeListener(this);
|
||||||
mBatteryManager = context.getSystemService(BatteryManager.class);
|
|
||||||
mPluggedIn = isPowered();
|
|
||||||
registerReceivers(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerReceivers(Context context) {
|
void setAppIdleParoleOn(boolean appIdleParoleOn) {
|
||||||
// Monitor battery charging state
|
if (mAppIdleParoleOn == appIdleParoleOn) {
|
||||||
IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
|
|
||||||
filter.addAction(BatteryManager.ACTION_DISCHARGING);
|
|
||||||
context.registerReceiver(mReceiver, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPowered() {
|
|
||||||
return mBatteryManager.isCharging();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPluggedIn(boolean pluggedIn) {
|
|
||||||
if (mPluggedIn == pluggedIn) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mPluggedIn = pluggedIn;
|
mAppIdleParoleOn = appIdleParoleOn;
|
||||||
if (mPluggedIn) {
|
if (mAppIdleParoleOn) {
|
||||||
mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL);
|
mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isAppIdle(String packageName, int userId) {
|
boolean isAppIdle(String packageName, int userId) {
|
||||||
return !mPluggedIn && mUsageStats.isAppIdle(packageName, userId);
|
return !mAppIdleParoleOn && mUsageStats.isAppIdle(packageName, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,4 +60,9 @@ class AppIdleMonitor implements AppIdleStateChangeListener {
|
|||||||
if (idle) return;
|
if (idle) return;
|
||||||
mSyncManager.onAppNotIdle(packageName, userId);
|
mSyncManager.onAppNotIdle(packageName, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParoleStateChanged(boolean isParoleOn) {
|
||||||
|
setAppIdleParoleOn(isParoleOn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package com.android.server.content;
|
|||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountAndUser;
|
import android.accounts.AccountAndUser;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.AppGlobals;
|
import android.app.AppGlobals;
|
||||||
@@ -461,7 +462,7 @@ public class SyncManager {
|
|||||||
mSyncAlarmIntent = PendingIntent.getBroadcast(
|
mSyncAlarmIntent = PendingIntent.getBroadcast(
|
||||||
mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
|
mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
|
||||||
|
|
||||||
mAppIdleMonitor = new AppIdleMonitor(this, mContext);
|
mAppIdleMonitor = new AppIdleMonitor(this);
|
||||||
|
|
||||||
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
|
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
|
||||||
@@ -1271,7 +1272,7 @@ public class SyncManager {
|
|||||||
* @param userId The user for which the package has become active. Can be USER_ALL if
|
* @param userId The user for which the package has become active. Can be USER_ALL if
|
||||||
* the device just plugged in.
|
* the device just plugged in.
|
||||||
*/
|
*/
|
||||||
void onAppNotIdle(String packageName, int userId) {
|
void onAppNotIdle(@Nullable String packageName, int userId) {
|
||||||
synchronized (mSyncQueue) {
|
synchronized (mSyncQueue) {
|
||||||
// For all sync operations in sync queue, if marked as idle, compare with package name
|
// For all sync operations in sync queue, if marked as idle, compare with package name
|
||||||
// and unmark. And clear backoff for the operation.
|
// and unmark. And clear backoff for the operation.
|
||||||
|
|||||||
@@ -17,12 +17,7 @@
|
|||||||
package com.android.server.job.controllers;
|
package com.android.server.job.controllers;
|
||||||
|
|
||||||
import android.app.usage.UsageStatsManagerInternal;
|
import android.app.usage.UsageStatsManagerInternal;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.os.BatteryManager;
|
|
||||||
import android.os.BatteryManagerInternal;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
@@ -38,8 +33,7 @@ import java.util.ArrayList;
|
|||||||
* for a certain amount of time (maybe hours or days) are considered idle. When the app comes
|
* for a certain amount of time (maybe hours or days) are considered idle. When the app comes
|
||||||
* out of idle state, it will be allowed to run scheduled jobs.
|
* out of idle state, it will be allowed to run scheduled jobs.
|
||||||
*/
|
*/
|
||||||
public class AppIdleController extends StateController
|
public class AppIdleController extends StateController {
|
||||||
implements UsageStatsManagerInternal.AppIdleStateChangeListener {
|
|
||||||
|
|
||||||
private static final String LOG_TAG = "AppIdleController";
|
private static final String LOG_TAG = "AppIdleController";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
@@ -49,14 +43,7 @@ public class AppIdleController extends StateController
|
|||||||
private static volatile AppIdleController sController;
|
private static volatile AppIdleController sController;
|
||||||
final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
|
final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
|
||||||
private final UsageStatsManagerInternal mUsageStatsInternal;
|
private final UsageStatsManagerInternal mUsageStatsInternal;
|
||||||
private final BatteryManager mBatteryManager;
|
boolean mAppIdleParoleOn;
|
||||||
private boolean mPluggedIn;
|
|
||||||
|
|
||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
|
||||||
@Override public void onReceive(Context context, Intent intent) {
|
|
||||||
onPluggedIn(mBatteryManager.isCharging());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static AppIdleController get(JobSchedulerService service) {
|
public static AppIdleController get(JobSchedulerService service) {
|
||||||
synchronized (sCreationLock) {
|
synchronized (sCreationLock) {
|
||||||
@@ -70,17 +57,8 @@ public class AppIdleController extends StateController
|
|||||||
private AppIdleController(StateChangedListener stateChangedListener, Context context) {
|
private AppIdleController(StateChangedListener stateChangedListener, Context context) {
|
||||||
super(stateChangedListener, context);
|
super(stateChangedListener, context);
|
||||||
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
|
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||||
mBatteryManager = context.getSystemService(BatteryManager.class);
|
mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
|
||||||
mPluggedIn = mBatteryManager.isCharging();
|
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
|
||||||
mUsageStatsInternal.addAppIdleStateChangeListener(this);
|
|
||||||
registerReceivers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerReceivers() {
|
|
||||||
// Monitor battery charging state
|
|
||||||
IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
|
|
||||||
filter.addAction(BatteryManager.ACTION_DISCHARGING);
|
|
||||||
mContext.registerReceiver(mReceiver, filter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -88,7 +66,7 @@ public class AppIdleController extends StateController
|
|||||||
synchronized (mTrackedTasks) {
|
synchronized (mTrackedTasks) {
|
||||||
mTrackedTasks.add(jobStatus);
|
mTrackedTasks.add(jobStatus);
|
||||||
String packageName = jobStatus.job.getService().getPackageName();
|
String packageName = jobStatus.job.getService().getPackageName();
|
||||||
final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
|
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
|
||||||
jobStatus.getUserId());
|
jobStatus.getUserId());
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
|
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
|
||||||
@@ -108,7 +86,7 @@ public class AppIdleController extends StateController
|
|||||||
@Override
|
@Override
|
||||||
public void dumpControllerState(PrintWriter pw) {
|
public void dumpControllerState(PrintWriter pw) {
|
||||||
pw.println("AppIdle");
|
pw.println("AppIdle");
|
||||||
pw.println("Plugged In: " + mPluggedIn);
|
pw.println("Parole On: " + mAppIdleParoleOn);
|
||||||
synchronized (mTrackedTasks) {
|
synchronized (mTrackedTasks) {
|
||||||
for (JobStatus task : mTrackedTasks) {
|
for (JobStatus task : mTrackedTasks) {
|
||||||
pw.print(task.job.getService().getPackageName());
|
pw.print(task.job.getService().getPackageName());
|
||||||
@@ -119,48 +97,20 @@ public class AppIdleController extends StateController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
|
||||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
|
|
||||||
boolean changed = false;
|
|
||||||
synchronized (mTrackedTasks) {
|
|
||||||
// If currently plugged in, we don't care about app idle state
|
|
||||||
if (mPluggedIn) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (JobStatus task : mTrackedTasks) {
|
|
||||||
if (task.job.getService().getPackageName().equals(packageName)
|
|
||||||
&& task.getUserId() == userId) {
|
|
||||||
if (task.appNotIdleConstraintSatisfied.get() != !idle) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
|
|
||||||
+ packageName + " to " + idle);
|
|
||||||
}
|
|
||||||
task.appNotIdleConstraintSatisfied.set(!idle);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
mStateChangedListener.onControllerStateChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPluggedIn(boolean pluggedIn) {
|
|
||||||
// Flag if any app's idle state has changed
|
// Flag if any app's idle state has changed
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
synchronized (mTrackedTasks) {
|
synchronized (mTrackedTasks) {
|
||||||
if (mPluggedIn == pluggedIn) {
|
if (mAppIdleParoleOn == isAppIdleParoleOn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mPluggedIn = pluggedIn;
|
mAppIdleParoleOn = isAppIdleParoleOn;
|
||||||
for (JobStatus task : mTrackedTasks) {
|
for (JobStatus task : mTrackedTasks) {
|
||||||
String packageName = task.job.getService().getPackageName();
|
String packageName = task.job.getService().getPackageName();
|
||||||
final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
|
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
|
||||||
task.getUserId());
|
task.getUserId());
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(LOG_TAG, "Plugged in " + pluggedIn + ", setting idle state of "
|
Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
|
||||||
+ packageName + " to " + appIdle);
|
|
||||||
}
|
}
|
||||||
if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
|
if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
|
||||||
task.appNotIdleConstraintSatisfied.set(!appIdle);
|
task.appNotIdleConstraintSatisfied.set(!appIdle);
|
||||||
@@ -172,4 +122,41 @@ public class AppIdleController extends StateController
|
|||||||
mStateChangedListener.onControllerStateChanged();
|
mStateChangedListener.onControllerStateChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class AppIdleStateChangeListener
|
||||||
|
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
|
||||||
|
@Override
|
||||||
|
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
|
||||||
|
boolean changed = false;
|
||||||
|
synchronized (mTrackedTasks) {
|
||||||
|
if (mAppIdleParoleOn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (JobStatus task : mTrackedTasks) {
|
||||||
|
if (task.job.getService().getPackageName().equals(packageName)
|
||||||
|
&& task.getUserId() == userId) {
|
||||||
|
if (task.appNotIdleConstraintSatisfied.get() != !idle) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
|
||||||
|
+ packageName + " to " + idle);
|
||||||
|
}
|
||||||
|
task.appNotIdleConstraintSatisfied.set(!idle);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
mStateChangedListener.onControllerStateChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParoleStateChanged(boolean isParoleOn) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Slog.d(LOG_TAG, "Parole on: " + isParoleOn);
|
||||||
|
}
|
||||||
|
setAppIdleParoleOn(isParoleOn);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ import android.app.IUidObserver;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.usage.UsageStatsManagerInternal;
|
import android.app.usage.UsageStatsManagerInternal;
|
||||||
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -154,7 +153,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.internal.util.FastXmlSerializer;
|
import com.android.internal.util.FastXmlSerializer;
|
||||||
import com.android.internal.util.IndentingPrintWriter;
|
import com.android.internal.util.IndentingPrintWriter;
|
||||||
import com.android.server.DeviceIdleController;
|
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
import com.google.android.collect.Lists;
|
import com.google.android.collect.Lists;
|
||||||
|
|
||||||
@@ -182,8 +180,7 @@ import java.util.List;
|
|||||||
* and delivers to listeners, such as {@link ConnectivityManager}, for
|
* and delivers to listeners, such as {@link ConnectivityManager}, for
|
||||||
* enforcement.
|
* enforcement.
|
||||||
*/
|
*/
|
||||||
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||||
implements AppIdleStateChangeListener {
|
|
||||||
private static final String TAG = "NetworkPolicy";
|
private static final String TAG = "NetworkPolicy";
|
||||||
private static final boolean LOGD = false;
|
private static final boolean LOGD = false;
|
||||||
private static final boolean LOGV = false;
|
private static final boolean LOGV = false;
|
||||||
@@ -279,6 +276,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
|||||||
final SparseIntArray mUidPolicy = new SparseIntArray();
|
final SparseIntArray mUidPolicy = new SparseIntArray();
|
||||||
/** Currently derived rules for each UID. */
|
/** Currently derived rules for each UID. */
|
||||||
final SparseIntArray mUidRules = new SparseIntArray();
|
final SparseIntArray mUidRules = new SparseIntArray();
|
||||||
|
/** Set of states for the child firewall chains. True if the chain is active. */
|
||||||
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
|
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -508,7 +506,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
|||||||
WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||||
mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
|
mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
|
||||||
|
|
||||||
mUsageStats.addAppIdleStateChangeListener(this);
|
mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2043,7 +2041,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
|||||||
}
|
}
|
||||||
setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
|
setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
|
||||||
}
|
}
|
||||||
enableFirewallChain(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
|
enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateRulesForAppIdleParoleLocked() {
|
||||||
|
boolean enableChain = !mUsageStats.isAppIdleParoleOn();
|
||||||
|
enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2187,9 +2190,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
|||||||
final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
|
final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
|
||||||
if (oldFirewallReject != firewallReject) {
|
if (oldFirewallReject != firewallReject) {
|
||||||
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject);
|
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject);
|
||||||
if (mDeviceIdleMode && !firewallReject) {
|
if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE) && !firewallReject) {
|
||||||
// if we are in device idle mode, and we decide to allow this uid. we need to punch
|
// if the dozable chain is on, and we decide to allow this uid. we need to punch
|
||||||
// a hole in the device idle chain.
|
// a hole in the dozable chain.
|
||||||
setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, false);
|
setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2207,15 +2210,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private class AppIdleStateChangeListener
|
||||||
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
|
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
|
||||||
try {
|
|
||||||
int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
|
@Override
|
||||||
synchronized (mRulesLock) {
|
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
|
||||||
updateRulesForUidLocked(uid);
|
try {
|
||||||
|
int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
|
||||||
|
synchronized (mRulesLock) {
|
||||||
|
updateRulesForUidLocked(uid);
|
||||||
|
}
|
||||||
|
} catch (NameNotFoundException nnfe) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParoleStateChanged(boolean isParoleOn) {
|
||||||
|
synchronized (mRulesLock) {
|
||||||
|
updateRulesForAppIdleParoleLocked();
|
||||||
}
|
}
|
||||||
} catch (NameNotFoundException nnfe) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2381,12 +2394,13 @@ 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 enableFirewallChain(int chain, boolean enable) {
|
private void enableFirewallChainLocked(int chain, boolean enable) {
|
||||||
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
|
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
|
||||||
mFirewallChainStates.get(chain) == enable) {
|
mFirewallChainStates.get(chain) == enable) {
|
||||||
// All is the same, nothing to do.
|
// All is the same, nothing to do.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mFirewallChainStates.put(chain, enable);
|
||||||
try {
|
try {
|
||||||
mNetworkManager.setFirewallChainEnabled(chain, enable);
|
mNetworkManager.setFirewallChainEnabled(chain, enable);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ public class UsageStatsService extends SystemService implements
|
|||||||
static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
|
static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
|
||||||
static final int MSG_PAROLE_END_TIMEOUT = 7;
|
static final int MSG_PAROLE_END_TIMEOUT = 7;
|
||||||
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
|
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
|
||||||
|
static final int MSG_PAROLE_STATE_CHANGED = 9;
|
||||||
|
|
||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
Handler mHandler;
|
Handler mHandler;
|
||||||
@@ -313,7 +314,7 @@ public class UsageStatsService extends SystemService implements
|
|||||||
mLastAppIdleParoledTime = checkAndGetTimeLocked();
|
mLastAppIdleParoledTime = checkAndGetTimeLocked();
|
||||||
postNextParoleTimeout();
|
postNextParoleTimeout();
|
||||||
}
|
}
|
||||||
postCheckIdleStates(UserHandle.USER_ALL);
|
postParoleStateChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,6 +339,12 @@ public class UsageStatsService extends SystemService implements
|
|||||||
mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
|
mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void postParoleStateChanged() {
|
||||||
|
if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
|
||||||
|
mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
|
||||||
|
mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
void postCheckIdleStates(int userId) {
|
void postCheckIdleStates(int userId) {
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
|
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
|
||||||
}
|
}
|
||||||
@@ -756,6 +763,13 @@ public class UsageStatsService extends SystemService implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isAppIdleFilteredOrParoled(String packageName, int userId, long timeNow) {
|
||||||
|
if (mAppIdleParoled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isAppIdleFiltered(packageName, userId, timeNow);
|
||||||
|
}
|
||||||
|
|
||||||
boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
|
boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
|
||||||
final UserUsageStatsService userService;
|
final UserUsageStatsService userService;
|
||||||
final long screenOnTime;
|
final long screenOnTime;
|
||||||
@@ -782,13 +796,6 @@ public class UsageStatsService extends SystemService implements
|
|||||||
if (!mAppIdleEnabled) {
|
if (!mAppIdleEnabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
synchronized (mLock) {
|
|
||||||
// Temporary exemption, probably due to device charging or occasional allowance to
|
|
||||||
// be allowed to sync, etc.
|
|
||||||
if (mAppIdleParoled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (packageName.equals("android")) return false;
|
if (packageName.equals("android")) return false;
|
||||||
try {
|
try {
|
||||||
if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) {
|
if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) {
|
||||||
@@ -846,6 +853,12 @@ public class UsageStatsService extends SystemService implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void informParoleStateChanged() {
|
||||||
|
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
|
||||||
|
listener.onParoleStateChanged(mAppIdleParoled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean validRange(long currentTime, long beginTime, long endTime) {
|
private static boolean validRange(long currentTime, long beginTime, long endTime) {
|
||||||
return beginTime <= currentTime && beginTime < endTime;
|
return beginTime <= currentTime && beginTime < endTime;
|
||||||
}
|
}
|
||||||
@@ -975,6 +988,11 @@ public class UsageStatsService extends SystemService implements
|
|||||||
args.recycle();
|
args.recycle();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSG_PAROLE_STATE_CHANGED:
|
||||||
|
if (DEBUG) Slog.d(TAG, "Parole state changed: " + mAppIdleParoled);
|
||||||
|
informParoleStateChanged();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
super.handleMessage(msg);
|
super.handleMessage(msg);
|
||||||
break;
|
break;
|
||||||
@@ -1126,7 +1144,7 @@ public class UsageStatsService extends SystemService implements
|
|||||||
}
|
}
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
|
return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId, -1);
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
@@ -1250,6 +1268,11 @@ public class UsageStatsService extends SystemService implements
|
|||||||
return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
|
return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAppIdleParoleOn() {
|
||||||
|
return mAppIdleParoled;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareShutdown() {
|
public void prepareShutdown() {
|
||||||
// This method *WILL* do IO work, but we must block until it is finished or else
|
// This method *WILL* do IO work, but we must block until it is finished or else
|
||||||
@@ -1261,6 +1284,7 @@ public class UsageStatsService extends SystemService implements
|
|||||||
@Override
|
@Override
|
||||||
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
|
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
|
||||||
UsageStatsService.this.addListener(listener);
|
UsageStatsService.this.addListener(listener);
|
||||||
|
listener.onParoleStateChanged(isAppIdleParoleOn());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user