summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorXiaohui Chen <xiaohuic@google.com>2015-06-19 12:44:59 -0700
committerXiaohui Chen <xiaohuic@google.com>2015-06-22 15:35:19 -0700
commit8dca36dc8a5d17315775ce216689addc5bd9be00 (patch)
tree020e812cedd03afe06a6c783465ec85356c26b86 /services
parent20fab81a09e1ca04e811c6c6d94acb08037739e7 (diff)
downloadframeworks_base-8dca36dc8a5d17315775ce216689addc5bd9be00.zip
frameworks_base-8dca36dc8a5d17315775ce216689addc5bd9be00.tar.gz
frameworks_base-8dca36dc8a5d17315775ce216689addc5bd9be00.tar.bz2
system_server: optimize app idle parole state change
Currently when app idle parole state changes, all idle apps' states are updated one by one including firewall modifications which are very expensive. This optimization gets rid of individual firewall rule changes and makes sure we only modify the firewall once at child chain level. BUG: 21446713 Change-Id: Iafc415fe0bc127826fe17894d4fedcf1755cb17d
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java143
-rw-r--r--services/core/java/com/android/server/content/AppIdleMonitor.java51
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java5
-rw-r--r--services/core/java/com/android/server/job/controllers/AppIdleController.java109
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java48
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java42
6 files changed, 210 insertions, 188 deletions
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index baa55e7..7afb192 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -214,9 +214,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
*/
@GuardedBy("mQuotaLock")
private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
-
- private boolean mStandbyChainEnabled = false;
- private boolean mDozableChainEnabled = false;
+ /** Set of states for the child firewall chains. True if the chain is active. */
+ @GuardedBy("mQuotaLock")
+ final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
private Object mIdleTimerLock = new Object();
/** Set of interfaces with active idle timers. */
@@ -307,9 +307,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
public void systemReady() {
- // init firewall states
- mDozableChainEnabled = false;
- mStandbyChainEnabled = true;
prepareNativeDaemon();
if (DBG) Slog.d(TAG, "Prepared");
}
@@ -611,7 +608,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
uidFirewallRules.valueAt(i));
}
}
- if (mStandbyChainEnabled) {
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) {
setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
}
@@ -625,7 +622,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
uidFirewallRules.valueAt(i));
}
}
- if (mDozableChainEnabled) {
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
}
}
@@ -2013,24 +2010,31 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void setFirewallChainEnabled(int chain, boolean enable) {
enforceSystemUid();
- final String operation = enable ? "enable_chain" : "disable_chain";
- try {
- String chainName;
- switch(chain) {
- case FIREWALL_CHAIN_STANDBY:
- chainName = FIREWALL_CHAIN_NAME_STANDBY;
- mStandbyChainEnabled = enable;
- break;
- case FIREWALL_CHAIN_DOZABLE:
- chainName = FIREWALL_CHAIN_NAME_DOZABLE;
- mDozableChainEnabled = enable;
- break;
- default:
- throw new IllegalArgumentException("Bad child chain: " + chain);
+ synchronized (mQuotaLock) {
+ if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
+ mFirewallChainStates.get(chain) == enable) {
+ // All is the same, nothing to do.
+ return;
+ }
+ mFirewallChainStates.put(chain, enable);
+
+ final String operation = enable ? "enable_chain" : "disable_chain";
+ try {
+ String chainName;
+ switch(chain) {
+ case FIREWALL_CHAIN_STANDBY:
+ 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
public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
enforceSystemUid();
- SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
- SparseIntArray newRules = new SparseIntArray();
- // apply new set of rules
- for (int index = uids.length - 1; index >= 0; --index) {
- int uid = uids[index];
- int rule = rules[index];
- setFirewallUidRule(chain, uid, rule);
- newRules.put(uid, rule);
- }
- // collect the rules to remove.
- SparseIntArray rulesToRemove = new SparseIntArray();
- for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
- int uid = uidFirewallRules.keyAt(index);
- if (newRules.indexOfKey(uid) < 0) {
- rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
+ synchronized (mQuotaLock) {
+ SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
+ SparseIntArray newRules = new SparseIntArray();
+ // apply new set of rules
+ for (int index = uids.length - 1; index >= 0; --index) {
+ int uid = uids[index];
+ int rule = rules[index];
+ setFirewallUidRule(chain, uid, rule);
+ newRules.put(uid, rule);
+ }
+ // collect the rules to remove.
+ SparseIntArray rulesToRemove = new SparseIntArray();
+ for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
+ int uid = uidFirewallRules.keyAt(index);
+ 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 {
- 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";
- }
- }
+ String ruleName = getFirewallRuleName(chain, rule);
+ String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
uidFirewallRules.delete(uid);
} else {
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) {
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) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
@@ -2272,7 +2287,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
pw.println("]");
}
- pw.println("UID firewall standby chain enabled: " + mStandbyChainEnabled);
+ pw.println("UID firewall standby chain enabled: " +
+ mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
synchronized (mUidFirewallStandbyRules) {
pw.print("UID firewall standby rule: [");
final int size = mUidFirewallStandbyRules.size();
@@ -2285,7 +2301,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
pw.println("]");
}
- pw.println("UID firewall dozable chain enabled: " + mDozableChainEnabled);
+ pw.println("UID firewall dozable chain enabled: " +
+ mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
synchronized (mUidFirewallDozableRules) {
pw.print("UID firewall dozable rule: [");
final int size = mUidFirewallDozableRules.size();
diff --git a/services/core/java/com/android/server/content/AppIdleMonitor.java b/services/core/java/com/android/server/content/AppIdleMonitor.java
index 9598de8..fe5c2da 100644
--- a/services/core/java/com/android/server/content/AppIdleMonitor.java
+++ b/services/core/java/com/android/server/content/AppIdleMonitor.java
@@ -18,11 +18,6 @@ package com.android.server.content;
import android.app.usage.UsageStatsManagerInternal;
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 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
* sync operations.
*/
-class AppIdleMonitor implements AppIdleStateChangeListener {
+class AppIdleMonitor extends AppIdleStateChangeListener {
private final SyncManager mSyncManager;
private final UsageStatsManagerInternal mUsageStats;
- final BatteryManager mBatteryManager;
- /** Is the device currently plugged into power. */
- private boolean mPluggedIn;
+ private boolean mAppIdleParoleOn;
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onPluggedIn(mBatteryManager.isCharging());
- }
- };
-
- AppIdleMonitor(SyncManager syncManager, Context context) {
+ AppIdleMonitor(SyncManager syncManager) {
mSyncManager = syncManager;
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
- mUsageStats.addAppIdleStateChangeListener(this);
- mBatteryManager = context.getSystemService(BatteryManager.class);
- mPluggedIn = isPowered();
- registerReceivers(context);
- }
-
- private void registerReceivers(Context context) {
- // Monitor battery charging state
- IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
- filter.addAction(BatteryManager.ACTION_DISCHARGING);
- context.registerReceiver(mReceiver, filter);
- }
+ mAppIdleParoleOn = mUsageStats.isAppIdleParoleOn();
- private boolean isPowered() {
- return mBatteryManager.isCharging();
+ mUsageStats.addAppIdleStateChangeListener(this);
}
- void onPluggedIn(boolean pluggedIn) {
- if (mPluggedIn == pluggedIn) {
+ void setAppIdleParoleOn(boolean appIdleParoleOn) {
+ if (mAppIdleParoleOn == appIdleParoleOn) {
return;
}
- mPluggedIn = pluggedIn;
- if (mPluggedIn) {
+ mAppIdleParoleOn = appIdleParoleOn;
+ if (mAppIdleParoleOn) {
mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL);
}
}
boolean isAppIdle(String packageName, int userId) {
- return !mPluggedIn && mUsageStats.isAppIdle(packageName, userId);
+ return !mAppIdleParoleOn && mUsageStats.isAppIdle(packageName, userId);
}
@Override
@@ -86,4 +60,9 @@ class AppIdleMonitor implements AppIdleStateChangeListener {
if (idle) return;
mSyncManager.onAppNotIdle(packageName, userId);
}
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ setAppIdleParoleOn(isParoleOn);
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index cd9c7fe..91aa745 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -19,6 +19,7 @@ package com.android.server.content;
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
@@ -448,7 +449,7 @@ public class SyncManager {
mSyncAlarmIntent = PendingIntent.getBroadcast(
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);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
@@ -1236,7 +1237,7 @@ public class SyncManager {
* @param userId The user for which the package has become active. Can be USER_ALL if
* the device just plugged in.
*/
- void onAppNotIdle(String packageName, int userId) {
+ void onAppNotIdle(@Nullable String packageName, int userId) {
synchronized (mSyncQueue) {
// For all sync operations in sync queue, if marked as idle, compare with package name
// and unmark. And clear backoff for the operation.
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 98fb11b..02d4f40 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -17,12 +17,7 @@
package com.android.server.job.controllers;
import android.app.usage.UsageStatsManagerInternal;
-import android.content.BroadcastReceiver;
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 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
* out of idle state, it will be allowed to run scheduled jobs.
*/
-public class AppIdleController extends StateController
- implements UsageStatsManagerInternal.AppIdleStateChangeListener {
+public class AppIdleController extends StateController {
private static final String LOG_TAG = "AppIdleController";
private static final boolean DEBUG = false;
@@ -49,14 +43,7 @@ public class AppIdleController extends StateController
private static volatile AppIdleController sController;
final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
private final UsageStatsManagerInternal mUsageStatsInternal;
- private final BatteryManager mBatteryManager;
- private boolean mPluggedIn;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override public void onReceive(Context context, Intent intent) {
- onPluggedIn(mBatteryManager.isCharging());
- }
- };
+ boolean mAppIdleParoleOn;
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
@@ -70,17 +57,8 @@ public class AppIdleController extends StateController
private AppIdleController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
- mBatteryManager = context.getSystemService(BatteryManager.class);
- mPluggedIn = mBatteryManager.isCharging();
- 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);
+ mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
+ mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
}
@Override
@@ -88,7 +66,7 @@ public class AppIdleController extends StateController
synchronized (mTrackedTasks) {
mTrackedTasks.add(jobStatus);
String packageName = jobStatus.job.getService().getPackageName();
- final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
jobStatus.getUserId());
if (DEBUG) {
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
@@ -108,7 +86,7 @@ public class AppIdleController extends StateController
@Override
public void dumpControllerState(PrintWriter pw) {
pw.println("AppIdle");
- pw.println("Plugged In: " + mPluggedIn);
+ pw.println("Parole On: " + mAppIdleParoleOn);
synchronized (mTrackedTasks) {
for (JobStatus task : mTrackedTasks) {
pw.print(task.job.getService().getPackageName());
@@ -119,48 +97,20 @@ public class AppIdleController extends StateController
}
}
- @Override
- 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) {
+ void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
// Flag if any app's idle state has changed
boolean changed = false;
synchronized (mTrackedTasks) {
- if (mPluggedIn == pluggedIn) {
+ if (mAppIdleParoleOn == isAppIdleParoleOn) {
return;
}
- mPluggedIn = pluggedIn;
+ mAppIdleParoleOn = isAppIdleParoleOn;
for (JobStatus task : mTrackedTasks) {
String packageName = task.job.getService().getPackageName();
- final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
task.getUserId());
if (DEBUG) {
- Slog.d(LOG_TAG, "Plugged in " + pluggedIn + ", setting idle state of "
- + packageName + " to " + appIdle);
+ Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
}
if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
task.appNotIdleConstraintSatisfied.set(!appIdle);
@@ -172,4 +122,41 @@ public class AppIdleController extends StateController
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);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b0550d6..847bcb5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -86,7 +86,6 @@ import android.app.IUidObserver;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
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.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.google.android.collect.Lists;
@@ -182,8 +180,7 @@ import java.util.List;
* and delivers to listeners, such as {@link ConnectivityManager}, for
* enforcement.
*/
-public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
- implements AppIdleStateChangeListener {
+public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG = "NetworkPolicy";
private static final boolean LOGD = false;
private static final boolean LOGV = false;
@@ -279,6 +276,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
final SparseIntArray mUidRules = new SparseIntArray();
+ /** Set of states for the child firewall chains. True if the chain is active. */
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
/**
@@ -508,7 +506,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
WifiManager.NETWORK_STATE_CHANGED_ACTION);
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);
}
- 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;
if (oldFirewallReject != firewallReject) {
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject);
- if (mDeviceIdleMode && !firewallReject) {
- // if we are in device idle mode, and we decide to allow this uid. we need to punch
- // a hole in the device idle chain.
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE) && !firewallReject) {
+ // if the dozable chain is on, and we decide to allow this uid. we need to punch
+ // a hole in the dozable chain.
setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, false);
}
}
@@ -2207,15 +2210,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
}
}
- @Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
- try {
- int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+ private class AppIdleStateChangeListener
+ extends UsageStatsManagerInternal.AppIdleStateChangeListener {
+
+ @Override
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+ synchronized (mRulesLock) {
+ updateRulesForUidLocked(uid);
+ }
+ } catch (NameNotFoundException nnfe) {
+ }
+ }
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
synchronized (mRulesLock) {
- updateRulesForUidLocked(uid);
+ 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.
*/
- private void enableFirewallChain(int chain, boolean enable) {
+ private void enableFirewallChainLocked(int chain, boolean enable) {
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
mFirewallChainStates.get(chain) == enable) {
// All is the same, nothing to do.
return;
}
+ mFirewallChainStates.put(chain, enable);
try {
mNetworkManager.setFirewallChainEnabled(chain, enable);
} catch (IllegalStateException e) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 490236e..c49a5f9 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -119,6 +119,7 @@ public class UsageStatsService extends SystemService implements
static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
static final int MSG_PAROLE_END_TIMEOUT = 7;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
+ static final int MSG_PAROLE_STATE_CHANGED = 9;
private final Object mLock = new Object();
Handler mHandler;
@@ -313,7 +314,7 @@ public class UsageStatsService extends SystemService implements
mLastAppIdleParoledTime = checkAndGetTimeLocked();
postNextParoleTimeout();
}
- postCheckIdleStates(UserHandle.USER_ALL);
+ postParoleStateChanged();
}
}
}
@@ -338,6 +339,12 @@ public class UsageStatsService extends SystemService implements
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) {
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) {
final UserUsageStatsService userService;
final long screenOnTime;
@@ -782,13 +796,6 @@ public class UsageStatsService extends SystemService implements
if (!mAppIdleEnabled) {
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;
try {
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) {
return beginTime <= currentTime && beginTime < endTime;
}
@@ -975,6 +988,11 @@ public class UsageStatsService extends SystemService implements
args.recycle();
break;
+ case MSG_PAROLE_STATE_CHANGED:
+ if (DEBUG) Slog.d(TAG, "Parole state changed: " + mAppIdleParoled);
+ informParoleStateChanged();
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -1126,7 +1144,7 @@ public class UsageStatsService extends SystemService implements
}
final long token = Binder.clearCallingIdentity();
try {
- return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
+ return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId, -1);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1251,6 +1269,11 @@ public class UsageStatsService extends SystemService implements
}
@Override
+ public boolean isAppIdleParoleOn() {
+ return mAppIdleParoled;
+ }
+
+ @Override
public void prepareShutdown() {
// This method *WILL* do IO work, but we must block until it is finished or else
// we might not shutdown cleanly. This is ok to do with the 'am' lock held, because
@@ -1261,6 +1284,7 @@ public class UsageStatsService extends SystemService implements
@Override
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
UsageStatsService.this.addListener(listener);
+ listener.onParoleStateChanged(isAppIdleParoleOn());
}
@Override