diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 1ac22bd2c5..e7441a97ee 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -526,6 +526,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private final boolean mBackgroundFirewallChainEnabled; private final boolean mUseDeclaredMethodsForCallbacksEnabled; + private final boolean mQueueNetworkAgentEventsInSystemServer; // Flag to delay callbacks for frozen apps, suppressing duplicate and stale callbacks. private final boolean mQueueCallbacksForFrozenApps; @@ -1917,6 +1918,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mUseDeclaredMethodsForCallbacksEnabled = mDeps.isFeatureNotChickenedOut(context, ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS); + mQueueNetworkAgentEventsInSystemServer = + mDeps.isFeatureNotChickenedOut(context, + ConnectivityFlags.QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER); // registerUidFrozenStateChangedCallback is only available on U+ mQueueCallbacksForFrozenApps = mDeps.isAtLeastU() && mDeps.isFeatureNotChickenedOut(context, QUEUE_CALLBACKS_FOR_FROZEN_APPS); @@ -4677,18 +4681,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void maybeHandleNetworkAgentMessage(Message msg) { final Pair arg = (Pair) msg.obj; final NetworkAgentInfo nai = arg.first; - if (!mNetworkAgentInfos.contains(nai)) { - if (VDBG) { - log(String.format("%s from unknown NetworkAgent", eventName(msg.what))); - } - return; - } // If the network has been destroyed, the only thing that it can do is disconnect. if (nai.isDestroyed() && !isDisconnectRequest(msg)) { return; } + if (mQueueNetworkAgentEventsInSystemServer && nai.maybeEnqueueMessage(msg)) { + // If the message is enqueued, the NAI will replay it immediately + // when registration is complete. It does this by sending all the + // messages in the order received immediately after the + // EVENT_AGENT_REGISTERED message. + return; + } + + // If the nai has been registered (and doesn't enqueue), it should now be + // in the list of NAIs. + if (!mNetworkAgentInfos.contains(nai)) { + // TODO : this is supposed to be impossible + if (VDBG) { + log(String.format("%s from unknown NetworkAgent", eventName(msg.what))); + } + return; + } + switch (msg.what) { case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: { final NetworkCapabilities proposed = (NetworkCapabilities) arg.second; diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java index 136ea812da..74bd2351ac 100644 --- a/service/src/com/android/server/connectivity/ConnectivityFlags.java +++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java @@ -62,6 +62,9 @@ public final class ConnectivityFlags { public static final String QUEUE_CALLBACKS_FOR_FROZEN_APPS = "queue_callbacks_for_frozen_apps"; + public static final String QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER = + "queue_network_agent_events_in_system_server"; + private boolean mNoRematchAllRequestsOnRegister; /** diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java index 6d25d63457..4540f02a72 100644 --- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java +++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java @@ -62,6 +62,7 @@ import android.net.QosSession; import android.net.TcpKeepalivePacketData; import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.SystemClock; @@ -630,6 +631,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { // Used by ConnectivityService to keep track of 464xlat. public final Nat464Xlat clatd; + private final ArrayList mMessagesPendingRegistration = new ArrayList<>(); // Set after asynchronous creation of the NetworkMonitor. private volatile NetworkMonitorManager mNetworkMonitor; @@ -715,6 +717,29 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { } mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_SUCCESS, 0, this).sendToTarget(); + for (final Message enqueued : mMessagesPendingRegistration) { + mHandler.sendMessage(enqueued); + } + mMessagesPendingRegistration.clear(); + } + + /** + * Enqueues a message if it needs to be enqueued, and returns whether it was enqueued. + * + * The message is enqueued iff it can't be sent just yet. If it can be sent + * immediately, this method returns false and doesn't enqueue. + * + * If it enqueues, this method will make a copy of the message for enqueuing since + * messages can't be reused or recycled before the end of their processing by the + * handler. + */ + public boolean maybeEnqueueMessage(final Message msg) { + HandlerUtils.ensureRunningOnHandlerThread(mHandler); + if (null != mNetworkMonitor) return false; + final Message m = mHandler.obtainMessage(); + m.copyFrom(msg); + mMessagesPendingRegistration.add(m); + return true; } /** diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index c4944b6de0..c5e1a2ae00 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -2199,6 +2199,7 @@ public class ConnectivityServiceTest { case ConnectivityFlags.DELAY_DESTROY_SOCKETS: case ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS: case ConnectivityFlags.QUEUE_CALLBACKS_FOR_FROZEN_APPS: + case ConnectivityFlags.QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER: return true; default: throw new UnsupportedOperationException("Unknown flag " + name diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt index 557bfd6612..e941b1f8e6 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -168,6 +168,7 @@ open class CSTest { it[ConnectivityFlags.DELAY_DESTROY_SOCKETS] = true it[ConnectivityFlags.USE_DECLARED_METHODS_FOR_CALLBACKS] = true it[ConnectivityFlags.QUEUE_CALLBACKS_FOR_FROZEN_APPS] = true + it[ConnectivityFlags.QUEUE_NETWORK_AGENT_EVENTS_IN_SYSTEM_SERVER] = true } fun setFeatureEnabled(flag: String, enabled: Boolean) = enabledFeatures.set(flag, enabled)