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
This commit is contained in:
Cody Kesting
2020-02-12 14:50:58 -08:00
parent 7b987276db
commit b77bf707c6
4 changed files with 95 additions and 1 deletions

View File

@@ -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.
*
* <p>The Network specified in the ConnectivityReport may not be active any more when this
* method is invoked.

View File

@@ -7816,6 +7816,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<NetworkAgentInfo> 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.
}
}
}
@@ -7851,6 +7879,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.linkProperties,
networkCapabilities,
extras);
nai.setConnectivityReport(report);
final List<IConnectivityDiagnosticsCallback> results =
getMatchingPermissionedCallbacks(nai);
for (final IConnectivityDiagnosticsCallback cb : results) {

View File

@@ -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<NetworkAgentInfo> {
// 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,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
}
/**
* Sets the most recent ConnectivityReport for this network.
*
* <p>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.
*
* <p>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() {
return "NetworkAgentInfo{"
+ "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{"

View File

@@ -316,6 +316,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;
@@ -6909,6 +6911,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);