From 8a97692638ed9f2fadbc89d593ef0662a2080803 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 18 Mar 2025 09:27:33 +0900 Subject: [PATCH 1/3] Reapply "Return the registry in registerNetworkAgent." Now that faulty Telephony tests have been disabled temporarily to allow for this bugfix, this can be reverted. This reverts commit 653d5f1ef42cef52203c06d40027096a70e381f6. Test: FrameworksTelephonyTests CtsNetTestCases Change-Id: If6b1541981803dc84de57b48adb13d40c9997fa0 --- .../src/android/net/ConnectivityManager.java | 14 ++++-- .../src/android/net/IConnectivityManager.aidl | 4 +- framework/src/android/net/INetworkAgent.aidl | 2 +- .../android/net/INetworkAgentRegistry.aidl | 2 +- framework/src/android/net/NetworkAgent.java | 48 +++++++++++++------ .../NetworkAndAgentRegistryParcelable.aidl | 31 ++++++++++++ .../android/server/ConnectivityService.java | 13 +++-- .../server/connectivity/NetworkAgentInfo.java | 11 ++++- .../src/android/net/cts/NetworkAgentTest.kt | 11 +++-- 9 files changed, 104 insertions(+), 32 deletions(-) create mode 100644 framework/src/android/net/NetworkAndAgentRegistryParcelable.aidl diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java index 3d7ea6944e..4f18fa207e 100644 --- a/framework/src/android/net/ConnectivityManager.java +++ b/framework/src/android/net/ConnectivityManager.java @@ -1252,9 +1252,13 @@ public class ConnectivityManager { * {@link ConnectivityManager#registerNetworkAgent} * @hide */ - public static Network registerNetworkAgentResult( + public static NetworkAndAgentRegistryParcelable registerNetworkAgentResult( @Nullable final Network network, @Nullable final INetworkAgentRegistry registry) { - return network; + final NetworkAndAgentRegistryParcelable result = + new NetworkAndAgentRegistryParcelable(); + result.network = network; + result.registry = registry; + return result; } } @@ -3968,7 +3972,8 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(@NonNull INetworkAgent na, @NonNull NetworkInfo ni, + public NetworkAndAgentRegistryParcelable registerNetworkAgent( + @NonNull INetworkAgent na, @NonNull NetworkInfo ni, @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId) { return registerNetworkAgent(na, ni, lp, nc, null /* localNetworkConfig */, score, config, @@ -3983,7 +3988,8 @@ public class ConnectivityManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) - public Network registerNetworkAgent(@NonNull INetworkAgent na, @NonNull NetworkInfo ni, + public NetworkAndAgentRegistryParcelable registerNetworkAgent( + @NonNull INetworkAgent na, @NonNull NetworkInfo ni, @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc, @Nullable LocalNetworkConfig localNetworkConfig, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId) { diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl index 47b33162d2..a270684c40 100644 --- a/framework/src/android/net/IConnectivityManager.aidl +++ b/framework/src/android/net/IConnectivityManager.aidl @@ -30,6 +30,7 @@ import android.net.LinkProperties; import android.net.LocalNetworkConfig; import android.net.Network; import android.net.NetworkAgentConfig; +import android.net.NetworkAndAgentRegistryParcelable; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; @@ -146,7 +147,8 @@ interface IConnectivityManager void declareNetworkRequestUnfulfillable(in NetworkRequest request); - Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp, + NetworkAndAgentRegistryParcelable registerNetworkAgent( + in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, in NetworkScore score, in LocalNetworkConfig localNetworkConfig, in NetworkAgentConfig config, in int factorySerialNumber); diff --git a/framework/src/android/net/INetworkAgent.aidl b/framework/src/android/net/INetworkAgent.aidl index fa5175c49f..c6beeca869 100644 --- a/framework/src/android/net/INetworkAgent.aidl +++ b/framework/src/android/net/INetworkAgent.aidl @@ -26,7 +26,7 @@ import android.net.INetworkAgentRegistry; * @hide */ oneway interface INetworkAgent { - void onRegistered(in INetworkAgentRegistry registry); + void onRegistered(); void onDisconnected(); void onBandwidthUpdateRequested(); void onValidationStatusChanged(int validationStatus, diff --git a/framework/src/android/net/INetworkAgentRegistry.aidl b/framework/src/android/net/INetworkAgentRegistry.aidl index 61b27b5f0e..afdd1eec0b 100644 --- a/framework/src/android/net/INetworkAgentRegistry.aidl +++ b/framework/src/android/net/INetworkAgentRegistry.aidl @@ -30,7 +30,7 @@ import android.telephony.data.NrQosSessionAttributes; * Interface for NetworkAgents to send network properties. * @hide */ -oneway interface INetworkAgentRegistry { +interface INetworkAgentRegistry { void sendNetworkCapabilities(in NetworkCapabilities nc); void sendLinkProperties(in LinkProperties lp); // TODO: consider replacing this by "markConnected()" and removing diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java index cefa1ea072..08f5ecdb7c 100644 --- a/framework/src/android/net/NetworkAgent.java +++ b/framework/src/android/net/NetworkAgent.java @@ -98,6 +98,7 @@ public abstract class NetworkAgent { @Nullable private volatile Network mNetwork; + // Null before the agent is registered @Nullable private volatile INetworkAgentRegistry mRegistry; @@ -121,6 +122,8 @@ public abstract class NetworkAgent { private NetworkInfo mNetworkInfo; @NonNull private final Object mRegisterLock = new Object(); + // TODO : move the preconnected queue to the system server and remove this + private boolean mConnected = false; /** * The ID of the {@link NetworkProvider} that created this object, or @@ -606,16 +609,16 @@ public abstract class NetworkAgent { public void handleMessage(Message msg) { switch (msg.what) { case EVENT_AGENT_CONNECTED: { - if (mRegistry != null) { - log("Received new connection while already connected!"); - } else { - if (VDBG) log("NetworkAgent fully connected"); - synchronized (mPreConnectedQueue) { - final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj; - mRegistry = registry; + // TODO : move the pre-connected queue to the system server, and remove + // handling this EVENT_AGENT_CONNECTED message. + synchronized (mPreConnectedQueue) { + if (mConnected) { + log("Received new connection while already connected!"); + } else { + if (VDBG) log("NetworkAgent fully connected"); for (RegistryAction a : mPreConnectedQueue) { try { - a.execute(registry); + a.execute(mRegistry); } catch (RemoteException e) { Log.wtf(LOG_TAG, "Communication error with registry", e); // Fall through @@ -623,6 +626,7 @@ public abstract class NetworkAgent { } mPreConnectedQueue.clear(); } + mConnected = true; } break; } @@ -631,7 +635,7 @@ public abstract class NetworkAgent { // let the client know CS is done with us. onNetworkUnwanted(); synchronized (mPreConnectedQueue) { - mRegistry = null; + mConnected = false; } break; } @@ -758,20 +762,32 @@ public abstract class NetworkAgent { } final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context .getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkAndAgentRegistryParcelable result; if (mInitialConfiguration.localNetworkConfig == null) { // Call registerNetworkAgent without localNetworkConfig argument to pass // android.net.cts.NetworkAgentTest#testAgentStartsInConnecting in old cts - mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), + result = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), new NetworkInfo(mInitialConfiguration.info), mInitialConfiguration.properties, mInitialConfiguration.capabilities, mInitialConfiguration.score, mInitialConfiguration.config, providerId); } else { - mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), + result = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler), new NetworkInfo(mInitialConfiguration.info), mInitialConfiguration.properties, mInitialConfiguration.capabilities, mInitialConfiguration.localNetworkConfig, mInitialConfiguration.score, mInitialConfiguration.config, providerId); } + if (null == result && Process.isApplicationUid(Process.myUid())) { + // Let it slide in tests to allow mocking, since NetworkAndAgentRegistryParcelable + // is not public and can't be instantiated by CTS. The danger here is that if + // this happens in production for some reason the code will crash later instead + // of here. If this is a system app, it will still crash as expected. + Log.e(LOG_TAG, "registerNetworkAgent returned null. This agent will not work. " + + "Is ConnectivityManager a mockĀ ?"); + } else { + mNetwork = result.network; + mRegistry = result.registry; + } mInitialConfiguration = null; // All this memory can now be GC'd } return mNetwork; @@ -787,8 +803,8 @@ public abstract class NetworkAgent { } @Override - public void onRegistered(@NonNull INetworkAgentRegistry registry) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry)); + public void onRegistered() { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED)); } @Override @@ -913,11 +929,13 @@ public abstract class NetworkAgent { * * @hide */ - public INetworkAgent registerForTest(final Network network) { + public INetworkAgent registerForTest(final Network network, + final INetworkAgentRegistry registry) { log("Registering NetworkAgent for test"); synchronized (mRegisterLock) { mNetwork = network; mInitialConfiguration = null; + mRegistry = registry; } return new NetworkAgentBinder(mHandler); } @@ -958,7 +976,7 @@ public abstract class NetworkAgent { FrameworkConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_MESSAGE_QUEUED_BEFORE_CONNECT ); } - if (mRegistry != null) { + if (mConnected) { try { action.execute(mRegistry); } catch (RemoteException e) { diff --git a/framework/src/android/net/NetworkAndAgentRegistryParcelable.aidl b/framework/src/android/net/NetworkAndAgentRegistryParcelable.aidl new file mode 100644 index 0000000000..8c01bbcda1 --- /dev/null +++ b/framework/src/android/net/NetworkAndAgentRegistryParcelable.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.INetworkAgentRegistry; +import android.net.Network; + +/** + * A pair of Network and NetworkAgentRegistry. + * + * {@hide} + */ +@JavaDerive(toString=true) +parcelable NetworkAndAgentRegistryParcelable { + Network network; + INetworkAgentRegistry registry; +} diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 3ce3f0227f..45eb15ad94 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -228,6 +228,7 @@ import android.net.NattSocketKeepalive; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkAgentConfig; +import android.net.NetworkAndAgentRegistryParcelable; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -9328,7 +9329,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * @param providerId the ID of the provider owning this NetworkAgent. * @return the network created for this agent. */ - public Network registerNetworkAgent(INetworkAgent na, + public NetworkAndAgentRegistryParcelable registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, @@ -9371,7 +9372,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo, + private NetworkAndAgentRegistryParcelable registerNetworkAgentInternal( + INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, @Nullable LocalNetworkConfig localNetworkConfig, int providerId, @@ -9403,8 +9405,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // NetworkAgentInfo registration will finish when the NetworkMonitor is created. // If the network disconnects or sends any other event before that, messages are deferred by // NetworkAgent until nai.connect(), which will be called when finalizing the - // registration. - return nai.network; + // registration. TODO : have NetworkAgentInfo defer them instead. + final NetworkAndAgentRegistryParcelable result = new NetworkAndAgentRegistryParcelable(); + result.network = nai.network; + result.registry = nai.getRegistry(); + return result; } private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java index e762a8e866..d6bd659946 100644 --- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java +++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java @@ -639,6 +639,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { private final ConnectivityService.Dependencies mConnServiceDeps; private final Context mContext; private final Handler mHandler; + private final NetworkAgentMessageHandler mRegistry; private final QosCallbackTracker mQosCallbackTracker; private final INetd mNetd; @@ -673,6 +674,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { mNetd = netd; mContext = context; mHandler = handler; + mRegistry = new NetworkAgentMessageHandler(mHandler); this.factorySerialNumber = factorySerialNumber; this.creatorUid = creatorUid; mLingerDurationMs = lingerDurationMs; @@ -701,7 +703,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { public void notifyRegistered() { try { networkAgent.asBinder().linkToDeath(mDeathMonitor, 0); - networkAgent.onRegistered(new NetworkAgentMessageHandler(mHandler)); + networkAgent.onRegistered(); } catch (RemoteException e) { Log.e(TAG, "Error registering NetworkAgent", e); maybeUnlinkDeathMonitor(); @@ -1117,6 +1119,13 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { return mNetworkMonitor; } + /** + * Get the registry in this NetworkAgentInfo. + */ + public INetworkAgentRegistry getRegistry() { + return mRegistry; + } + // Functions for manipulating the requests satisfied by this network. // // These functions must only called on ConnectivityService's main thread. diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt index 5e035a2723..678e1cab55 100644 --- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt +++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt @@ -154,10 +154,10 @@ import java.nio.ByteBuffer import java.security.MessageDigest import java.time.Duration import java.util.Arrays -import java.util.Random import java.util.UUID import java.util.concurrent.Executors import kotlin.collections.ArrayList +import kotlin.random.Random import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse @@ -267,7 +267,7 @@ class NetworkAgentTest { private class FakeConnectivityService { val mockRegistry = mock(INetworkAgentRegistry::class.java) private var agentField: INetworkAgent? = null - private val registry = object : INetworkAgentRegistry.Stub(), + val registry: INetworkAgentRegistry = object : INetworkAgentRegistry.Stub(), INetworkAgentRegistry by mockRegistry { // asBinder has implementations in both INetworkAgentRegistry.Stub and mockRegistry, so // it needs to be disambiguated. Just fail the test as it should be unused here. @@ -284,7 +284,7 @@ class NetworkAgentTest { fun connect(agent: INetworkAgent) { this.agentField = agent - agent.onRegistered(registry) + agent.onRegistered() } fun disconnect() = agent.onDisconnected() @@ -413,7 +413,8 @@ class NetworkAgentTest { } private fun createNetworkAgentWithFakeCS() = createNetworkAgent().also { - mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID))) + val binder = it.registerForTest(Network(FAKE_NET_ID), mFakeConnectivityService.registry) + mFakeConnectivityService.connect(binder) } private fun TestableNetworkAgent.expectPostConnectionCallbacks( @@ -1628,7 +1629,7 @@ class NetworkAgentTest { val s = Os.socket(AF_INET6, SOCK_DGRAM, 0) net.bindSocket(s) val content = ByteArray(16) - Random().nextBytes(content) + Random.nextBytes(content) Os.sendto(s, ByteBuffer.wrap(content), 0, REMOTE_ADDRESS, 7 /* port */) val match = reader.poll(DEFAULT_TIMEOUT_MS) { val udpStart = IPV6_HEADER_LEN + UDP_HEADER_LEN From b3a53d0d39e608bbdbe01b0448aa1df7cdbdc3a6 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 18 Mar 2025 09:28:26 +0900 Subject: [PATCH 2/3] Reapply "Unify registration and NM assignment in NAI" Now that faulty Telephony tests have been disabled temporarily to allow for this bugfix, this can be reverted. This reverts commit 30fcf820f92470a824d2a083907e03a609ecaf35. Test: FrameworksTelephonyTests CtsNetTestCases Change-Id: I57f25f5e6481106255df0ab69558e351eb938f68 --- .../src/com/android/server/ConnectivityService.java | 4 +--- .../android/server/connectivity/NetworkAgentInfo.java | 11 +++-------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 45eb15ad94..85c432887e 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -9421,8 +9421,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { nai.getDeclaredCapabilitiesSanitized(mCarrierPrivilegeAuthenticator))); processLinkPropertiesFromAgent(nai, nai.linkProperties); - nai.onNetworkMonitorCreated(networkMonitor); - mNetworkAgentInfos.add(nai); synchronized (mNetworkForNetId) { mNetworkForNetId.put(nai.network.getNetId(), nai); @@ -9437,7 +9435,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (nai.isLocalNetwork()) { handleUpdateLocalNetworkConfig(nai, null /* oldConfig */, nai.localNetworkConfig); } - nai.notifyRegistered(); + nai.notifyRegistered(networkMonitor); NetworkInfo networkInfo = nai.networkInfo; updateNetworkInfo(nai, networkInfo); updateVpnUids(nai, null, nai.networkCapabilities); diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java index d6bd659946..6d25d63457 100644 --- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java +++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java @@ -700,7 +700,9 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { * Must be called from the ConnectivityService handler thread. A NetworkAgent can only be * registered once. */ - public void notifyRegistered() { + public void notifyRegistered(final INetworkMonitor nm) { + HandlerUtils.ensureRunningOnHandlerThread(mHandler); + mNetworkMonitor = new NetworkMonitorManager(nm); try { networkAgent.asBinder().linkToDeath(mDeathMonitor, 0); networkAgent.onRegistered(); @@ -1037,13 +1039,6 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { } } - /** - * Inform NetworkAgentInfo that a new NetworkMonitor was created. - */ - public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) { - mNetworkMonitor = new NetworkMonitorManager(networkMonitor); - } - /** * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor * of the new capabilities, if NetworkMonitor has been created. From 3c040009c59a5579b13bb1c1f8a41d5d8a88464a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 18 Mar 2025 09:28:41 +0900 Subject: [PATCH 3/3] Reapply "Add a queue system server-side for NetworkAgent" Now that faulty Telephony tests have been disabled temporarily to allow for this bugfix, this can be reverted. This reverts commit a5ec9b41128ad926475116b184d71b34740fd6f1. Test: FrameworksTelephonyTests CtsNetTestCases Change-Id: I71abf9d02bdd34a4de80157a3f42bdfee6f6617e --- .../android/server/ConnectivityService.java | 28 +++++++++++++++---- .../connectivity/ConnectivityFlags.java | 3 ++ .../server/connectivity/NetworkAgentInfo.java | 25 +++++++++++++++++ .../server/ConnectivityServiceTest.java | 1 + .../server/connectivityservice/base/CSTest.kt | 1 + 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 85c432887e..a95d95c0d2 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -527,6 +527,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; @@ -1929,6 +1930,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); @@ -4689,18 +4693,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 c28a0f8953..3eefa0f227 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -2200,6 +2200,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 d7e781e6b1..48333c59cf 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -169,6 +169,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)