Merge "Add charging parole notification for network changes." into rvc-dev
This commit is contained in:
@@ -44,6 +44,14 @@ public interface AppStandbyInternal {
|
||||
public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId,
|
||||
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
|
||||
* an active state due to user interaction.
|
||||
@@ -92,6 +100,11 @@ public interface AppStandbyInternal {
|
||||
boolean isAppIdleFiltered(String packageName, int appId, int userId,
|
||||
long elapsedRealtime);
|
||||
|
||||
/**
|
||||
* @return true if currently app idle parole mode is on.
|
||||
*/
|
||||
boolean isInParole();
|
||||
|
||||
int[] getIdleUidsForUser(int userId);
|
||||
|
||||
void setAppIdleAsync(String packageName, boolean idle, int userId);
|
||||
|
||||
@@ -214,8 +214,7 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
private AppIdleHistory mAppIdleHistory;
|
||||
|
||||
@GuardedBy("mPackageAccessListeners")
|
||||
private ArrayList<AppIdleStateChangeListener>
|
||||
mPackageAccessListeners = new ArrayList<>();
|
||||
private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
|
||||
|
||||
/** Whether we've queried the list of carrier privileged apps. */
|
||||
@GuardedBy("mAppIdleLock")
|
||||
@@ -235,6 +234,7 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
static final int MSG_FORCE_IDLE_STATE = 4;
|
||||
static final int MSG_CHECK_IDLE_STATES = 5;
|
||||
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;
|
||||
/** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
|
||||
static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
|
||||
@@ -390,7 +390,16 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
|
||||
@VisibleForTesting
|
||||
void setAppIdleEnabled(boolean enabled) {
|
||||
mAppIdleEnabled = enabled;
|
||||
synchronized (mAppIdleLock) {
|
||||
if (mAppIdleEnabled != enabled) {
|
||||
final boolean oldParoleState = isInParole();
|
||||
mAppIdleEnabled = enabled;
|
||||
if (isInParole() != oldParoleState) {
|
||||
postParoleStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -563,10 +572,22 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
if (mIsCharging != isCharging) {
|
||||
if (DEBUG) Slog.d(TAG, "Setting mIsCharging to " + 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
|
||||
public void postCheckIdleStates(int userId) {
|
||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
|
||||
@@ -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
|
||||
public void flushToDisk(int userId) {
|
||||
synchronized (mAppIdleLock) {
|
||||
@@ -1920,6 +1950,11 @@ public class AppStandbyController implements AppStandbyInternal {
|
||||
args.recycle();
|
||||
break;
|
||||
|
||||
case MSG_PAROLE_STATE_CHANGED:
|
||||
if (DEBUG) Slog.d(TAG, "Parole state: " + isInParole());
|
||||
informParoleStateChanged();
|
||||
break;
|
||||
|
||||
case MSG_CHECK_PACKAGE_IDLE_STATE:
|
||||
checkAndUpdateStandbyState((String) msg.obj, msg.arg1, msg.arg2,
|
||||
mInjector.elapsedRealtime());
|
||||
|
||||
@@ -799,7 +799,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
writePolicyAL();
|
||||
}
|
||||
|
||||
enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, true);
|
||||
setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service");
|
||||
updateRulesForGlobalChangeAL(false);
|
||||
updateNotificationsNL();
|
||||
@@ -871,6 +870,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
new NetworkRequest.Builder().build(), mNetworkCallback);
|
||||
|
||||
mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener());
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
updateRulesForAppIdleParoleUL();
|
||||
}
|
||||
|
||||
// Listen for subscriber changes
|
||||
mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
|
||||
@@ -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},
|
||||
* {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
|
||||
@@ -4347,7 +4382,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
private void updateRulesForPowerRestrictionsUL(int uid) {
|
||||
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) {
|
||||
mUidRules.delete(uid);
|
||||
@@ -4361,28 +4396,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
*
|
||||
* @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 paroled whether to ignore idle state of apps and only look at other restrictions
|
||||
*
|
||||
* @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)) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
|
||||
"updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules);
|
||||
"updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
|
||||
+ (paroled ? "P" : "-"));
|
||||
}
|
||||
try {
|
||||
return updateRulesForPowerRestrictionsULInner(uid, oldUidRules);
|
||||
return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled);
|
||||
} finally {
|
||||
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 (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
|
||||
return RULE_NONE;
|
||||
}
|
||||
|
||||
final boolean isIdle = isUidIdle(uid);
|
||||
final boolean isIdle = !paroled && isUidIdle(uid);
|
||||
final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
|
||||
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
|
||||
|
||||
@@ -4452,6 +4489,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
|
||||
} catch (NameNotFoundException nnfe) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onParoleStateChanged(boolean isParoleOn) {
|
||||
synchronized (mUidRulesFirstLock) {
|
||||
mLogger.paroleStateChanged(isParoleOn);
|
||||
updateRulesForAppIdleParoleUL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
|
||||
|
||||
@@ -366,29 +366,87 @@ public class AppStandbyControllerTests {
|
||||
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
|
||||
public void testIsAppIdle_Charging() throws Exception {
|
||||
TestParoleListener paroleListener = new TestParoleListener();
|
||||
mController.addListener(paroleListener);
|
||||
|
||||
setChargingState(mController, false);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_MAIN_FORCED_BY_SYSTEM);
|
||||
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, false));
|
||||
assertFalse(mController.isInParole());
|
||||
|
||||
paroleListener.rearmLatch(true);
|
||||
setChargingState(mController, true);
|
||||
paroleListener.awaitOnLatch(2000);
|
||||
assertTrue(paroleListener.getParoleState());
|
||||
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, false));
|
||||
assertTrue(mController.isInParole());
|
||||
|
||||
paroleListener.rearmLatch(false);
|
||||
setChargingState(mController, false);
|
||||
paroleListener.awaitOnLatch(2000);
|
||||
assertFalse(paroleListener.getParoleState());
|
||||
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, false));
|
||||
assertFalse(mController.isInParole());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAppIdle_Enabled() throws Exception {
|
||||
setChargingState(mController, false);
|
||||
TestParoleListener paroleListener = new TestParoleListener();
|
||||
mController.addListener(paroleListener);
|
||||
|
||||
setAppIdleEnabled(mController, true);
|
||||
mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
|
||||
REASON_MAIN_FORCED_BY_SYSTEM);
|
||||
@@ -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, false));
|
||||
|
||||
paroleListener.rearmLatch(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, false));
|
||||
|
||||
paroleListener.rearmLatch(true);
|
||||
setAppIdleEnabled(mController, true);
|
||||
paroleListener.awaitOnLatch(2000);
|
||||
assertFalse(paroleListener.getParoleState());
|
||||
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, false));
|
||||
|
||||
Reference in New Issue
Block a user