Loading apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +13 −0 Original line number Original line Diff line number Diff line Loading @@ -44,6 +44,14 @@ public interface AppStandbyInternal { public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId, public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId, boolean idle, int bucket, int reason); boolean idle, int bucket, int reason); /** * Callback to inform listeners that the parole state has changed. This means apps are * allowed to do work even if they're idle or in a low bucket. */ public void onParoleStateChanged(boolean isParoleOn) { // No-op by default } /** /** * Optional callback to inform the listener that the app has transitioned into * Optional callback to inform the listener that the app has transitioned into * an active state due to user interaction. * an active state due to user interaction. Loading Loading @@ -92,6 +100,11 @@ public interface AppStandbyInternal { boolean isAppIdleFiltered(String packageName, int appId, int userId, boolean isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime); long elapsedRealtime); /** * @return true if currently app idle parole mode is on. */ boolean isInParole(); int[] getIdleUidsForUser(int userId); int[] getIdleUidsForUser(int userId); void setAppIdleAsync(String packageName, boolean idle, int userId); void setAppIdleAsync(String packageName, boolean idle, int userId); Loading apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +38 −3 Original line number Original line Diff line number Diff line Loading @@ -214,8 +214,7 @@ public class AppStandbyController implements AppStandbyInternal { private AppIdleHistory mAppIdleHistory; private AppIdleHistory mAppIdleHistory; @GuardedBy("mPackageAccessListeners") @GuardedBy("mPackageAccessListeners") private ArrayList<AppIdleStateChangeListener> private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); mPackageAccessListeners = new ArrayList<>(); /** Whether we've queried the list of carrier privileged apps. */ /** Whether we've queried the list of carrier privileged apps. */ @GuardedBy("mAppIdleLock") @GuardedBy("mAppIdleLock") Loading @@ -235,6 +234,7 @@ public class AppStandbyController implements AppStandbyInternal { static final int MSG_FORCE_IDLE_STATE = 4; static final int MSG_FORCE_IDLE_STATE = 4; static final int MSG_CHECK_IDLE_STATES = 5; static final int MSG_CHECK_IDLE_STATES = 5; 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; static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; Loading Loading @@ -390,7 +390,16 @@ public class AppStandbyController implements AppStandbyInternal { @VisibleForTesting @VisibleForTesting void setAppIdleEnabled(boolean enabled) { void setAppIdleEnabled(boolean enabled) { synchronized (mAppIdleLock) { if (mAppIdleEnabled != enabled) { final boolean oldParoleState = isInParole(); mAppIdleEnabled = enabled; mAppIdleEnabled = enabled; if (isInParole() != oldParoleState) { postParoleStateChanged(); } } } } } @Override @Override Loading Loading @@ -563,10 +572,22 @@ public class AppStandbyController implements AppStandbyInternal { if (mIsCharging != isCharging) { if (mIsCharging != isCharging) { if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging); if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging); mIsCharging = isCharging; mIsCharging = isCharging; postParoleStateChanged(); } } } } } } @Override public boolean isInParole() { return !mAppIdleEnabled || mIsCharging; } 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); } @Override @Override public void postCheckIdleStates(int userId) { public void postCheckIdleStates(int userId) { mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); Loading Loading @@ -1502,6 +1523,15 @@ public class AppStandbyController implements AppStandbyInternal { } } } } private void informParoleStateChanged() { final boolean paroled = isInParole(); synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onParoleStateChanged(paroled); } } } @Override @Override public void flushToDisk(int userId) { public void flushToDisk(int userId) { synchronized (mAppIdleLock) { synchronized (mAppIdleLock) { Loading Loading @@ -1920,6 +1950,11 @@ public class AppStandbyController implements AppStandbyInternal { args.recycle(); args.recycle(); break; break; case MSG_PAROLE_STATE_CHANGED: if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole()); informParoleStateChanged(); break; case MSG_CHECK_PACKAGE_IDLE_STATE: case MSG_CHECK_PACKAGE_IDLE_STATE: checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, mInjector.elapsedRealtime()); mInjector.elapsedRealtime()); Loading services/core/java/com/android/server/net/NetworkPolicyManagerService.java +52 −7 Original line number Original line Diff line number Diff line Loading @@ -799,7 +799,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { writePolicyAL(); writePolicyAL(); } } enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true); setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); updateRulesForGlobalChangeAL(false); updateRulesForGlobalChangeAL(false); updateNotificationsNL(); updateNotificationsNL(); Loading Loading @@ -871,6 +870,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { new NetworkRequest.Builder().build(), mNetworkCallback); new NetworkRequest.Builder().build(), mNetworkCallback); mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener()); mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener()); synchronized (mUidRulesFirstLock) { updateRulesForAppIdleParoleUL(); } // Listen for subscriber changes // Listen for subscriber changes mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener( mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener( Loading Loading @@ -3892,6 +3894,39 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } } } /** * Toggle the firewall standby chain and inform listeners if the uid rules have effectively * changed. */ @GuardedBy("mUidRulesFirstLock") private void updateRulesForAppIdleParoleUL() { final boolean paroled = mAppStandby.isInParole(); final boolean enableChain = !paroled; enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain); int ruleCount = mUidFirewallStandbyRules.size(); for (int i = 0; i < ruleCount; i++) { final int uid = mUidFirewallStandbyRules.keyAt(i); int oldRules = mUidRules.get(uid); if (enableChain) { // Chain wasn't enabled before and the other power-related // chains are whitelists, so we can clear the // MASK_ALL_NETWORKS part of the rules and re-inform listeners if // the effective rules result in blocking network access. oldRules &= MASK_METERED_NETWORKS; } else { // Skip if it had no restrictions to begin with if ((oldRules & MASK_ALL_NETWORKS) == 0) continue; } final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled); if (newUidRules == RULE_NONE) { mUidRules.delete(uid); } else { mUidRules.put(uid, newUidRules); } } } /** /** * Update rules that might be changed by {@link #mRestrictBackground}, * Update rules that might be changed by {@link #mRestrictBackground}, * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value. * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value. Loading Loading @@ -4347,7 +4382,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateRulesForPowerRestrictionsUL(int uid) { private void updateRulesForPowerRestrictionsUL(int uid) { final int oldUidRules = mUidRules.get(uid, RULE_NONE); final int oldUidRules = mUidRules.get(uid, RULE_NONE); final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules); final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false); if (newUidRules == RULE_NONE) { if (newUidRules == RULE_NONE) { mUidRules.delete(uid); mUidRules.delete(uid); Loading @@ -4361,28 +4396,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * * * @param uid the uid of the app to update rules for * @param uid the uid of the app to update rules for * @param oldUidRules the current rules for the uid, in order to determine if there's a change * @param oldUidRules the current rules for the uid, in order to determine if there's a change * @param paroled whether to ignore idle state of apps and only look at other restrictions * * * @return the new computed rules for the uid * @return the new computed rules for the uid */ */ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules) { private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules); "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/" + (paroled ? "P" : "-")); } } try { try { return updateRulesForPowerRestrictionsULInner(uid, oldUidRules); return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled); } finally { } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } } } } private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules) { private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) { if (!isUidValidForBlacklistRules(uid)) { if (!isUidValidForBlacklistRules(uid)) { if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); return RULE_NONE; return RULE_NONE; } } final boolean isIdle = isUidIdle(uid); final boolean isIdle = !paroled && isUidIdle(uid); final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode; final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode; final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); Loading Loading @@ -4452,6 +4489,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } catch (NameNotFoundException nnfe) { } catch (NameNotFoundException nnfe) { } } } } @Override public void onParoleStateChanged(boolean isParoleOn) { synchronized (mUidRulesFirstLock) { mLogger.paroleStateChanged(isParoleOn); updateRulesForAppIdleParoleUL(); } } } } private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { Loading services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +64 −0 Original line number Original line Diff line number Diff line Loading @@ -366,29 +366,87 @@ public class AppStandbyControllerTests { mInjector.mElapsedRealtime, false)); mInjector.mElapsedRealtime, false)); } } private static class TestParoleListener extends AppIdleStateChangeListener { private boolean mIsParoleOn = false; private CountDownLatch mLatch; private boolean mIsExpecting = false; private boolean mExpectedParoleState; boolean getParoleState() { synchronized (this) { return mIsParoleOn; } } void rearmLatch(boolean expectedParoleState) { synchronized (this) { mLatch = new CountDownLatch(1); mIsExpecting = true; mExpectedParoleState = expectedParoleState; } } void awaitOnLatch(long time) throws Exception { mLatch.await(time, TimeUnit.MILLISECONDS); } @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) { } @Override public void onParoleStateChanged(boolean isParoleOn) { synchronized (this) { // Only record information if it is being looked for if (mLatch != null && mLatch.getCount() > 0) { mIsParoleOn = isParoleOn; if (mIsExpecting && isParoleOn == mExpectedParoleState) { mLatch.countDown(); } } } } } @Test @Test public void testIsAppIdle_Charging() throws Exception { public void testIsAppIdle_Charging() throws Exception { TestParoleListener paroleListener = new TestParoleListener(); mController.addListener(paroleListener); setChargingState(mController, false); setChargingState(mController, false); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); REASON_MAIN_FORCED_BY_SYSTEM); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isInParole()); paroleListener.rearmLatch(true); setChargingState(mController, true); setChargingState(mController, true); paroleListener.awaitOnLatch(2000); assertTrue(paroleListener.getParoleState()); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isInParole()); paroleListener.rearmLatch(false); setChargingState(mController, false); setChargingState(mController, false); paroleListener.awaitOnLatch(2000); assertFalse(paroleListener.getParoleState()); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isInParole()); } } @Test @Test public void testIsAppIdle_Enabled() throws Exception { public void testIsAppIdle_Enabled() throws Exception { setChargingState(mController, false); setChargingState(mController, false); TestParoleListener paroleListener = new TestParoleListener(); mController.addListener(paroleListener); setAppIdleEnabled(mController, true); setAppIdleEnabled(mController, true); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); REASON_MAIN_FORCED_BY_SYSTEM); Loading @@ -396,11 +454,17 @@ public class AppStandbyControllerTests { assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); paroleListener.rearmLatch(false); setAppIdleEnabled(mController, false); setAppIdleEnabled(mController, false); paroleListener.awaitOnLatch(2000); assertTrue(paroleListener.mIsParoleOn); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); paroleListener.rearmLatch(true); setAppIdleEnabled(mController, true); setAppIdleEnabled(mController, true); paroleListener.awaitOnLatch(2000); assertFalse(paroleListener.getParoleState()); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); Loading Loading
apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +13 −0 Original line number Original line Diff line number Diff line Loading @@ -44,6 +44,14 @@ public interface AppStandbyInternal { public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId, public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId, boolean idle, int bucket, int reason); boolean idle, int bucket, int reason); /** * Callback to inform listeners that the parole state has changed. This means apps are * allowed to do work even if they're idle or in a low bucket. */ public void onParoleStateChanged(boolean isParoleOn) { // No-op by default } /** /** * Optional callback to inform the listener that the app has transitioned into * Optional callback to inform the listener that the app has transitioned into * an active state due to user interaction. * an active state due to user interaction. Loading Loading @@ -92,6 +100,11 @@ public interface AppStandbyInternal { boolean isAppIdleFiltered(String packageName, int appId, int userId, boolean isAppIdleFiltered(String packageName, int appId, int userId, long elapsedRealtime); long elapsedRealtime); /** * @return true if currently app idle parole mode is on. */ boolean isInParole(); int[] getIdleUidsForUser(int userId); int[] getIdleUidsForUser(int userId); void setAppIdleAsync(String packageName, boolean idle, int userId); void setAppIdleAsync(String packageName, boolean idle, int userId); Loading
apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +38 −3 Original line number Original line Diff line number Diff line Loading @@ -214,8 +214,7 @@ public class AppStandbyController implements AppStandbyInternal { private AppIdleHistory mAppIdleHistory; private AppIdleHistory mAppIdleHistory; @GuardedBy("mPackageAccessListeners") @GuardedBy("mPackageAccessListeners") private ArrayList<AppIdleStateChangeListener> private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>(); mPackageAccessListeners = new ArrayList<>(); /** Whether we've queried the list of carrier privileged apps. */ /** Whether we've queried the list of carrier privileged apps. */ @GuardedBy("mAppIdleLock") @GuardedBy("mAppIdleLock") Loading @@ -235,6 +234,7 @@ public class AppStandbyController implements AppStandbyInternal { static final int MSG_FORCE_IDLE_STATE = 4; static final int MSG_FORCE_IDLE_STATE = 4; static final int MSG_CHECK_IDLE_STATES = 5; static final int MSG_CHECK_IDLE_STATES = 5; 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; static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10; /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */ static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11; Loading Loading @@ -390,7 +390,16 @@ public class AppStandbyController implements AppStandbyInternal { @VisibleForTesting @VisibleForTesting void setAppIdleEnabled(boolean enabled) { void setAppIdleEnabled(boolean enabled) { synchronized (mAppIdleLock) { if (mAppIdleEnabled != enabled) { final boolean oldParoleState = isInParole(); mAppIdleEnabled = enabled; mAppIdleEnabled = enabled; if (isInParole() != oldParoleState) { postParoleStateChanged(); } } } } } @Override @Override Loading Loading @@ -563,10 +572,22 @@ public class AppStandbyController implements AppStandbyInternal { if (mIsCharging != isCharging) { if (mIsCharging != isCharging) { if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging); if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + isCharging); mIsCharging = isCharging; mIsCharging = isCharging; postParoleStateChanged(); } } } } } } @Override public boolean isInParole() { return !mAppIdleEnabled || mIsCharging; } 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); } @Override @Override public void postCheckIdleStates(int userId) { public void postCheckIdleStates(int userId) { mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0)); Loading Loading @@ -1502,6 +1523,15 @@ public class AppStandbyController implements AppStandbyInternal { } } } } private void informParoleStateChanged() { final boolean paroled = isInParole(); synchronized (mPackageAccessListeners) { for (AppIdleStateChangeListener listener : mPackageAccessListeners) { listener.onParoleStateChanged(paroled); } } } @Override @Override public void flushToDisk(int userId) { public void flushToDisk(int userId) { synchronized (mAppIdleLock) { synchronized (mAppIdleLock) { Loading Loading @@ -1920,6 +1950,11 @@ public class AppStandbyController implements AppStandbyInternal { args.recycle(); args.recycle(); break; break; case MSG_PAROLE_STATE_CHANGED: if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole()); informParoleStateChanged(); break; case MSG_CHECK_PACKAGE_IDLE_STATE: case MSG_CHECK_PACKAGE_IDLE_STATE: checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2, mInjector.elapsedRealtime()); mInjector.elapsedRealtime()); Loading
services/core/java/com/android/server/net/NetworkPolicyManagerService.java +52 −7 Original line number Original line Diff line number Diff line Loading @@ -799,7 +799,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { writePolicyAL(); writePolicyAL(); } } enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true); setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service"); updateRulesForGlobalChangeAL(false); updateRulesForGlobalChangeAL(false); updateNotificationsNL(); updateNotificationsNL(); Loading Loading @@ -871,6 +870,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { new NetworkRequest.Builder().build(), mNetworkCallback); new NetworkRequest.Builder().build(), mNetworkCallback); mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener()); mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener()); synchronized (mUidRulesFirstLock) { updateRulesForAppIdleParoleUL(); } // Listen for subscriber changes // Listen for subscriber changes mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener( mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener( Loading Loading @@ -3892,6 +3894,39 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } } } /** * Toggle the firewall standby chain and inform listeners if the uid rules have effectively * changed. */ @GuardedBy("mUidRulesFirstLock") private void updateRulesForAppIdleParoleUL() { final boolean paroled = mAppStandby.isInParole(); final boolean enableChain = !paroled; enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain); int ruleCount = mUidFirewallStandbyRules.size(); for (int i = 0; i < ruleCount; i++) { final int uid = mUidFirewallStandbyRules.keyAt(i); int oldRules = mUidRules.get(uid); if (enableChain) { // Chain wasn't enabled before and the other power-related // chains are whitelists, so we can clear the // MASK_ALL_NETWORKS part of the rules and re-inform listeners if // the effective rules result in blocking network access. oldRules &= MASK_METERED_NETWORKS; } else { // Skip if it had no restrictions to begin with if ((oldRules & MASK_ALL_NETWORKS) == 0) continue; } final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled); if (newUidRules == RULE_NONE) { mUidRules.delete(uid); } else { mUidRules.put(uid, newUidRules); } } } /** /** * Update rules that might be changed by {@link #mRestrictBackground}, * Update rules that might be changed by {@link #mRestrictBackground}, * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value. * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value. Loading Loading @@ -4347,7 +4382,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateRulesForPowerRestrictionsUL(int uid) { private void updateRulesForPowerRestrictionsUL(int uid) { final int oldUidRules = mUidRules.get(uid, RULE_NONE); final int oldUidRules = mUidRules.get(uid, RULE_NONE); final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules); final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false); if (newUidRules == RULE_NONE) { if (newUidRules == RULE_NONE) { mUidRules.delete(uid); mUidRules.delete(uid); Loading @@ -4361,28 +4396,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * * * @param uid the uid of the app to update rules for * @param uid the uid of the app to update rules for * @param oldUidRules the current rules for the uid, in order to determine if there's a change * @param oldUidRules the current rules for the uid, in order to determine if there's a change * @param paroled whether to ignore idle state of apps and only look at other restrictions * * * @return the new computed rules for the uid * @return the new computed rules for the uid */ */ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules) { private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules); "updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/" + (paroled ? "P" : "-")); } } try { try { return updateRulesForPowerRestrictionsULInner(uid, oldUidRules); return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled); } finally { } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } } } } private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules) { private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) { if (!isUidValidForBlacklistRules(uid)) { if (!isUidValidForBlacklistRules(uid)) { if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); return RULE_NONE; return RULE_NONE; } } final boolean isIdle = isUidIdle(uid); final boolean isIdle = !paroled && isUidIdle(uid); final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode; final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode; final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid); Loading Loading @@ -4452,6 +4489,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } catch (NameNotFoundException nnfe) { } catch (NameNotFoundException nnfe) { } } } } @Override public void onParoleStateChanged(boolean isParoleOn) { synchronized (mUidRulesFirstLock) { mLogger.paroleStateChanged(isParoleOn); updateRulesForAppIdleParoleUL(); } } } } private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { Loading
services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +64 −0 Original line number Original line Diff line number Diff line Loading @@ -366,29 +366,87 @@ public class AppStandbyControllerTests { mInjector.mElapsedRealtime, false)); mInjector.mElapsedRealtime, false)); } } private static class TestParoleListener extends AppIdleStateChangeListener { private boolean mIsParoleOn = false; private CountDownLatch mLatch; private boolean mIsExpecting = false; private boolean mExpectedParoleState; boolean getParoleState() { synchronized (this) { return mIsParoleOn; } } void rearmLatch(boolean expectedParoleState) { synchronized (this) { mLatch = new CountDownLatch(1); mIsExpecting = true; mExpectedParoleState = expectedParoleState; } } void awaitOnLatch(long time) throws Exception { mLatch.await(time, TimeUnit.MILLISECONDS); } @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) { } @Override public void onParoleStateChanged(boolean isParoleOn) { synchronized (this) { // Only record information if it is being looked for if (mLatch != null && mLatch.getCount() > 0) { mIsParoleOn = isParoleOn; if (mIsExpecting && isParoleOn == mExpectedParoleState) { mLatch.countDown(); } } } } } @Test @Test public void testIsAppIdle_Charging() throws Exception { public void testIsAppIdle_Charging() throws Exception { TestParoleListener paroleListener = new TestParoleListener(); mController.addListener(paroleListener); setChargingState(mController, false); setChargingState(mController, false); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); REASON_MAIN_FORCED_BY_SYSTEM); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isInParole()); paroleListener.rearmLatch(true); setChargingState(mController, true); setChargingState(mController, true); paroleListener.awaitOnLatch(2000); assertTrue(paroleListener.getParoleState()); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isInParole()); paroleListener.rearmLatch(false); setChargingState(mController, false); setChargingState(mController, false); paroleListener.awaitOnLatch(2000); assertFalse(paroleListener.getParoleState()); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isInParole()); } } @Test @Test public void testIsAppIdle_Enabled() throws Exception { public void testIsAppIdle_Enabled() throws Exception { setChargingState(mController, false); setChargingState(mController, false); TestParoleListener paroleListener = new TestParoleListener(); mController.addListener(paroleListener); setAppIdleEnabled(mController, true); setAppIdleEnabled(mController, true); mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); REASON_MAIN_FORCED_BY_SYSTEM); Loading @@ -396,11 +454,17 @@ public class AppStandbyControllerTests { assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); paroleListener.rearmLatch(false); setAppIdleEnabled(mController, false); setAppIdleEnabled(mController, false); paroleListener.awaitOnLatch(2000); assertTrue(paroleListener.mIsParoleOn); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); paroleListener.rearmLatch(true); setAppIdleEnabled(mController, true); setAppIdleEnabled(mController, true); paroleListener.awaitOnLatch(2000); assertFalse(paroleListener.getParoleState()); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false)); Loading