diff options
| author | 2022-04-15 17:38:30 +0000 | |
|---|---|---|
| committer | 2022-04-15 17:38:30 +0000 | |
| commit | cc7dec54ab49f99246ad96ae6365a6119931287a (patch) | |
| tree | de9be25931d9488acbecaf89c34c79f2ae742c5e | |
| parent | e816d004adf8dd3841ee97ba8647579fb243fdaa (diff) | |
| parent | 4613ce0a2bbbaebec8df183efa60f8fc299da561 (diff) | |
Merge changes Iad41fa42,Ie37173d0,Ib923eafb,I9bff481a,I631f5e01, ...
* changes:
Inform the app to wait only if procstate has affect on ntwk access.
Inform Application thread to block for network rules to be updated.
Update getUidProcessState to consider mPendingStartActivityUids.
Inform AMS about the uid blocked reasons.
Ignore older UID state change callbacks in NPMS.
Inform NPMS about the app coming to the TOP state early.
Optimize the handling of disabling doze state.
Fix the arguments order to postBlockedReasonsChangedMsg.
Avoid checking for idle state when the app is in top state.
Update network rules for only uids that are installed.
Fix logs in NetworkPolicyManagerService.
Guard mUidBlockedState with a separate lock.
Add SDK sandbox UIDs to network policy.
Add some debugs to diagnose test failure.
15 files changed, 690 insertions, 417 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index db45466d98d2..6a877f97f180 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -4658,6 +4658,11 @@ public class ActivityManager { } /** @hide */ + public static boolean isProcStateConsideredInteraction(@ProcessState int procState) { + return (procState <= PROCESS_STATE_TOP || procState == PROCESS_STATE_BOUND_TOP); + } + + /** @hide */ public static String procStateToString(int procState) { final String procStateStr; switch (procState) { diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 4c30f56e40d6..7ec361922afc 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -209,6 +209,12 @@ public abstract class ActivityManagerInternal { public abstract void notifyNetworkPolicyRulesUpdated(int uid, long procStateSeq); /** + * Inform ActivityManagerService about the latest {@code blockedReasons} for an uid, which + * can be used to understand whether the {@code uid} is allowed to access network or not. + */ + public abstract void onUidBlockedReasonsChanged(int uid, int blockedReasons); + + /** * @return true if runtime was restarted, false if it's normal boot */ public abstract boolean isRuntimeRestarted(); @@ -581,7 +587,7 @@ public abstract class ActivityManagerInternal { * @param uid uid * @param pid pid of the ProcessRecord that is pending top. */ - public abstract void addPendingTopUid(int uid, int pid); + public abstract void addPendingTopUid(int uid, int pid, @Nullable IApplicationThread thread); /** * Delete uid from the ActivityManagerService PendingStartActivityUids list. @@ -680,4 +686,15 @@ public abstract class ActivityManagerInternal { */ void notifyActivityEventChanged(); } + + /** + * Register the UidObserver for NetworkPolicyManager service. + * + * This is equivalent to calling + * {@link IActivityManager#registerUidObserver(IUidObserver, int, int, String)} but having a + * separate method for NetworkPolicyManager service so that it's UidObserver can be called + * separately outside the usual UidObserver flow. + */ + public abstract void registerNetworkPolicyUidObserver(@NonNull IUidObserver observer, + int which, int cutpoint, @NonNull String callingPackage); } diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 2c2a703b16e2..9341105675a2 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -817,11 +817,13 @@ public class NetworkPolicyManager { public static final class UidState { public int uid; public int procState; + public long procStateSeq; public int capability; - public UidState(int uid, int procState, int capability) { + public UidState(int uid, int procState, long procStateSeq, int capability) { this.uid = uid; this.procState = procState; + this.procStateSeq = procStateSeq; this.capability = capability; } @@ -830,6 +832,8 @@ public class NetworkPolicyManager { final StringBuilder sb = new StringBuilder(); sb.append("{procState="); sb.append(procStateToString(procState)); + sb.append(",seq="); + sb.append(procStateSeq); sb.append(",cap="); ActivityManager.printCapabilitiesSummary(sb, capability); sb.append("}"); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 76c2d5ef7fd3..ec9f1fe9212a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -28,6 +28,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART; import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; +import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityManager.PROCESS_STATE_TOP; @@ -45,6 +46,13 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED; +import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY; +import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER; +import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE; +import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY; +import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.os.FactoryTest.FACTORY_TEST_OFF; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH; @@ -1415,6 +1423,10 @@ public class ActivityManagerService extends IActivityManager.Stub final ActivityThread mSystemThread; final UidObserverController mUidObserverController; + private volatile IUidObserver mNetworkPolicyUidObserver; + + @GuardedBy("mUidNetworkBlockedReasons") + private final SparseIntArray mUidNetworkBlockedReasons = new SparseIntArray(); private final class AppDeathRecipient implements IBinder.DeathRecipient { final ProcessRecord mApp; @@ -6784,6 +6796,9 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (mProcLock) { + if (mPendingStartActivityUids.isPendingTopUid(uid)) { + return PROCESS_STATE_TOP; + } return mProcessList.getUidProcStateLOSP(uid); } } @@ -14447,7 +14462,6 @@ public class ActivityManagerService extends IActivityManager.Stub uid, change, procState, procStateSeq, capability, ephemeral); if (uidRec != null) { uidRec.setLastReportedChange(enqueuedChange); - uidRec.updateLastDispatchedProcStateSeq(enqueuedChange); } // Directly update the power manager, since we sit on top of it and it is critical @@ -15585,18 +15599,13 @@ public class ActivityManagerService extends IActivityManager.Stub return; } record.lastNetworkUpdatedProcStateSeq = procStateSeq; - if (record.curProcStateSeq > procStateSeq) { - if (DEBUG_NETWORK) { - Slog.d(TAG_NETWORK, "No need to handle older seq no., Uid: " + uid - + ", curProcstateSeq: " + record.curProcStateSeq - + ", procStateSeq: " + procStateSeq); - } - return; - } - if (record.waitingForNetwork) { + if (record.procStateSeqWaitingForNetwork != 0 + && procStateSeq >= record.procStateSeqWaitingForNetwork) { if (DEBUG_NETWORK) { Slog.d(TAG_NETWORK, "Notifying all blocking threads for uid: " + uid - + ", procStateSeq: " + procStateSeq); + + ", procStateSeq: " + procStateSeq + + ", procStateSeqWaitingForNetwork: " + + record.procStateSeqWaitingForNetwork); } record.networkStateLock.notifyAll(); } @@ -15604,6 +15613,17 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void onUidBlockedReasonsChanged(int uid, int blockedReasons) { + synchronized (mUidNetworkBlockedReasons) { + if (blockedReasons == BLOCKED_REASON_NONE) { + mUidNetworkBlockedReasons.delete(uid); + } else { + mUidNetworkBlockedReasons.put(uid, blockedReasons); + } + } + } + + @Override public boolean isRuntimeRestarted() { return mSystemServiceManager.isRuntimeRestarted(); } @@ -16301,8 +16321,51 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void addPendingTopUid(int uid, int pid) { - mPendingStartActivityUids.add(uid, pid); + public void addPendingTopUid(int uid, int pid, @Nullable IApplicationThread thread) { + final boolean isNewPending = mPendingStartActivityUids.add(uid, pid); + // We need to update the network rules for the app coming to the top state so that + // it can access network when the device or the app is in a restricted state + // (e.g. battery/data saver) but since waiting for updateOomAdj to complete and then + // informing NetworkPolicyManager might get delayed, informing the state change as soon + // as we know app is going to come to the top state. + if (isNewPending && mNetworkPolicyUidObserver != null) { + try { + final long procStateSeq = mProcessList.getNextProcStateSeq(); + mNetworkPolicyUidObserver.onUidStateChanged(uid, PROCESS_STATE_TOP, + procStateSeq, PROCESS_CAPABILITY_ALL); + if (thread != null && isNetworkingBlockedForUid(uid)) { + thread.setNetworkBlockSeq(procStateSeq); + } + } catch (RemoteException e) { + Slog.d(TAG, "Error calling setNetworkBlockSeq", e); + } + } + } + + private boolean isNetworkingBlockedForUid(int uid) { + synchronized (mUidNetworkBlockedReasons) { + // TODO: We can consider only those blocked reasons that will be overridden + // by the TOP state. For other ones, there is no point in waiting. + // TODO: We can reuse this data in + // ProcessList#incrementProcStateSeqAndNotifyAppsLOSP instead of calling into + // NetworkManagementService. + final int uidBlockedReasons = mUidNetworkBlockedReasons.get( + uid, BLOCKED_REASON_NONE); + if (uidBlockedReasons == BLOCKED_REASON_NONE) { + return false; + } + final int topExemptedBlockedReasons = BLOCKED_REASON_BATTERY_SAVER + | BLOCKED_REASON_DOZE + | BLOCKED_REASON_APP_STANDBY + | BLOCKED_REASON_LOW_POWER_STANDBY + | BLOCKED_METERED_REASON_DATA_SAVER + | BLOCKED_METERED_REASON_USER_RESTRICTED; + final int effectiveBlockedReasons = + uidBlockedReasons & ~topExemptedBlockedReasons; + // Only consider it as blocked if it is not blocked by a reason + // that is not exempted by app being in the top state. + return effectiveBlockedReasons == BLOCKED_REASON_NONE; + } } @Override @@ -16449,6 +16512,14 @@ public class ActivityManagerService extends IActivityManager.Stub public void setStopUserOnSwitch(int value) { ActivityManagerService.this.setStopUserOnSwitch(value); } + + @Override + public void registerNetworkPolicyUidObserver(@NonNull IUidObserver observer, + int which, int cutpoint, @NonNull String callingPackage) { + mNetworkPolicyUidObserver = observer; + mUidObserverController.register(observer, which, cutpoint, callingPackage, + Binder.getCallingUid()); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { @@ -16528,23 +16599,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } synchronized (record.networkStateLock) { - if (record.lastDispatchedProcStateSeq < procStateSeq) { - if (DEBUG_NETWORK) { - Slog.d(TAG_NETWORK, "Uid state change for seq no. " + procStateSeq + " is not " - + "dispatched to NPMS yet, so don't wait. Uid: " + callingUid - + " lastProcStateSeqDispatchedToObservers: " - + record.lastDispatchedProcStateSeq); - } - return; - } - if (record.curProcStateSeq > procStateSeq) { - if (DEBUG_NETWORK) { - Slog.d(TAG_NETWORK, "Ignore the wait requests for older seq numbers. Uid: " - + callingUid + ", curProcStateSeq: " + record.curProcStateSeq - + ", procStateSeq: " + procStateSeq); - } - return; - } if (record.lastNetworkUpdatedProcStateSeq >= procStateSeq) { if (DEBUG_NETWORK) { Slog.d(TAG_NETWORK, "Network rules have been already updated for seq no. " @@ -16560,9 +16614,9 @@ public class ActivityManagerService extends IActivityManager.Stub + " Uid: " + callingUid + " procStateSeq: " + procStateSeq); } final long startTime = SystemClock.uptimeMillis(); - record.waitingForNetwork = true; + record.procStateSeqWaitingForNetwork = procStateSeq; record.networkStateLock.wait(mWaitForNetworkTimeoutMs); - record.waitingForNetwork = false; + record.procStateSeqWaitingForNetwork = 0; final long totalTime = SystemClock.uptimeMillis() - startTime; if (totalTime >= mWaitForNetworkTimeoutMs || DEBUG_NETWORK) { Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: " diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 9e0441004568..ce40f85972f5 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -2911,8 +2911,7 @@ public class OomAdjuster { // To avoid some abuse patterns, we are going to be careful about what we consider // to be an app interaction. Being the top activity doesn't count while the display // is sleeping, nor do short foreground services. - if (state.getCurProcState() <= PROCESS_STATE_TOP - || state.getCurProcState() == PROCESS_STATE_BOUND_TOP) { + if (ActivityManager.isProcStateConsideredInteraction(state.getCurProcState())) { isInteraction = true; state.setFgInteractionTime(0); } else if (state.getCurProcState() <= PROCESS_STATE_FOREGROUND_SERVICE) { diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java index 20f6bb205dc4..5beda3197581 100644 --- a/services/core/java/com/android/server/am/PendingStartActivityUids.java +++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java @@ -44,10 +44,12 @@ final class PendingStartActivityUids { mContext = context; } - synchronized void add(int uid, int pid) { + synchronized boolean add(int uid, int pid) { if (mPendingUids.get(uid) == null) { mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime())); + return true; } + return false; } synchronized void delete(int uid, long nowElapsed) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 1e66ed42ff96..dc80c4b33297 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -482,9 +482,8 @@ public final class ProcessList { * Having a global counter ensures that seq numbers are monotonically increasing for a * particular uid even when the uidRecord is re-created. */ - @GuardedBy("mService") @VisibleForTesting - long mProcStateSeqCounter = 0; + volatile long mProcStateSeqCounter = 0; /** * A global counter for generating sequence numbers to uniquely identify pending process starts. @@ -4878,13 +4877,17 @@ public final class ProcessList { } /** - * Checks if any uid is coming from background to foreground or vice versa and if so, increments - * the {@link UidRecord#curProcStateSeq} corresponding to that uid using global seq counter - * {@link ProcessList#mProcStateSeqCounter} and notifies the app if it needs to block. + * Increments the {@link UidRecord#curProcStateSeq} for all uids using global seq counter + * {@link ProcessList#mProcStateSeqCounter} and checks if any uid is coming + * from background to foreground or vice versa and if so, notifies the app if it needs to block. */ @VisibleForTesting @GuardedBy(anyOf = {"mService", "mProcLock"}) void incrementProcStateSeqAndNotifyAppsLOSP(ActiveUids activeUids) { + for (int i = activeUids.size() - 1; i >= 0; --i) { + final UidRecord uidRec = activeUids.valueAt(i); + uidRec.curProcStateSeq = getNextProcStateSeq(); + } if (mService.mWaitForNetworkTimeoutMs <= 0) { return; } @@ -4911,7 +4914,6 @@ public final class ProcessList { continue; } synchronized (uidRec.networkStateLock) { - uidRec.curProcStateSeq = ++mProcStateSeqCounter; // TODO: use method if (blockState == NETWORK_STATE_BLOCK) { if (blockingUids == null) { blockingUids = new ArrayList<>(); @@ -4922,7 +4924,7 @@ public final class ProcessList { Slog.d(TAG_NETWORK, "uid going to background, notifying all blocking" + " threads for uid: " + uidRec); } - if (uidRec.waitingForNetwork) { + if (uidRec.procStateSeqWaitingForNetwork != 0) { uidRec.networkStateLock.notifyAll(); } } @@ -4956,6 +4958,10 @@ public final class ProcessList { } } + long getNextProcStateSeq() { + return ++mProcStateSeqCounter; + } + /** * Create a server socket in system_server, zygote will connect to it * in order to send unsolicited messages to system_server. diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java index c1bfe25618b2..67b9ae67bbd9 100644 --- a/services/core/java/com/android/server/am/UidObserverController.java +++ b/services/core/java/com/android/server/am/UidObserverController.java @@ -219,7 +219,6 @@ public class UidObserverController { validateUid.setCurProcState(item.procState); validateUid.setSetCapability(item.capability); validateUid.setCurCapability(item.capability); - validateUid.lastDispatchedProcStateSeq = item.procStateSeq; } } } diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index 4ba59faea9ec..2ec08a45236f 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -95,16 +95,9 @@ public final class UidRecord { long lastNetworkUpdatedProcStateSeq; /** - * Last seq number for which AcitivityManagerService dispatched uid state change to - * NetworkPolicyManagerService. + * Indicates if any thread is waiting for network rules to get updated for {@link #mUid}. */ - @GuardedBy("networkStateUpdate") - long lastDispatchedProcStateSeq; - - /** - * Indicates if any thread is waiting for network rules to get updated for {@link #uid}. - */ - volatile boolean waitingForNetwork; + volatile long procStateSeqWaitingForNetwork; /** * Indicates whether this uid has internet permission or not. @@ -309,18 +302,6 @@ public final class UidRecord { mUid) == PackageManager.PERMISSION_GRANTED; } - /** - * If the change being dispatched is not CHANGE_GONE (not interested in - * these changes), then update the {@link #lastDispatchedProcStateSeq} with - * {@link #curProcStateSeq}. - */ - public void updateLastDispatchedProcStateSeq(int changeToDispatch) { - if ((changeToDispatch & CHANGE_GONE) == 0) { - lastDispatchedProcStateSeq = curProcStateSeq; - } - } - - void dumpDebug(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); proto.write(UidRecordProto.UID, mUid); @@ -341,7 +322,6 @@ public final class UidRecord { proto.write(UidRecordProto.ProcStateSequence.CURURENT, curProcStateSeq); proto.write(UidRecordProto.ProcStateSequence.LAST_NETWORK_UPDATED, lastNetworkUpdatedProcStateSeq); - proto.write(UidRecordProto.ProcStateSequence.LAST_DISPATCHED, lastDispatchedProcStateSeq); proto.end(seqToken); proto.end(token); @@ -412,8 +392,6 @@ public final class UidRecord { sb.append(curProcStateSeq); sb.append(","); sb.append(lastNetworkUpdatedProcStateSeq); - sb.append(","); - sb.append(lastDispatchedProcStateSeq); sb.append(")}"); return sb.toString(); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 33ac6cdb269e..c9631549cd76 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -77,6 +77,8 @@ public class NetworkPolicyLogger { private static final int EVENT_FIREWALL_CHAIN_ENABLED = 12; private static final int EVENT_UPDATE_METERED_RESTRICTED_PKGS = 13; private static final int EVENT_APP_IDLE_WL_CHANGED = 14; + private static final int EVENT_METERED_ALLOWLIST_CHANGED = 15; + private static final int EVENT_METERED_DENYLIST_CHANGED = 16; private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE); private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE); @@ -89,7 +91,7 @@ public class NetworkPolicyLogger { void networkBlocked(int uid, @Nullable UidBlockedState uidBlockedState) { synchronized (mLock) { if (LOGD || uid == mDebugUid) { - Slog.d(TAG, "Blocked state of uid: " + uidBlockedState.toString()); + Slog.d(TAG, "Blocked state of " + uid + ": " + uidBlockedState.toString()); } if (uidBlockedState == null) { mNetworkBlockedBuffer.networkBlocked(uid, BLOCKED_REASON_NONE, ALLOWED_REASON_NONE, @@ -245,6 +247,24 @@ public class NetworkPolicyLogger { } } + void meteredAllowlistChanged(int uid, boolean added) { + synchronized (mLock) { + if (LOGD || mDebugUid == uid) { + Slog.d(TAG, getMeteredAllowlistChangedLog(uid, added)); + } + mEventsBuffer.meteredAllowlistChanged(uid, added); + } + } + + void meteredDenylistChanged(int uid, boolean added) { + synchronized (mLock) { + if (LOGD || mDebugUid == uid) { + Slog.d(TAG, getMeteredDenylistChangedLog(uid, added)); + } + mEventsBuffer.meteredDenylistChanged(uid, added); + } + } + void setDebugUid(int uid) { mDebugUid = uid; } @@ -320,6 +340,14 @@ public class NetworkPolicyLogger { return "Firewall chain " + getFirewallChainName(chain) + " state: " + enabled; } + private static String getMeteredAllowlistChangedLog(int uid, boolean added) { + return "metered-allowlist for " + uid + " changed to " + added; + } + + private static String getMeteredDenylistChangedLog(int uid, boolean added) { + return "metered-denylist for " + uid + " changed to " + added; + } + private static String getFirewallChainName(int chain) { switch (chain) { case FIREWALL_CHAIN_DOZABLE: @@ -520,6 +548,28 @@ public class NetworkPolicyLogger { data.timeStamp = System.currentTimeMillis(); } + public void meteredAllowlistChanged(int uid, boolean added) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + data.type = EVENT_METERED_ALLOWLIST_CHANGED; + data.ifield1 = uid; + data.bfield1 = added; + data.timeStamp = System.currentTimeMillis(); + } + + public void meteredDenylistChanged(int uid, boolean added) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + data.type = EVENT_METERED_DENYLIST_CHANGED; + data.ifield1 = uid; + data.bfield1 = added; + data.timeStamp = System.currentTimeMillis(); + } + public void reverseDump(IndentingPrintWriter pw) { final Data[] allData = toArray(); for (int i = allData.length - 1; i >= 0; --i) { @@ -567,6 +617,10 @@ public class NetworkPolicyLogger { return getUidFirewallRuleChangedLog(data.ifield1, data.ifield2, data.ifield3); case EVENT_FIREWALL_CHAIN_ENABLED: return getFirewallChainEnabledLog(data.ifield1, data.bfield1); + case EVENT_METERED_ALLOWLIST_CHANGED: + return getMeteredAllowlistChangedLog(data.ifield1, data.bfield1); + case EVENT_METERED_DENYLIST_CHANGED: + return getMeteredDenylistChangedLog(data.ifield1, data.bfield1); default: return String.valueOf(data.type); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index ea851ba9669f..0c47efe57563 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -26,6 +26,9 @@ import static android.Manifest.permission.NETWORK_STACK; import static android.Manifest.permission.OBSERVE_NETWORK_POLICY; import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; +import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; +import static android.app.ActivityManager.isProcStateConsideredInteraction; +import static android.app.ActivityManager.procStateToString; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import static android.content.Intent.ACTION_PACKAGE_ADDED; @@ -90,6 +93,8 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; +import static android.net.NetworkPolicyManager.allowedReasonsToString; +import static android.net.NetworkPolicyManager.blockedReasonsToString; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileInLowPowerStandby; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; @@ -160,6 +165,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; @@ -418,6 +424,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20; + // TODO: Add similar docs for other messages. /** * Message to indicate that reasons for why an uid is blocked changed. @@ -425,7 +432,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * arg2 = newBlockedReasons * obj = oldBlockedReasons */ - private static final int MSG_BLOCKED_REASON_CHANGED = 21; + private static final int MSG_UID_BLOCKED_REASON_CHANGED = 21; + /** * Message to indicate that subscription plans expired and should be cleared. * arg1 = subId @@ -434,6 +442,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ private static final int MSG_CLEAR_SUBSCRIPTION_PLANS = 22; + /** + * Message to indicate that reasons for why some uids are blocked changed. + * obj = SparseArray<SomeArgs> where key = uid and value = SomeArgs object with + * value.argi1 = oldEffectiveBlockedReasons, + * value.argi2 = newEffectiveBlockedReasons, + * value.argi3 = uidRules + */ + private static final int MSG_UIDS_BLOCKED_REASONS_CHANGED = 23; + private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -471,7 +488,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final Object mUidRulesFirstLock = new Object(); final Object mNetworkPoliciesSecondLock = new Object(); - @GuardedBy({"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"}) + @GuardedBy(anyOf = {"mUidRulesFirstLock", "mNetworkPoliciesSecondLock"}) volatile boolean mSystemReady; @GuardedBy("mUidRulesFirstLock") volatile boolean mRestrictBackground; @@ -594,7 +611,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private final SparseArray<UidState> mUidState = new SparseArray<>(); - @GuardedBy("mUidRulesFirstLock") + @GuardedBy("mUidBlockedState") private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>(); /** Objects used temporarily while computing the new blocked state for each uid. */ @@ -909,6 +926,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); mAppStandby = LocalServices.getService(AppStandbyInternal.class); + mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { @@ -986,12 +1004,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); try { final int changes = ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_CAPABILITY; - mActivityManager.registerUidObserver(mUidObserver, changes, + mActivityManagerInternal.registerNetworkPolicyUidObserver(mUidObserver, changes, NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android"); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { @@ -1107,7 +1124,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { callbackInfo = new UidStateCallbackInfo(); mUidStateCallbackInfos.put(uid, callbackInfo); } - callbackInfo.update(uid, procState, procStateSeq, capability); + if (callbackInfo.procStateSeq == -1 || procStateSeq > callbackInfo.procStateSeq) { + callbackInfo.update(uid, procState, procStateSeq, capability); + } if (!callbackInfo.isPending) { mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo) .sendToTarget(); @@ -1131,8 +1150,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final class UidStateCallbackInfo { public int uid; - public int procState; - public long procStateSeq; + public int procState = ActivityManager.PROCESS_STATE_NONEXISTENT; + public long procStateSeq = -1; @ProcessCapability public int capability; public boolean isPending; @@ -3298,7 +3317,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (mSystemReady) { // Device idle change means we need to rebuild rules for all // known apps, so do a global refresh. - updateRulesForRestrictPowerUL(); + handleDeviceIdleModeChangedUL(enabled); } } if (enabled) { @@ -3947,7 +3966,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final SparseBooleanArray knownUids = new SparseBooleanArray(); collectKeys(mUidState, knownUids); - collectKeys(mUidBlockedState, knownUids); + synchronized (mUidBlockedState) { + collectKeys(mUidBlockedState, knownUids); + } fout.println("Status for all known UIDs:"); fout.increaseIndent(); @@ -3965,12 +3986,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print(uidState.toString()); } - final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); - if (uidBlockedState == null) { - fout.print(" blocked_state={null}"); - } else { - fout.print(" blocked_state="); - fout.print(uidBlockedState.toString()); + synchronized (mUidBlockedState) { + final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + fout.print(" blocked_state={null}"); + } else { + fout.print(" blocked_state="); + fout.print(uidBlockedState); + } } fout.println(); } @@ -4038,13 +4061,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * {@link #updateRulesForPowerRestrictionsUL(int)}. Returns true if the state was updated. */ @GuardedBy("mUidRulesFirstLock") - private boolean updateUidStateUL(int uid, int procState, @ProcessCapability int capability) { + private boolean updateUidStateUL(int uid, int procState, long procStateSeq, + @ProcessCapability int capability) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL"); try { final UidState oldUidState = mUidState.get(uid); + if (oldUidState != null && procStateSeq < oldUidState.procStateSeq) { + if (LOGV) { + Slog.v(TAG, "Ignoring older uid state updates; uid=" + uid + + ",procState=" + procStateToString(procState) + ",seq=" + procStateSeq + + ",cap=" + capability + ",oldUidState=" + oldUidState); + } + return false; + } if (oldUidState == null || oldUidState.procState != procState || oldUidState.capability != capability) { - final UidState newUidState = new UidState(uid, procState, capability); + final UidState newUidState = new UidState(uid, procState, procStateSeq, capability); // state changed, push updated rules mUidState.put(uid, newUidState); updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, newUidState); @@ -4052,14 +4084,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState) != isProcStateAllowedWhileIdleOrPowerSaveMode(newUidState); if (allowedWhileIdleOrPowerSaveModeChanged) { - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, procState); if (mDeviceIdleMode) { updateRuleForDeviceIdleUL(uid); } if (mRestrictPower) { updateRuleForRestrictPowerUL(uid); } - updateRulesForPowerRestrictionsUL(uid); + updateRulesForPowerRestrictionsUL(uid, procState); } if (mLowPowerStandbyActive) { boolean allowedInLpsChanged = @@ -4067,7 +4099,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { != isProcStateAllowedWhileInLowPowerStandby(newUidState); if (allowedInLpsChanged) { if (!allowedWhileIdleOrPowerSaveModeChanged) { - updateRulesForPowerRestrictionsUL(uid); + updateRulesForPowerRestrictionsUL(uid, procState); } updateRuleForLowPowerStandbyUL(uid); } @@ -4145,9 +4177,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidFirewallRestrictedModeRules.clear(); forEachUid("updateRestrictedModeAllowlist", uid -> { synchronized (mUidRulesFirstLock) { - final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL( + final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL( uid); - final int newFirewallRule = getRestrictedModeFirewallRule(uidBlockedState); + final int newFirewallRule = getRestrictedModeFirewallRule(effectiveBlockedReasons); // setUidFirewallRulesUL will allowlist all uids that are passed to it, so only add // non-default rules. @@ -4167,7 +4199,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @VisibleForTesting @GuardedBy("mUidRulesFirstLock") void updateRestrictedModeForUidUL(int uid) { - final UidBlockedState uidBlockedState = updateBlockedReasonsForRestrictedModeUL(uid); + final int effectiveBlockedReasons = updateBlockedReasonsForRestrictedModeUL(uid); // if restricted networking mode is on, and the app has an access exemption, the uid rule // will not change, but the firewall rule will have to be updated. @@ -4175,37 +4207,48 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Note: setUidFirewallRule also updates mUidFirewallRestrictedModeRules. // In this case, default firewall rules can also be added. setUidFirewallRuleUL(FIREWALL_CHAIN_RESTRICTED, uid, - getRestrictedModeFirewallRule(uidBlockedState)); + getRestrictedModeFirewallRule(effectiveBlockedReasons)); } } @GuardedBy("mUidRulesFirstLock") - private UidBlockedState updateBlockedReasonsForRestrictedModeUL(int uid) { - final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( - mUidBlockedState, uid); - final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; - if (mRestrictedNetworkingMode) { - uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE; - } else { - uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE; - } - if (hasRestrictedModeAccess(uid)) { - uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; - } else { - uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + private int updateBlockedReasonsForRestrictedModeUL(int uid) { + final boolean hasRestrictedModeAccess = hasRestrictedModeAccess(uid); + final int oldEffectiveBlockedReasons; + final int newEffectiveBlockedReasons; + final int uidRules; + synchronized (mUidBlockedState) { + final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( + mUidBlockedState, uid); + oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + if (mRestrictedNetworkingMode) { + uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE; + } else { + uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE; + } + if (hasRestrictedModeAccess) { + uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + } else { + uidBlockedState.allowedReasons &= ~ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + } + uidBlockedState.updateEffectiveBlockedReasons(); + + newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons + ? RULE_NONE + : uidBlockedState.deriveUidRules(); } - uidBlockedState.updateEffectiveBlockedReasons(); - if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { - postBlockedReasonsChangedMsg(uid, - uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons); + if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) { + handleBlockedReasonsChanged(uid, + newEffectiveBlockedReasons, oldEffectiveBlockedReasons); - postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules()); + postUidRulesChangedMsg(uid, uidRules); } - return uidBlockedState; + return newEffectiveBlockedReasons; } - private static int getRestrictedModeFirewallRule(UidBlockedState uidBlockedState) { - if ((uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) { + private static int getRestrictedModeFirewallRule(int effectiveBlockedReasons) { + if ((effectiveBlockedReasons & BLOCKED_REASON_RESTRICTED_MODE) != 0) { // rejected in restricted mode, this is the default behavior. return FIREWALL_RULE_DEFAULT; } else { @@ -4309,12 +4352,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidFirewallLowPowerStandbyModeRules.clear(); for (int i = mUidState.size() - 1; i >= 0; i--) { final int uid = mUidState.keyAt(i); - UidBlockedState uidBlockedState = mUidBlockedState.get(uid); - if (hasInternetPermissionUL(uid) && uidBlockedState != null - && (uidBlockedState.effectiveBlockedReasons + final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid); + if (hasInternetPermissionUL(uid) && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) { - mUidFirewallLowPowerStandbyModeRules.put(mUidBlockedState.keyAt(i), - FIREWALL_RULE_ALLOW); + mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW); } } setUidFirewallRulesUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, @@ -4333,10 +4374,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return; } - final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); - if (mUidState.contains(uid) && uidBlockedState != null - && (uidBlockedState.effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) - == 0) { + final int effectiveBlockedReasons = getEffectiveBlockedReasons(uid); + if (mUidState.contains(uid) + && (effectiveBlockedReasons & BLOCKED_REASON_LOW_POWER_STANDBY) == 0) { mUidFirewallLowPowerStandbyModeRules.put(uid, FIREWALL_RULE_ALLOW); setUidFirewallRuleUL(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, FIREWALL_RULE_ALLOW); } else { @@ -4428,7 +4468,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @GuardedBy("mUidRulesFirstLock") - void updateRuleForAppIdleUL(int uid) { + void updateRuleForAppIdleUL(int uid, int uidProcessState) { if (!isUidValidForDenylistRulesUL(uid)) return; if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { @@ -4436,7 +4476,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } try { int appId = UserHandle.getAppId(uid); - if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid) + if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid, uidProcessState) && !isUidForegroundOnRestrictPowerUL(uid)) { setUidFirewallRuleUL(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY); if (LOGD) Log.d(TAG, "updateRuleForAppIdleUL DENY " + uid); @@ -4465,9 +4505,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (!isUidValidForDenylistRulesUL(uid)) { continue; } - final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( - mUidBlockedState, uid); - if (!enableChain && (uidBlockedState.blockedReasons & ~BLOCKED_METERED_REASON_MASK) + final int blockedReasons = getBlockedReasons(uid); + if (!enableChain && (blockedReasons & ~BLOCKED_METERED_REASON_MASK) == BLOCKED_REASON_NONE) { // Chain isn't enabled and the uid had no restrictions to begin with. continue; @@ -4512,6 +4551,71 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + @GuardedBy("mUidRulesFirstLock") + private void handleDeviceIdleModeChangedUL(boolean enabled) { + Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL"); + try { + updateRulesForDeviceIdleUL(); + if (enabled) { + forEachUid("updateRulesForRestrictPower", uid -> { + synchronized (mUidRulesFirstLock) { + updateRulesForPowerRestrictionsUL(uid); + } + }); + } else { + // TODO: Note that we could handle the case of enabling-doze state similar + // to this but first, we need to update how we listen to uid state changes + // so that we always get a callback when a process moves from a NONEXISTENT state + // to a "background" state. + handleDeviceIdleModeDisabledUL(); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_NETWORK); + } + } + + @GuardedBy("mUidRulesFirstLock") + private void handleDeviceIdleModeDisabledUL() { + Trace.traceBegin(TRACE_TAG_NETWORK, "handleDeviceIdleModeDisabledUL"); + try { + final SparseArray<SomeArgs> uidStateUpdates = new SparseArray<>(); + synchronized (mUidBlockedState) { + final int size = mUidBlockedState.size(); + for (int i = 0; i < size; ++i) { + final int uid = mUidBlockedState.keyAt(i); + final UidBlockedState uidBlockedState = mUidBlockedState.valueAt(i); + if ((uidBlockedState.blockedReasons & BLOCKED_REASON_DOZE) == 0) { + continue; + } + uidBlockedState.blockedReasons &= ~BLOCKED_REASON_DOZE; + final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + uidBlockedState.updateEffectiveBlockedReasons(); + if (LOGV) { + Log.v(TAG, "handleDeviceIdleModeDisabled(" + uid + "); " + + "newUidBlockedState=" + uidBlockedState + + ", oldEffectiveBlockedReasons=" + oldEffectiveBlockedReasons); + } + if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { + final SomeArgs someArgs = SomeArgs.obtain(); + someArgs.argi1 = oldEffectiveBlockedReasons; + someArgs.argi2 = uidBlockedState.effectiveBlockedReasons; + someArgs.argi3 = uidBlockedState.deriveUidRules(); + uidStateUpdates.append(uid, someArgs); + // TODO: Update the state for all changed uids together. + mActivityManagerInternal.onUidBlockedReasonsChanged(uid, + uidBlockedState.effectiveBlockedReasons); + } + } + } + if (uidStateUpdates.size() != 0) { + mHandler.obtainMessage(MSG_UIDS_BLOCKED_REASONS_CHANGED, uidStateUpdates) + .sendToTarget(); + } + } finally { + Trace.traceEnd(TRACE_TAG_NETWORK); + } + } + // TODO: rename / document to make it clear these are global (not app-specific) rules @GuardedBy("mUidRulesFirstLock") private void updateRulesForRestrictPowerUL() { @@ -4543,9 +4647,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } try { // update rules for all installed applications - final PackageManager pm = mContext.getPackageManager(); final List<UserInfo> users; - final List<ApplicationInfo> apps; Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "list-users"); try { @@ -4553,26 +4655,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } - Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "list-uids"); + Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "iterate-uids"); try { - apps = pm.getInstalledApplications( - PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS - | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); + final PackageManagerInternal packageManagerInternal = LocalServices.getService( + PackageManagerInternal.class); + final int usersSize = users.size(); + for (int i = 0; i < usersSize; ++i) { + final int userId = users.get(i).id; + final SparseBooleanArray sharedAppIdsHandled = new SparseBooleanArray(); + packageManagerInternal.forEachInstalledPackage(androidPackage -> { + final int appId = androidPackage.getUid(); + if (androidPackage.getSharedUserId() != null) { + if (sharedAppIdsHandled.indexOfKey(appId) < 0) { + sharedAppIdsHandled.put(appId, true); + } else { + return; + } + } + final int uid = UserHandle.getUid(userId, appId); + consumer.accept(uid); + }, userId); + } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } - - final int usersSize = users.size(); - final int appsSize = apps.size(); - for (int i = 0; i < usersSize; i++) { - final UserInfo user = users.get(i); - for (int j = 0; j < appsSize; j++) { - final ApplicationInfo app = apps.get(j); - final int uid = UserHandle.getUid(user.id, app.uid); - consumer.accept(uid); - } - } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } @@ -4586,7 +4692,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final UserInfo user = users.get(i); int uid = UserHandle.getUid(user.id, appId); // Update external firewall rules. - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRuleForDeviceIdleUL(uid); updateRuleForRestrictPowerUL(uid); // Update internal rules. @@ -4634,7 +4740,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } else { mAppIdleTempWhitelistAppIds.delete(uid); } - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRulesForPowerRestrictionsUL(uid); } finally { Binder.restoreCallingIdentity(token); @@ -4660,7 +4766,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Returns if the UID is currently considered idle. */ @VisibleForTesting boolean isUidIdle(int uid) { + return isUidIdle(uid, PROCESS_STATE_UNKNOWN); + } + + private boolean isUidIdle(int uid, int uidProcessState) { synchronized (mUidRulesFirstLock) { + if (uidProcessState != PROCESS_STATE_UNKNOWN && isProcStateConsideredInteraction( + uidProcessState)) { + return false; + } if (mAppIdleTempWhitelistAppIds.get(uid)) { // UID is temporarily allowlisted. return false; @@ -4709,7 +4823,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private void onUidDeletedUL(int uid) { // First cleanup in-memory state synchronously... - mUidBlockedState.delete(uid); + synchronized (mUidBlockedState) { + mUidBlockedState.delete(uid); + } + mUidState.delete(uid); + mActivityManagerInternal.onUidBlockedReasonsChanged(uid, BLOCKED_REASON_NONE); mUidPolicy.delete(uid); mUidFirewallStandbyRules.delete(uid); mUidFirewallDozableRules.delete(uid); @@ -4745,7 +4863,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateRestrictionRulesForUidUL(int uid) { // Methods below only changes the firewall rules for the power-related modes. updateRuleForDeviceIdleUL(uid); - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRuleForRestrictPowerUL(uid); // If the uid has the necessary permissions, then it should be added to the restricted mode @@ -4821,11 +4939,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE); final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); - final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( - mUidBlockedState, uid); - final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid( - mTmpUidBlockedState, uid); - previousUidBlockedState.copyFrom(uidBlockedState); final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; @@ -4840,18 +4953,47 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0); newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0); - uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons - & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons; - uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons - & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons; - uidBlockedState.updateEffectiveBlockedReasons(); - final int oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons; - final int newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + final int oldEffectiveBlockedReasons; + final int newEffectiveBlockedReasons; + final int oldAllowedReasons; + final int uidRules; + synchronized (mUidBlockedState) { + final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( + mUidBlockedState, uid); + final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid( + mTmpUidBlockedState, uid); + previousUidBlockedState.copyFrom(uidBlockedState); + + uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons + & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons; + uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons + & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons; + uidBlockedState.updateEffectiveBlockedReasons(); + + oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons; + newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + oldAllowedReasons = previousUidBlockedState.allowedReasons; + uidRules = (oldEffectiveBlockedReasons == newEffectiveBlockedReasons) + ? RULE_NONE : uidBlockedState.deriveUidRules(); + + if (LOGV) { + Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" + + ": isForeground=" + isForeground + + ", isDenied=" + isDenied + + ", isAllowed=" + isAllowed + + ", isRestrictedByAdmin=" + isRestrictedByAdmin + + ", oldBlockedState=" + previousUidBlockedState + + ", newBlockedState=" + uidBlockedState + + ", newBlockedMeteredReasons=" + blockedReasonsToString(newBlockedReasons) + + ", newAllowedMeteredReasons=" + allowedReasonsToString( + newAllowedReasons)); + } + } if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) { - postBlockedReasonsChangedMsg(uid, + handleBlockedReasonsChanged(uid, newEffectiveBlockedReasons, oldEffectiveBlockedReasons); - postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules()); + postUidRulesChangedMsg(uid, uidRules); } // Note that the conditionals below are for avoiding unnecessary calls to netd. @@ -4867,29 +5009,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } final int allowlistReasons = ALLOWED_METERED_REASON_FOREGROUND | ALLOWED_METERED_REASON_USER_EXEMPTED; - final int oldAllowedReasons = previousUidBlockedState.allowedReasons; if ((oldAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE || (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE) { setMeteredNetworkAllowlist(uid, (newAllowedReasons & allowlistReasons) != ALLOWED_REASON_NONE); } - - if (LOGV) { - Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" - + ": isForeground=" +isForeground - + ", isDenied=" + isDenied - + ", isAllowed=" + isAllowed - + ", isRestrictedByAdmin=" + isRestrictedByAdmin - + ", oldBlockedState=" + previousUidBlockedState.toString() - + ", newBlockedState=" - + ", oldBlockedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString( - uidBlockedState.blockedReasons & BLOCKED_METERED_REASON_MASK) - + ", oldBlockedMeteredEffectiveReasons=" - + NetworkPolicyManager.blockedReasonsToString( - uidBlockedState.effectiveBlockedReasons & BLOCKED_METERED_REASON_MASK) - + ", oldAllowedMeteredReasons=" + NetworkPolicyManager.blockedReasonsToString( - uidBlockedState.allowedReasons & BLOCKED_METERED_REASON_MASK)); - } } /** @@ -4913,7 +5037,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ @GuardedBy("mUidRulesFirstLock") private void updateRulesForPowerRestrictionsUL(int uid) { - updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid)); + updateRulesForPowerRestrictionsUL(uid, PROCESS_STATE_UNKNOWN); + } + + @GuardedBy("mUidRulesFirstLock") + private void updateRulesForPowerRestrictionsUL(int uid, int uidProcState) { + updateRulesForPowerRestrictionsUL(uid, isUidIdle(uid, uidProcState)); } /** @@ -4949,56 +5078,66 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode); - final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( - mUidBlockedState, uid); - final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid( - mTmpUidBlockedState, uid); - previousUidBlockedState.copyFrom(uidBlockedState); + final int oldEffectiveBlockedReasons; + final int newEffectiveBlockedReasons; + final int uidRules; + synchronized (mUidBlockedState) { + final UidBlockedState uidBlockedState = getOrCreateUidBlockedStateForUid( + mUidBlockedState, uid); + final UidBlockedState previousUidBlockedState = getOrCreateUidBlockedStateForUid( + mTmpUidBlockedState, uid); + previousUidBlockedState.copyFrom(uidBlockedState); + + int newBlockedReasons = BLOCKED_REASON_NONE; + int newAllowedReasons = ALLOWED_REASON_NONE; + newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0); + newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0); + newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0); + newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0); + newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE); + + newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); + newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0); + newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true) + ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0); + newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid) + ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0); + newAllowedReasons |= (uidBlockedState.allowedReasons + & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS); + newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid)) + ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0; + + uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons + & BLOCKED_METERED_REASON_MASK) | newBlockedReasons; + uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons + & ALLOWED_METERED_REASON_MASK) | newAllowedReasons; + uidBlockedState.updateEffectiveBlockedReasons(); - int newBlockedReasons = BLOCKED_REASON_NONE; - int newAllowedReasons = ALLOWED_REASON_NONE; - newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0); - newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0); - newBlockedReasons |= (mLowPowerStandbyActive ? BLOCKED_REASON_LOW_POWER_STANDBY : 0); - newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0); - newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE); - - newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); - newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); - newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0); - newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true) - ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0); - newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid) - ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0); - newAllowedReasons |= (uidBlockedState.allowedReasons - & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS); - newAllowedReasons |= (isAllowlistedFromLowPowerStandbyUL(uid)) - ? ALLOWED_REASON_LOW_POWER_STANDBY_ALLOWLIST : 0; - - uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons - & BLOCKED_METERED_REASON_MASK) | newBlockedReasons; - uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons - & ALLOWED_METERED_REASON_MASK) | newAllowedReasons; - uidBlockedState.updateEffectiveBlockedReasons(); - if (previousUidBlockedState.effectiveBlockedReasons - != uidBlockedState.effectiveBlockedReasons) { - postBlockedReasonsChangedMsg(uid, - uidBlockedState.effectiveBlockedReasons, - previousUidBlockedState.effectiveBlockedReasons); - - postUidRulesChangedMsg(uid, uidBlockedState.deriveUidRules()); - } - - if (LOGV) { - Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")" - + ", isIdle: " + isUidIdle - + ", mRestrictPower: " + mRestrictPower - + ", mDeviceIdleMode: " + mDeviceIdleMode - + ", isForeground=" + isForeground - + ", isTop=" + isTop - + ", isWhitelisted=" + isWhitelisted - + ", oldUidBlockedState=" + previousUidBlockedState.toString() - + ", newUidBlockedState=" + uidBlockedState.toString()); + if (LOGV) { + Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")" + + ", isIdle: " + isUidIdle + + ", mRestrictPower: " + mRestrictPower + + ", mDeviceIdleMode: " + mDeviceIdleMode + + ", isForeground=" + isForeground + + ", isTop=" + isTop + + ", isWhitelisted=" + isWhitelisted + + ", oldUidBlockedState=" + previousUidBlockedState + + ", newUidBlockedState=" + uidBlockedState); + } + + oldEffectiveBlockedReasons = previousUidBlockedState.effectiveBlockedReasons; + newEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + uidRules = oldEffectiveBlockedReasons == newEffectiveBlockedReasons + ? RULE_NONE + : uidBlockedState.deriveUidRules(); + } + if (oldEffectiveBlockedReasons != newEffectiveBlockedReasons) { + handleBlockedReasonsChanged(uid, + newEffectiveBlockedReasons, + oldEffectiveBlockedReasons); + + postUidRulesChangedMsg(uid, uidRules); } } @@ -5011,7 +5150,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); synchronized (mUidRulesFirstLock) { mLogger.appIdleStateChanged(uid, idle); - updateRuleForAppIdleUL(uid); + updateRuleForAppIdleUL(uid, PROCESS_STATE_UNKNOWN); updateRulesForPowerRestrictionsUL(uid); } } catch (NameNotFoundException nnfe) { @@ -5027,9 +5166,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void handleBlockedReasonsChanged(int uid, int newEffectiveBlockedReasons, + int oldEffectiveBlockedReasons) { + mActivityManagerInternal.onUidBlockedReasonsChanged(uid, newEffectiveBlockedReasons); + postBlockedReasonsChangedMsg(uid, newEffectiveBlockedReasons, oldEffectiveBlockedReasons); + } + private void postBlockedReasonsChangedMsg(int uid, int newEffectiveBlockedReasons, int oldEffectiveBlockedReasons) { - mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, + mHandler.obtainMessage(MSG_UID_BLOCKED_REASON_CHANGED, uid, newEffectiveBlockedReasons, oldEffectiveBlockedReasons) .sendToTarget(); } @@ -5276,7 +5421,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } return true; } - case MSG_BLOCKED_REASON_CHANGED: { + case MSG_UID_BLOCKED_REASON_CHANGED: { final int uid = msg.arg1; final int newBlockedReasons = msg.arg2; final int oldBlockedReasons = (int) msg.obj; @@ -5289,6 +5434,35 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } + case MSG_UIDS_BLOCKED_REASONS_CHANGED: { + final SparseArray<SomeArgs> uidStateUpdates = (SparseArray<SomeArgs>) msg.obj; + final int uidsSize = uidStateUpdates.size(); + final int listenersSize = mListeners.beginBroadcast(); + for (int i = 0; i < listenersSize; ++i) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + for (int uidIndex = 0; uidIndex < uidsSize; ++uidIndex) { + final int uid = uidStateUpdates.keyAt(uidIndex); + final SomeArgs someArgs = uidStateUpdates.valueAt(uidIndex); + final int oldBlockedReasons = someArgs.argi1; + final int newBlockedReasons = someArgs.argi2; + final int uidRules = someArgs.argi3; + + dispatchBlockedReasonChanged(listener, uid, + oldBlockedReasons, newBlockedReasons); + if (LOGV) { + Slog.v(TAG, "Dispatching rules=" + uidRulesToString(uidRules) + + " for uid=" + uid); + } + dispatchUidRulesChanged(listener, uid, uidRules); + } + } + mListeners.finishBroadcast(); + + for (int uidIndex = 0; uidIndex < uidsSize; ++uidIndex) { + uidStateUpdates.valueAt(uidIndex).recycle(); + } + return true; + } default: { return false; } @@ -5301,21 +5475,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public boolean handleMessage(Message msg) { switch (msg.what) { case UID_MSG_STATE_CHANGED: { - final UidStateCallbackInfo uidStateCallbackInfo = - (UidStateCallbackInfo) msg.obj; - final int uid; - final int procState; - final long procStateSeq; - final int capability; - synchronized (mUidStateCallbackInfos) { - uid = uidStateCallbackInfo.uid; - procState = uidStateCallbackInfo.procState; - procStateSeq = uidStateCallbackInfo.procStateSeq; - capability = uidStateCallbackInfo.capability; - uidStateCallbackInfo.isPending = false; - } - - handleUidChanged(uid, procState, procStateSeq, capability); + handleUidChanged((UidStateCallbackInfo) msg.obj); return true; } case UID_MSG_GONE: { @@ -5330,17 +5490,28 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - void handleUidChanged(int uid, int procState, long procStateSeq, - @ProcessCapability int capability) { + void handleUidChanged(@NonNull UidStateCallbackInfo uidStateCallbackInfo) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged"); try { boolean updated; + final int uid; + final int procState; + final long procStateSeq; + final int capability; synchronized (mUidRulesFirstLock) { + synchronized (mUidStateCallbackInfos) { + uid = uidStateCallbackInfo.uid; + procState = uidStateCallbackInfo.procState; + procStateSeq = uidStateCallbackInfo.procStateSeq; + capability = uidStateCallbackInfo.capability; + uidStateCallbackInfo.isPending = false; + } + // We received a uid state change callback, add it to the history so that it // will be useful for debugging. mLogger.uidStateChanged(uid, procState, procStateSeq, capability); // Now update the network policy rules as per the updated uid state. - updated = updateUidStateUL(uid, procState, capability); + updated = updateUidStateUL(uid, procState, procStateSeq, capability); // Updating the network rules is done, so notify AMS about this. mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq); } @@ -5437,6 +5608,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable); try { mNetworkManager.setUidOnMeteredNetworkDenylist(uid, enable); + mLogger.meteredDenylistChanged(uid, enable); + if (Process.isApplicationUid(uid)) { + final int sdkSandboxUid = Process.toSdkSandboxUid(uid); + mNetworkManager.setUidOnMeteredNetworkDenylist(sdkSandboxUid, enable); + mLogger.meteredDenylistChanged(sdkSandboxUid, enable); + } } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e); } catch (RemoteException e) { @@ -5448,6 +5625,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable); try { mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, enable); + mLogger.meteredAllowlistChanged(uid, enable); + if (Process.isApplicationUid(uid)) { + final int sdkSandboxUid = Process.toSdkSandboxUid(uid); + mNetworkManager.setUidOnMeteredNetworkAllowlist(sdkSandboxUid, enable); + mLogger.meteredAllowlistChanged(sdkSandboxUid, enable); + } } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e); } catch (RemoteException e) { @@ -5486,12 +5669,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void addSdkSandboxUidsIfNeeded(SparseIntArray uidRules) { + final int size = uidRules.size(); + final SparseIntArray sdkSandboxUids = new SparseIntArray(); + for (int index = 0; index < size; index++) { + final int uid = uidRules.keyAt(index); + final int rule = uidRules.valueAt(index); + if (Process.isApplicationUid(uid)) { + sdkSandboxUids.put(Process.toSdkSandboxUid(uid), rule); + } + } + + for (int index = 0; index < sdkSandboxUids.size(); index++) { + final int uid = sdkSandboxUids.keyAt(index); + final int rule = sdkSandboxUids.valueAt(index); + uidRules.put(uid, rule); + } + } + /** * Set uid rules on a particular firewall chain. This is going to synchronize the rules given * here to netd. It will clean up dead rules and make sure the target chain only contains rules * specified here. */ private void setUidFirewallRulesUL(int chain, SparseIntArray uidRules) { + addSdkSandboxUidsIfNeeded(uidRules); try { int size = uidRules.size(); int[] uids = new int[size]; @@ -5534,6 +5736,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { try { mNetworkManager.setFirewallUidRule(chain, uid, rule); mLogger.uidFirewallRuleChanged(chain, uid, rule); + if (Process.isApplicationUid(uid)) { + final int sdkSandboxUid = Process.toSdkSandboxUid(uid); + mNetworkManager.setFirewallUidRule(chain, sdkSandboxUid, rule); + mLogger.uidFirewallRuleChanged(chain, sdkSandboxUid, rule); + } } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting firewall uid rules", e); } catch (RemoteException e) { @@ -5570,22 +5777,28 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ private void resetUidFirewallRules(int uid) { try { - mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT); - mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); - mNetworkManager - .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT); - mNetworkManager - .setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, FIREWALL_RULE_DEFAULT); - mNetworkManager - .setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, - FIREWALL_RULE_DEFAULT); + mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_DOZABLE, uid, + FIREWALL_RULE_DEFAULT); + mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, + FIREWALL_RULE_DEFAULT); + mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, + FIREWALL_RULE_DEFAULT); + mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_RESTRICTED, uid, + FIREWALL_RULE_DEFAULT); + mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, uid, + FIREWALL_RULE_DEFAULT); mNetworkManager.setUidOnMeteredNetworkAllowlist(uid, false); + mLogger.meteredAllowlistChanged(uid, false); mNetworkManager.setUidOnMeteredNetworkDenylist(uid, false); + mLogger.meteredDenylistChanged(uid, false); } catch (IllegalStateException e) { Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e); } catch (RemoteException e) { // ignored; service lives in system_server } + if (Process.isApplicationUid(uid)) { + resetUidFirewallRules(Process.toSdkSandboxUid(uid)); + } } @Deprecated @@ -5745,7 +5958,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG); int blockedReasons; - synchronized (mUidRulesFirstLock) { + synchronized (mUidBlockedState) { final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); blockedReasons = uidBlockedState == null ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons; @@ -5763,7 +5976,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public boolean isUidRestrictedOnMeteredNetworks(int uid) { mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG); - synchronized (mUidRulesFirstLock) { + synchronized (mUidBlockedState) { final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); int blockedReasons = uidBlockedState == null ? BLOCKED_REASON_NONE : uidBlockedState.effectiveBlockedReasons; @@ -6011,10 +6224,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return restrictedUids != null && restrictedUids.contains(uid); } - private static boolean hasRule(int uidRules, int rule) { - return (uidRules & rule) != 0; - } - private static boolean getBooleanDefeatingNullable(@Nullable PersistableBundle bundle, String key, boolean defaultValue) { return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue; @@ -6030,16 +6239,39 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return uidBlockedState; } + private int getEffectiveBlockedReasons(int uid) { + synchronized (mUidBlockedState) { + final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + return uidBlockedState == null + ? BLOCKED_REASON_NONE + : uidBlockedState.effectiveBlockedReasons; + } + } + + private int getBlockedReasons(int uid) { + synchronized (mUidBlockedState) { + final UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + return uidBlockedState == null + ? BLOCKED_REASON_NONE + : uidBlockedState.blockedReasons; + } + } + @VisibleForTesting static final class UidBlockedState { public int blockedReasons; public int allowedReasons; public int effectiveBlockedReasons; + private UidBlockedState(int blockedReasons, int allowedReasons, + int effectiveBlockedReasons) { + this.blockedReasons = blockedReasons; + this.allowedReasons = allowedReasons; + this.effectiveBlockedReasons = effectiveBlockedReasons; + } + UidBlockedState() { - blockedReasons = BLOCKED_REASON_NONE; - allowedReasons = ALLOWED_REASON_NONE; - effectiveBlockedReasons = BLOCKED_REASON_NONE; + this(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE, BLOCKED_REASON_NONE); } void updateEffectiveBlockedReasons() { @@ -6276,7 +6508,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } if (LOGV) { - Slog.v(TAG, "uidBlockedState=" + this.toString() + Slog.v(TAG, "uidBlockedState=" + this + " -> uidRule=" + uidRulesToString(uidRule)); } return uidRule; diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 3ccb06ccef15..ab8527e7ec41 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1123,7 +1123,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio /** Makes the process have top state before oom-adj is computed from a posted message. */ void addToPendingTop() { - mAtm.mAmInternal.addPendingTopUid(mUid, mPid); + mAtm.mAmInternal.addPendingTopUid(mUid, mPid, mThread); } void updateServiceConnectionActivities() { @@ -1176,7 +1176,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } // update ActivityManagerService.PendingStartActivityUids list. if (topProcessState == ActivityManager.PROCESS_STATE_TOP) { - mAtm.mAmInternal.addPendingTopUid(mUid, mPid); + mAtm.mAmInternal.addPendingTopUid(mUid, mPid, mThread); } prepareOomAdjustment(); // Posting the message at the front of queue so WM lock isn't held when we call into AM, diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java index 8c21a39c20d1..16406bcb9a1f 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerInternalTest.java @@ -129,7 +129,7 @@ public class ActivityManagerInternalTest { thread2.assertWaiting("Unexpected state for " + record2); thread2.interrupt(); - mAms.mProcessList.mActiveUids.clear(); + clearActiveUids(); } private UidRecord addActiveUidRecord(int uid, long curProcStateSeq, @@ -137,11 +137,21 @@ public class ActivityManagerInternalTest { final UidRecord record = new UidRecord(uid, mAms); record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq; record.curProcStateSeq = curProcStateSeq; - record.waitingForNetwork = true; - mAms.mProcessList.mActiveUids.put(uid, record); + record.procStateSeqWaitingForNetwork = 1; + addActiveUidRecord(uid, record); return record; } + @SuppressWarnings("GuardedBy") + private void addActiveUidRecord(int uid, UidRecord record) { + mAms.mProcessList.mActiveUids.put(uid, record); + } + + @SuppressWarnings("GuardedBy") + private void clearActiveUids() { + mAms.mProcessList.mActiveUids.clear(); + } + static class CustomThread extends Thread { private static final long WAIT_TIMEOUT_MS = 1000; private static final long WAIT_INTERVAL_MS = 100; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 12e0d8bc5d62..968a3e2c354e 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -191,8 +191,6 @@ public class ActivityManagerServiceTest { verifySeqCounterAndInteractions(uidRec, PROCESS_STATE_TOP, // prevState PROCESS_STATE_TOP, // curState - 0, // expectedGlobalCounter - 0, // exptectedCurProcStateSeq NETWORK_STATE_NO_CHANGE, // expectedBlockState false); // expectNotify @@ -200,8 +198,6 @@ public class ActivityManagerServiceTest { verifySeqCounterAndInteractions(uidRec, PROCESS_STATE_FOREGROUND_SERVICE, // prevState PROCESS_STATE_SERVICE, // curState - 1, // expectedGlobalCounter - 1, // exptectedCurProcStateSeq NETWORK_STATE_UNBLOCK, // expectedBlockState true); // expectNotify @@ -213,8 +209,6 @@ public class ActivityManagerServiceTest { verifySeqCounterAndInteractions(uidRec, PROCESS_STATE_TRANSIENT_BACKGROUND, // prevState PROCESS_STATE_IMPORTANT_BACKGROUND, // curState - 42, // expectedGlobalCounter - 1, // exptectedCurProcStateSeq NETWORK_STATE_NO_CHANGE, // expectedBlockState false); // expectNotify @@ -222,73 +216,22 @@ public class ActivityManagerServiceTest { verifySeqCounterAndInteractions(uidRec, PROCESS_STATE_LAST_ACTIVITY, // prevState PROCESS_STATE_TOP, // curState - 43, // expectedGlobalCounter - 43, // exptectedCurProcStateSeq NETWORK_STATE_BLOCK, // expectedBlockState false); // expectNotify // verify waiting threads are not notified. - uidRec.waitingForNetwork = false; + uidRec.procStateSeqWaitingForNetwork = 0; // Uid state is moving from foreground to background. verifySeqCounterAndInteractions(uidRec, PROCESS_STATE_FOREGROUND_SERVICE, // prevState PROCESS_STATE_SERVICE, // curState - 44, // expectedGlobalCounter - 44, // exptectedCurProcStateSeq NETWORK_STATE_UNBLOCK, // expectedBlockState false); // expectNotify - - // Verify when uid is not restricted, procStateSeq is not incremented. - uidRec.waitingForNetwork = true; - mInjector.setNetworkRestrictedForUid(false); - verifySeqCounterAndInteractions(uidRec, - PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState - PROCESS_STATE_TOP, // curState - 44, // expectedGlobalCounter - 44, // exptectedCurProcStateSeq - -1, // expectedBlockState, -1 to verify there are no interactions with main thread. - false); // expectNotify - - // Verify when waitForNetworkTimeout is 0, then procStateSeq is not incremented. - mAms.mWaitForNetworkTimeoutMs = 0; - mInjector.setNetworkRestrictedForUid(true); - verifySeqCounterAndInteractions(uidRec, - PROCESS_STATE_TOP, // prevState - PROCESS_STATE_IMPORTANT_BACKGROUND, // curState - 44, // expectedGlobalCounter - 44, // exptectedCurProcStateSeq - -1, // expectedBlockState, -1 to verify there are no interactions with main thread. - false); // expectNotify - - // Verify when the uid doesn't have internet permission, then procStateSeq is not - // incremented. - uidRec.hasInternetPermission = false; - mAms.mWaitForNetworkTimeoutMs = 111; - mInjector.setNetworkRestrictedForUid(true); - verifySeqCounterAndInteractions(uidRec, - PROCESS_STATE_CACHED_ACTIVITY, // prevState - PROCESS_STATE_FOREGROUND_SERVICE, // curState - 44, // expectedGlobalCounter - 44, // exptectedCurProcStateSeq - -1, // expectedBlockState, -1 to verify there are no interactions with main thread. - false); // expectNotify - - // Verify procStateSeq is not incremented when the uid is not an application, regardless - // of the process state. - final int notAppUid = 111; - final UidRecord uidRec2 = addUidRecord(notAppUid); - verifySeqCounterAndInteractions(uidRec2, - PROCESS_STATE_CACHED_EMPTY, // prevState - PROCESS_STATE_TOP, // curState - 44, // expectedGlobalCounter - 0, // exptectedCurProcStateSeq - -1, // expectedBlockState, -1 to verify there are no interactions with main thread. - false); // expectNotify } private UidRecord addUidRecord(int uid) { final UidRecord uidRec = new UidRecord(uid, mAms); - uidRec.waitingForNetwork = true; + uidRec.procStateSeqWaitingForNetwork = 1; uidRec.hasInternetPermission = true; mAms.mProcessList.mActiveUids.put(uid, uidRec); @@ -305,18 +248,26 @@ public class ActivityManagerServiceTest { @SuppressWarnings("GuardedBy") private void verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState, - int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState, - boolean expectNotify) throws Exception { + int expectedBlockState, boolean expectNotify) throws Exception { CustomThread thread = new CustomThread(uidRec.networkStateLock); thread.startAndWait("Unexpected state for " + uidRec); uidRec.setSetProcState(prevState); uidRec.setCurProcState(curState); + final long beforeProcStateSeq = mAms.mProcessList.mProcStateSeqCounter; + mAms.mProcessList.incrementProcStateSeqAndNotifyAppsLOSP(mAms.mProcessList.mActiveUids); - // @SuppressWarnings("GuardedBy") - assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter); - assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq); + final long afterProcStateSeq = beforeProcStateSeq + + mAms.mProcessList.mActiveUids.size(); + assertEquals("beforeProcStateSeq=" + beforeProcStateSeq + + ",activeUids.size=" + mAms.mProcessList.mActiveUids.size(), + afterProcStateSeq, mAms.mProcessList.mProcStateSeqCounter); + assertTrue("beforeProcStateSeq=" + beforeProcStateSeq + + ",afterProcStateSeq=" + afterProcStateSeq + + ",uidCurProcStateSeq=" + uidRec.curProcStateSeq, + uidRec.curProcStateSeq > beforeProcStateSeq + && uidRec.curProcStateSeq <= afterProcStateSeq); for (int i = mAms.mProcessList.getLruSizeLOSP() - 1; i >= 0; --i) { final ProcessRecord app = mAms.mProcessList.getLruProcessesLOSP().get(i); @@ -815,48 +766,11 @@ public class ActivityManagerServiceTest { } @Test - public void testEnqueueUidChangeLocked_procStateSeqUpdated() { - final UidRecord uidRecord = new UidRecord(TEST_UID, mAms); - uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; - - // Verify with no pending changes for TEST_UID. - verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ1); - - // Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as - // expected. - uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2; - verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2); - } - - @Test public void testEnqueueUidChangeLocked_nullUidRecord() { // Use "null" uidRecord to make sure there is no crash. mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE); } - private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) { - // Test enqueueUidChangeLocked with every UidRecord.CHANGE_* - for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) { - final int changeToDispatch = UID_RECORD_CHANGES[i]; - // Reset lastProcStateSeqDispatchToObservers after every test. - uidRecord.lastDispatchedProcStateSeq = 0; - mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch); - // Verify there is no effect on curProcStateSeq. - assertEquals(curProcstateSeq, uidRecord.curProcStateSeq); - if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) { - // Since the change is CHANGE_GONE or CHANGE_GONE_IDLE, verify that - // lastProcStateSeqDispatchedToObservers is not updated. - assertNotEquals(uidRecord.curProcStateSeq, - uidRecord.lastDispatchedProcStateSeq); - } else { - // Since the change is neither CHANGE_GONE nor CHANGE_GONE_IDLE, verify that - // lastProcStateSeqDispatchedToObservers has been updated to curProcStateSeq. - assertEquals(uidRecord.curProcStateSeq, - uidRecord.lastDispatchedProcStateSeq); - } - } - } - @MediumTest @Test public void testEnqueueUidChangeLocked_dispatchUidsChanged() { @@ -893,29 +807,10 @@ public class ActivityManagerServiceTest { // Check there is no crash when there is no UidRecord for myUid mAms.waitForNetworkStateUpdate(TEST_PROC_STATE_SEQ1); - // Verify there is no waiting when UidRecord.curProcStateSeq is greater than - // the procStateSeq in the request to wait. - verifyWaitingForNetworkStateUpdate( - TEST_PROC_STATE_SEQ1, // curProcStateSeq - TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq - TEST_PROC_STATE_SEQ1 - 4, // lastNetworkUpdatedProcStateSeq - TEST_PROC_STATE_SEQ1 - 2, // procStateSeqToWait - false); // expectWait - - // Verify there is no waiting when the procStateSeq in the request to wait is - // not dispatched to NPMS. - verifyWaitingForNetworkStateUpdate( - TEST_PROC_STATE_SEQ1, // curProcStateSeq - TEST_PROC_STATE_SEQ1 - 1, // lastDsipatchedProcStateSeq - TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq - TEST_PROC_STATE_SEQ1, // procStateSeqToWait - false); // expectWait - // Verify there is not waiting when the procStateSeq in the request already has // an updated network state. verifyWaitingForNetworkStateUpdate( TEST_PROC_STATE_SEQ1, // curProcStateSeq - TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq TEST_PROC_STATE_SEQ1, // lastNetworkUpdatedProcStateSeq TEST_PROC_STATE_SEQ1, // procStateSeqToWait false); // expectWait @@ -923,18 +818,16 @@ public class ActivityManagerServiceTest { // Verify waiting for network works verifyWaitingForNetworkStateUpdate( TEST_PROC_STATE_SEQ1, // curProcStateSeq - TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq TEST_PROC_STATE_SEQ1, // procStateSeqToWait true); // expectWait } private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq, - long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq, + long lastNetworkUpdatedProcStateSeq, final long procStateSeqToWait, boolean expectWait) throws Exception { final UidRecord record = new UidRecord(Process.myUid(), mAms); record.curProcStateSeq = curProcStateSeq; - record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq; record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq; mAms.mProcessList.mActiveUids.put(Process.myUid(), record); @@ -953,7 +846,7 @@ public class ActivityManagerServiceTest { } thread.assertTerminated(errMsg); assertTrue(thread.mNotified); - assertFalse(record.waitingForNetwork); + assertEquals(0, record.procStateSeqWaitingForNetwork); } else { thread.start(); thread.assertTerminated(errMsg); diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index af8ac6f412f5..0f2fe4434bfa 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -118,6 +118,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.net.ConnectivityManager; @@ -166,6 +167,7 @@ import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent; import com.android.internal.util.test.FsUtil; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; +import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.usage.AppStandbyInternal; import com.google.common.util.concurrent.AbstractFuture; @@ -216,6 +218,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -274,6 +277,7 @@ public class NetworkPolicyManagerServiceTest { ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class); private ActivityManagerInternal mActivityManagerInternal; + private PackageManagerInternal mPackageManagerInternal; private IUidObserver mUidObserver; private INetworkManagementEventObserver mNetworkObserver; @@ -335,6 +339,7 @@ public class NetworkPolicyManagerServiceTest { when(usageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{}); mActivityManagerInternal = addLocalServiceMock(ActivityManagerInternal.class); + mPackageManagerInternal = addLocalServiceMock(PackageManagerInternal.class); final PowerSaveState state = new PowerSaveState.Builder() .setBatterySaverEnabled(false).build(); @@ -436,14 +441,14 @@ public class NetworkPolicyManagerServiceTest { setNetpolicyXml(context); doAnswer(new Answer<Void>() { - @Override public Void answer(InvocationOnMock invocation) throws Throwable { mUidObserver = (IUidObserver) invocation.getArguments()[0]; Log.d(TAG, "set mUidObserver to " + mUidObserver); return null; } - }).when(mActivityManager).registerUidObserver(any(), anyInt(), anyInt(), any(String.class)); + }).when(mActivityManagerInternal).registerNetworkPolicyUidObserver(any(), + anyInt(), anyInt(), any(String.class)); mFutureIntent = newRestrictBackgroundChangedFuture(); mDeps = new TestDependencies(mServiceContext); @@ -483,8 +488,15 @@ public class NetworkPolicyManagerServiceTest { .thenReturn(buildApplicationInfo(PKG_NAME_B, UID_B)); when(mPackageManager.getApplicationInfo(eq(PKG_NAME_C), anyInt())) .thenReturn(buildApplicationInfo(PKG_NAME_C, UID_C)); - when(mPackageManager.getInstalledApplications(anyInt())).thenReturn( - buildInstalledApplicationInfoList()); + doAnswer(arg -> { + final Consumer<AndroidPackage> consumer = + (Consumer<AndroidPackage>) arg.getArguments()[0]; + for (AndroidPackage androidPackage : buildInstalledPackageList()) { + consumer.accept(androidPackage); + } + return null; + }).when(mPackageManagerInternal).forEachInstalledPackage( + any(Consumer.class), anyInt()); when(mUserManager.getUsers()).thenReturn(buildUserInfoList()); when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true); when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true); @@ -536,6 +548,7 @@ public class NetworkPolicyManagerServiceTest { LocalServices.removeServiceForTest(DeviceIdleInternal.class); LocalServices.removeServiceForTest(AppStandbyInternal.class); LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); + LocalServices.removeServiceForTest(PackageManagerInternal.class); } @After @@ -978,19 +991,20 @@ public class NetworkPolicyManagerServiceTest { @Test public void testUidForeground() throws Exception { // push all uids into background - callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, 0); - callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, 0); + long procStateSeq = 0; + callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); + callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); assertFalse(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); // push one of the uids into foreground - callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, 0); + callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP, procStateSeq++); assertTrue(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); // and swap another uid into foreground - callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, 0); - callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, 0); + callOnUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE, procStateSeq++); + callOnUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP, procStateSeq++); assertFalse(mService.isUidForeground(UID_A)); assertTrue(mService.isUidForeground(UID_B)); } @@ -2037,14 +2051,20 @@ public class NetworkPolicyManagerServiceTest { return ai; } - private List<ApplicationInfo> buildInstalledApplicationInfoList() { - final List<ApplicationInfo> installedApps = new ArrayList<>(); - installedApps.add(buildApplicationInfo(PKG_NAME_A, UID_A)); - installedApps.add(buildApplicationInfo(PKG_NAME_B, UID_B)); - installedApps.add(buildApplicationInfo(PKG_NAME_C, UID_C)); + private List<AndroidPackage> buildInstalledPackageList() { + final List<AndroidPackage> installedApps = new ArrayList<>(); + installedApps.add(createPackageMock(UID_A)); + installedApps.add(createPackageMock(UID_B)); + installedApps.add(createPackageMock(UID_C)); return installedApps; } + private AndroidPackage createPackageMock(int uid) { + final AndroidPackage androidPackage = mock(AndroidPackage.class); + when(androidPackage.getUid()).thenReturn(uid); + return androidPackage; + } + private List<UserInfo> buildUserInfoList() { final List<UserInfo> users = new ArrayList<>(); users.add(new UserInfo(USER_ID, "user1", 0)); |