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
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 3d7ea69..4f18fa2 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1252,9 +1252,13 @@
* {@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 @@
@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 @@
@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 47b3316..a270684 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -30,6 +30,7 @@
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 @@
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 fa5175c..c6beeca 100644
--- a/framework/src/android/net/INetworkAgent.aidl
+++ b/framework/src/android/net/INetworkAgent.aidl
@@ -26,7 +26,7 @@
* @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 61b27b5..afdd1ee 100644
--- a/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -30,7 +30,7 @@
* 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 cefa1ea..08f5ecd 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -98,6 +98,7 @@
@Nullable
private volatile Network mNetwork;
+ // Null before the agent is registered
@Nullable
private volatile INetworkAgentRegistry mRegistry;
@@ -121,6 +122,8 @@
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 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 @@
}
mPreConnectedQueue.clear();
}
+ mConnected = true;
}
break;
}
@@ -631,7 +635,7 @@
// let the client know CS is done with us.
onNetworkUnwanted();
synchronized (mPreConnectedQueue) {
- mRegistry = null;
+ mConnected = false;
}
break;
}
@@ -758,20 +762,32 @@
}
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 @@
}
@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 @@
*
* @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 @@
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 0000000..8c01bbc
--- /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 3ce3f02..45eb15a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -228,6 +228,7 @@
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 @@
* @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 @@
}
}
- 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 @@
// 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 e762a8e..d6bd659 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -639,6 +639,7 @@
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 @@
mNetd = netd;
mContext = context;
mHandler = handler;
+ mRegistry = new NetworkAgentMessageHandler(mHandler);
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
mLingerDurationMs = lingerDurationMs;
@@ -701,7 +703,7 @@
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 @@
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 5e035a2..678e1ca 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.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 @@
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 @@
fun connect(agent: INetworkAgent) {
this.agentField = agent
- agent.onRegistered(registry)
+ agent.onRegistered()
}
fun disconnect() = agent.onDisconnected()
@@ -413,7 +413,8 @@
}
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 @@
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