diff options
18 files changed, 720 insertions, 424 deletions
diff --git a/apex/jobscheduler/OWNERS b/apex/jobscheduler/OWNERS index c77ea336990d..58434f165aa2 100644 --- a/apex/jobscheduler/OWNERS +++ b/apex/jobscheduler/OWNERS @@ -1,7 +1,9 @@ ctate@android.com ctate@google.com dplotnikov@google.com +jji@google.com kwekua@google.com omakoto@google.com suprabh@google.com +varunshah@google.com yamasani@google.com 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 0f450e16be2d..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); } } @@ -10375,7 +10390,7 @@ public class ActivityManagerService extends IActivityManager.Stub "Native", "System", "Persistent", "Persistent Service", "Foreground", "Visible", "Perceptible", "Perceptible Low", "Perceptible Medium", - "Heavy Weight", "Backup", + "Backup", "Heavy Weight", "A Services", "Home", "Previous", "B Services", "Cached" }; @@ -10383,7 +10398,7 @@ public class ActivityManagerService extends IActivityManager.Stub "native", "sys", "pers", "persvc", "fore", "vis", "percept", "perceptl", "perceptm", - "heavy", "backup", + "backup", "heavy", "servicea", "home", "prev", "serviceb", "cached" }; @@ -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/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 2030b19b6b9a..dedd89883687 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1978,7 +1978,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub mHandler.post(() -> { synchronized (mStats) { mStats.noteBluetoothScanStoppedFromSourceLocked(localWs, isUnoptimized, - uptime, elapsedRealtime); + elapsedRealtime, uptime); } }); } 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/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 33440a3591f6..c53a9a63be65 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -85,6 +85,7 @@ import android.net.ipsec.ike.ChildSessionParams; import android.net.ipsec.ike.IkeSession; import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionParams; +import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.ipsec.ike.exceptions.IkeProtocolException; import android.os.Binder; import android.os.Build.VERSION_CODES; @@ -2267,6 +2268,11 @@ public class Vpn { profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS); startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); return; + case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: + // All the necessary IKE options should come from IkeTunnelConnectionParams in the + // profile. + startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); + return; case VpnProfile.TYPE_L2TP_IPSEC_PSK: racoon = new String[] { iface, profile.server, "udppsk", profile.ipsecIdentifier, @@ -2702,10 +2708,23 @@ public class Vpn { resetIkeState(); mActiveNetwork = network; - final IkeSessionParams ikeSessionParams = - VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, network); - final ChildSessionParams childSessionParams = - VpnIkev2Utils.buildChildSessionParams(mProfile.getAllowedAlgorithms()); + // Get Ike options from IkeTunnelConnectionParams if it's available in the + // profile. + final IkeTunnelConnectionParams ikeTunConnParams = + mProfile.getIkeTunnelConnectionParams(); + final IkeSessionParams ikeSessionParams; + final ChildSessionParams childSessionParams; + if (ikeTunConnParams != null) { + final IkeSessionParams.Builder builder = new IkeSessionParams.Builder( + ikeTunConnParams.getIkeSessionParams()).setNetwork(network); + ikeSessionParams = builder.build(); + childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams(); + } else { + ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams( + mContext, mProfile, network); + childSessionParams = VpnIkev2Utils.buildChildSessionParams( + mProfile.getAllowedAlgorithms()); + } // TODO: Remove the need for adding two unused addresses with // IPsec tunnels. @@ -3226,6 +3245,7 @@ public class Vpn { case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: + case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: if (!mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_IPSEC_TUNNELS)) { throw new UnsupportedOperationException( @@ -3399,6 +3419,7 @@ public class Vpn { case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: + case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: mVpnRunner = new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile)); mVpnRunner.start(); 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)); |