diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 7bd3ee2b33e32..4aa1691efc586 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -643,6 +643,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray(); + /** + * Map of uid -> UidStateCallbackInfo objects holding the data received from + * {@link IUidObserver#onUidStateChanged(int, int, long, int)} callbacks. In order to avoid + * creating a new object for every callback received, we hold onto the object created for each + * uid and reuse it. + * + * Note that the lock used for accessing this object should not be used for anything else and we + * should not be acquiring new locks or doing any heavy work while this lock is held since this + * will be used in the callback from ActivityManagerService. + */ + @GuardedBy("mUidStateCallbackInfos") + private final SparseArray mUidStateCallbackInfos = + new SparseArray<>(); + private RestrictedModeObserver mRestrictedModeObserver; // TODO: keep allowlist of system-critical services that should never have @@ -1022,11 +1036,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final private IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState, long procStateSeq, @ProcessCapability int capability) { - // TODO: Avoid creating a new UidStateCallbackInfo object every time - // we get a callback for an uid - mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, - new UidStateCallbackInfo(uid, procState, procStateSeq, capability)) + synchronized (mUidStateCallbackInfos) { + UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid); + if (callbackInfo == null) { + callbackInfo = new UidStateCallbackInfo(); + mUidStateCallbackInfos.put(uid, callbackInfo); + } + callbackInfo.update(uid, procState, procStateSeq, capability); + if (!callbackInfo.isPending) { + mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo) .sendToTarget(); + } + } } @Override public void onUidGone(int uid, boolean disabled) { @@ -1044,14 +1065,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { }; private static final class UidStateCallbackInfo { - public final int uid; - public final int procState; - public final long procStateSeq; + public int uid; + public int procState; + public long procStateSeq; @ProcessCapability - public final int capability; + public int capability; + public boolean isPending; - UidStateCallbackInfo(int uid, int procState, long procStateSeq, - @ProcessCapability int capability) { + public void update(int uid, int procState, long procStateSeq, int capability) { this.uid = uid; this.procState = procState; this.procStateSeq = procStateSeq; @@ -4495,6 +4516,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mPowerSaveTempWhitelistAppIds.delete(uid); mAppIdleTempWhitelistAppIds.delete(uid); mUidFirewallRestrictedModeRules.delete(uid); + synchronized (mUidStateCallbackInfos) { + mUidStateCallbackInfos.remove(uid); + } // ...then update iptables asynchronously. mHandler.obtainMessage(MSG_RESET_FIREWALL_RULES_BY_UID, uid, 0).sendToTarget(); @@ -5128,10 +5152,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case UID_MSG_STATE_CHANGED: { final UidStateCallbackInfo uidStateCallbackInfo = (UidStateCallbackInfo) msg.obj; - final int uid = uidStateCallbackInfo.uid; - final int procState = uidStateCallbackInfo.procState; - final long procStateSeq = uidStateCallbackInfo.procStateSeq; - final int capability = uidStateCallbackInfo.capability; + 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); return true;