From fe059d8c302d464f80113e2a9178e69ee5b65bc1 Mon Sep 17 00:00:00 2001 From: Cody Kesting Date: Wed, 12 Feb 2020 14:50:58 -0800 Subject: [PATCH] Invoke onConnectivityReport on registering ConnectivityDiagnostics. This change updates the behavior for registering ConnectivityDiagnosticsCallbacks. Now, after a successful register() call, callbacks will receive cached ConnectivityReports for all matching, permissioned networks. This allows registrants to be updated with the network state for their networks without having to wait for the next network validation. Bug: 147849853 Test: atest FrameworksNetTests Change-Id: I924ba8fdcc847f453557021591bde38602fe089c Merged-In: I924ba8fdcc847f453557021591bde38602fe089c (cherry picked from commit 95ec0b206b759e1d26bc1dbb2255a515bb24358a) --- .../net/ConnectivityDiagnosticsManager.java | 3 +- .../android/server/ConnectivityService.java | 29 ++++++++++++++++ .../server/connectivity/NetworkAgentInfo.java | 28 +++++++++++++++ .../server/ConnectivityServiceTest.java | 34 +++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java index 6f0a4f9744..aa35852f78 100644 --- a/core/java/android/net/ConnectivityDiagnosticsManager.java +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -659,7 +659,8 @@ public class ConnectivityDiagnosticsManager { public abstract static class ConnectivityDiagnosticsCallback { /** * Called when the platform completes a data connectivity check. This will also be invoked - * upon registration with the latest report. + * immediately upon registration with the latest report, if a report has already been + * generated for this network. * *

The Network specified in the ConnectivityReport may not be active any more when this * method is invoked. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d684f0c199..2b5f21a172 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -7855,6 +7855,34 @@ public class ConnectivityService extends IConnectivityManager.Stub cb.asBinder().linkToDeath(cbInfo, 0); } catch (RemoteException e) { cbInfo.binderDied(); + return; + } + + // Once registered, provide ConnectivityReports for matching Networks + final List matchingNetworks = new ArrayList<>(); + synchronized (mNetworkForNetId) { + for (int i = 0; i < mNetworkForNetId.size(); i++) { + final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i); + if (nai.satisfies(nri.request)) { + matchingNetworks.add(nai); + } + } + } + for (final NetworkAgentInfo nai : matchingNetworks) { + final ConnectivityReport report = nai.getConnectivityReport(); + if (report == null) { + continue; + } + if (!checkConnectivityDiagnosticsPermissions( + nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) { + continue; + } + + try { + cb.onConnectivityReportAvailable(report); + } catch (RemoteException e) { + // Exception while sending the ConnectivityReport. Move on to the next network. + } } } @@ -7890,6 +7918,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.linkProperties, networkCapabilities, extras); + nai.setConnectivityReport(report); final List results = getMatchingPermissionedCallbacks(nai); for (final IConnectivityDiagnosticsCallback cb : results) { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 2f047157d4..d2086138a1 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -16,6 +16,7 @@ package com.android.server.connectivity; +import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import static android.net.NetworkCapabilities.transportNamesOf; import android.annotation.NonNull; @@ -243,6 +244,9 @@ public class NetworkAgentInfo implements Comparable { // How many of the satisfied requests are of type BACKGROUND_REQUEST. private int mNumBackgroundNetworkRequests = 0; + // The last ConnectivityReport made available for this network. + private ConnectivityReport mConnectivityReport; + public final Messenger messenger; public final AsyncChannel asyncChannel; @@ -621,6 +625,30 @@ public class NetworkAgentInfo implements Comparable { for (LingerTimer timer : mLingerTimers) { pw.println(timer); } } + /** + * Sets the most recent ConnectivityReport for this network. + * + *

This should only be called from the ConnectivityService thread. + * + * @hide + */ + public void setConnectivityReport(@NonNull ConnectivityReport connectivityReport) { + mConnectivityReport = connectivityReport; + } + + /** + * Returns the most recent ConnectivityReport for this network, or null if none have been + * reported yet. + * + *

This should only be called from the ConnectivityService thread. + * + * @hide + */ + @Nullable + public ConnectivityReport getConnectivityReport() { + return mConnectivityReport; + } + // TODO: Print shorter members first and only print the boolean variable which value is true // to improve readability. public String toString() { diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 86d8a820e4..50b61fb40f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -317,6 +317,8 @@ public class ConnectivityServiceTest { private static final String TEST_PACKAGE_NAME = "com.android.test.package"; private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private static final String INTERFACE_NAME = "interface"; + private MockContext mServiceContext; private HandlerThread mCsHandlerThread; private ConnectivityService mService; @@ -6915,6 +6917,38 @@ public class ConnectivityServiceTest { mContext.getOpPackageName())); } + @Test + public void testRegisterConnectivityDiagnosticsCallbackCallsOnConnectivityReport() + throws Exception { + // Set up the Network, which leads to a ConnectivityReport being cached for the network. + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + final LinkProperties linkProperties = new LinkProperties(); + linkProperties.setInterfaceName(INTERFACE_NAME); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties); + mCellNetworkAgent.connect(true); + callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + callback.assertNoCallback(); + + final NetworkRequest request = new NetworkRequest.Builder().build(); + when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder); + + mServiceContext.setPermission( + android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED); + + mService.registerConnectivityDiagnosticsCallback( + mConnectivityDiagnosticsCallback, request, mContext.getPackageName()); + + // Block until all other events are done processing. + HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + + verify(mConnectivityDiagnosticsCallback) + .onConnectivityReportAvailable(argThat(report -> { + return INTERFACE_NAME.equals(report.getLinkProperties().getInterfaceName()) + && report.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR); + })); + } + private void setUpConnectivityDiagnosticsCallback() throws Exception { final NetworkRequest request = new NetworkRequest.Builder().build(); when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);