Merge "Add callback registration in ConnectivityService." am: 29edc0ecc9 am: 89a5e805f9 am: 7d4ebb11d6

Change-Id: I596d4788f6d35f1adf110d8edd390f5632b4dc06
This commit is contained in:
Automerger Merge Worker
2020-02-03 15:18:18 +00:00
4 changed files with 350 additions and 29 deletions

View File

@@ -25,13 +25,16 @@ import android.os.Binder;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.os.RemoteException;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
/** /**
@@ -57,6 +60,11 @@ import java.util.concurrent.Executor;
* </ul> * </ul>
*/ */
public class ConnectivityDiagnosticsManager { public class ConnectivityDiagnosticsManager {
/** @hide */
@VisibleForTesting
public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder>
sCallbacks = new ConcurrentHashMap<>();
private final Context mContext; private final Context mContext;
private final IConnectivityManager mService; private final IConnectivityManager mService;
@@ -646,9 +654,9 @@ public class ConnectivityDiagnosticsManager {
* <p>If a registering app loses its relevant permissions, any callbacks it registered will * <p>If a registering app loses its relevant permissions, any callbacks it registered will
* silently stop receiving callbacks. * silently stop receiving callbacks.
* *
* <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If * <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is
* a single instance is registered with multiple NetworkRequests, an IllegalArgumentException * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
* will be thrown. * multiple NetworkRequests, an IllegalArgumentException will be thrown.
* *
* @param request The NetworkRequest that will be used to match with Networks for which * @param request The NetworkRequest that will be used to match with Networks for which
* callbacks will be fired * callbacks will be fired
@@ -657,15 +665,21 @@ public class ConnectivityDiagnosticsManager {
* System * System
* @throws IllegalArgumentException if the same callback instance is registered with multiple * @throws IllegalArgumentException if the same callback instance is registered with multiple
* NetworkRequests * NetworkRequests
* @throws SecurityException if the caller does not have appropriate permissions to register a
* callback
*/ */
public void registerConnectivityDiagnosticsCallback( public void registerConnectivityDiagnosticsCallback(
@NonNull NetworkRequest request, @NonNull NetworkRequest request,
@NonNull Executor e, @NonNull Executor e,
@NonNull ConnectivityDiagnosticsCallback callback) { @NonNull ConnectivityDiagnosticsCallback callback) {
// TODO(b/143187964): implement ConnectivityDiagnostics functionality final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e);
throw new UnsupportedOperationException("registerCallback() not supported yet"); if (sCallbacks.putIfAbsent(callback, binder) != null) {
throw new IllegalArgumentException("Callback is currently registered");
}
try {
mService.registerConnectivityDiagnosticsCallback(binder, request);
} catch (RemoteException exception) {
exception.rethrowFromSystemServer();
}
} }
/** /**
@@ -678,7 +692,15 @@ public class ConnectivityDiagnosticsManager {
*/ */
public void unregisterConnectivityDiagnosticsCallback( public void unregisterConnectivityDiagnosticsCallback(
@NonNull ConnectivityDiagnosticsCallback callback) { @NonNull ConnectivityDiagnosticsCallback callback) {
// TODO(b/143187964): implement ConnectivityDiagnostics functionality // unconditionally removing from sCallbacks prevents race conditions here, since remove() is
throw new UnsupportedOperationException("registerCallback() not supported yet"); // atomic.
final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback);
if (binder == null) return;
try {
mService.unregisterConnectivityDiagnosticsCallback(binder);
} catch (RemoteException exception) {
exception.rethrowFromSystemServer();
}
} }
} }

View File

@@ -557,13 +557,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
.asInterface(ServiceManager.getService("dnsresolver")); .asInterface(ServiceManager.getService("dnsresolver"));
} }
/** Handler thread used for both of the handlers below. */ /** Handler thread used for all of the handlers below. */
@VisibleForTesting @VisibleForTesting
protected final HandlerThread mHandlerThread; protected final HandlerThread mHandlerThread;
/** Handler used for internal events. */ /** Handler used for internal events. */
final private InternalHandler mHandler; final private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */ /** Handler used for incoming {@link NetworkStateTracker} events. */
final private NetworkStateTrackerHandler mTrackerHandler; final private NetworkStateTrackerHandler mTrackerHandler;
/** Handler used for processing {@link android.net.ConnectivityDiagnosticsManager} events */
@VisibleForTesting
final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
private final DnsManager mDnsManager; private final DnsManager mDnsManager;
private boolean mSystemReady; private boolean mSystemReady;
@@ -630,6 +634,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
@VisibleForTesting @VisibleForTesting
final MultipathPolicyTracker mMultipathPolicyTracker; final MultipathPolicyTracker mMultipathPolicyTracker;
@VisibleForTesting
final Map<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo>
mConnectivityDiagnosticsCallbacks = new HashMap<>();
/** /**
* Implements support for the legacy "one network per network type" model. * Implements support for the legacy "one network per network type" model.
* *
@@ -962,6 +970,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandlerThread.start(); mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper()); mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper()); mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
mConnectivityDiagnosticsHandler =
new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(), mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000); Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
@@ -3391,18 +3401,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
nri.unlinkDeathRecipient(); nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request); mNetworkRequests.remove(nri.request);
synchronized (mUidToNetworkRequestCount) { decrementNetworkRequestPerUidCount(nri);
int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
if (requests < 1) {
Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " +
nri.mUid);
} else if (requests == 1) {
mUidToNetworkRequestCount.removeAt(
mUidToNetworkRequestCount.indexOfKey(nri.mUid));
} else {
mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
}
}
mNetworkRequestInfoLogs.log("RELEASE " + nri); mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) { if (nri.request.isRequest()) {
@@ -3473,6 +3472,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) {
synchronized (mUidToNetworkRequestCount) {
final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
if (requests < 1) {
Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
} else if (requests == 1) {
mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
} else {
mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
}
}
}
@Override @Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup(); enforceNetworkStackSettingsOrSetup();
@@ -5091,6 +5103,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
NetworkRequestInfo(NetworkRequest r) {
this(r, null);
}
private void enforceRequestCountLimit() { private void enforceRequestCountLimit() {
synchronized (mUidToNetworkRequestCount) { synchronized (mUidToNetworkRequestCount) {
int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1; int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
@@ -6165,7 +6181,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void callCallbackForRequest(NetworkRequestInfo nri, private void callCallbackForRequest(NetworkRequestInfo nri,
NetworkAgentInfo networkAgent, int notificationType, int arg1) { NetworkAgentInfo networkAgent, int notificationType, int arg1) {
if (nri.messenger == null) { if (nri.messenger == null) {
return; // Default request has no msgr // Default request has no msgr. Also prevents callbacks from being invoked for
// NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
// are Type.LISTEN, but should not have NetworkCallbacks invoked.
return;
} }
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
// TODO: check if defensive copies of data is needed. // TODO: check if defensive copies of data is needed.
@@ -7321,19 +7340,161 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
/**
* Handler used for managing all Connectivity Diagnostics related functions.
*
* @see android.net.ConnectivityDiagnosticsManager
*
* TODO(b/147816404): Explore moving ConnectivityDiagnosticsHandler to a separate file
*/
@VisibleForTesting
class ConnectivityDiagnosticsHandler extends Handler {
/**
* Used to handle ConnectivityDiagnosticsCallback registration events from {@link
* android.net.ConnectivityDiagnosticsManager}.
* obj = ConnectivityDiagnosticsCallbackInfo with IConnectivityDiagnosticsCallback and
* NetworkRequestInfo to be registered
*/
private static final int EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 1;
/**
* Used to handle ConnectivityDiagnosticsCallback unregister events from {@link
* android.net.ConnectivityDiagnosticsManager}.
* obj = the IConnectivityDiagnosticsCallback to be unregistered
* arg1 = the uid of the caller
*/
private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2;
private ConnectivityDiagnosticsHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: {
handleRegisterConnectivityDiagnosticsCallback(
(ConnectivityDiagnosticsCallbackInfo) msg.obj);
break;
}
case EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: {
handleUnregisterConnectivityDiagnosticsCallback(
(IConnectivityDiagnosticsCallback) msg.obj, msg.arg1);
break;
}
}
}
}
/** Class used for cleaning up IConnectivityDiagnosticsCallback instances after their death. */
@VisibleForTesting
class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient {
@NonNull private final IConnectivityDiagnosticsCallback mCb;
@NonNull private final NetworkRequestInfo mRequestInfo;
@VisibleForTesting
ConnectivityDiagnosticsCallbackInfo(
@NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri) {
mCb = cb;
mRequestInfo = nri;
}
@Override
public void binderDied() {
log("ConnectivityDiagnosticsCallback IBinder died.");
unregisterConnectivityDiagnosticsCallback(mCb);
}
}
private void handleRegisterConnectivityDiagnosticsCallback(
@NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) {
ensureRunningOnConnectivityServiceThread();
final IConnectivityDiagnosticsCallback cb = cbInfo.mCb;
final NetworkRequestInfo nri = cbInfo.mRequestInfo;
// This means that the client registered the same callback multiple times. Do
// not override the previous entry, and exit silently.
if (mConnectivityDiagnosticsCallbacks.containsKey(cb)) {
if (VDBG) log("Diagnostics callback is already registered");
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
decrementNetworkRequestPerUidCount(nri);
return;
}
mConnectivityDiagnosticsCallbacks.put(cb, cbInfo);
try {
cb.asBinder().linkToDeath(cbInfo, 0);
} catch (RemoteException e) {
cbInfo.binderDied();
}
}
private void handleUnregisterConnectivityDiagnosticsCallback(
@NonNull IConnectivityDiagnosticsCallback cb, int uid) {
ensureRunningOnConnectivityServiceThread();
if (!mConnectivityDiagnosticsCallbacks.containsKey(cb)) {
if (VDBG) log("Removing diagnostics callback that is not currently registered");
return;
}
final NetworkRequestInfo nri = mConnectivityDiagnosticsCallbacks.get(cb).mRequestInfo;
if (uid != nri.mUid) {
if (VDBG) loge("Different uid than registrant attempting to unregister cb");
return;
}
cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0);
}
@Override @Override
public void registerConnectivityDiagnosticsCallback( public void registerConnectivityDiagnosticsCallback(
@NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) { @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) {
// TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality if (request.legacyType != TYPE_NONE) {
throw new UnsupportedOperationException( throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
"registerConnectivityDiagnosticsCallback not yet implemented"); + " Please use NetworkCapabilities instead.");
}
// This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
// and administrator uids to be safe.
final NetworkCapabilities nc = new NetworkCapabilities(request.networkCapabilities);
restrictRequestUidsForCaller(nc);
final NetworkRequest requestWithId =
new NetworkRequest(
nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN);
// NetworkRequestInfos created here count towards MAX_NETWORK_REQUESTS_PER_UID limit.
//
// nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in
// handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
// callback's binder death.
final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
final ConnectivityDiagnosticsCallbackInfo cbInfo =
new ConnectivityDiagnosticsCallbackInfo(callback, nri);
mConnectivityDiagnosticsHandler.sendMessage(
mConnectivityDiagnosticsHandler.obtainMessage(
ConnectivityDiagnosticsHandler
.EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
cbInfo));
} }
@Override @Override
public void unregisterConnectivityDiagnosticsCallback( public void unregisterConnectivityDiagnosticsCallback(
@NonNull IConnectivityDiagnosticsCallback callback) { @NonNull IConnectivityDiagnosticsCallback callback) {
// TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality mConnectivityDiagnosticsHandler.sendMessage(
throw new UnsupportedOperationException( mConnectivityDiagnosticsHandler.obtainMessage(
"unregisterConnectivityDiagnosticsCallback not yet implemented"); ConnectivityDiagnosticsHandler
.EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
Binder.getCallingUid(),
0,
callback));
} }
} }

View File

@@ -27,12 +27,18 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -52,15 +58,27 @@ public class ConnectivityDiagnosticsManagerTest {
private static final Executor INLINE_EXECUTOR = x -> x.run(); private static final Executor INLINE_EXECUTOR = x -> x.run();
@Mock private Context mContext;
@Mock private IConnectivityManager mService;
@Mock private ConnectivityDiagnosticsCallback mCb; @Mock private ConnectivityDiagnosticsCallback mCb;
private ConnectivityDiagnosticsBinder mBinder; private ConnectivityDiagnosticsBinder mBinder;
private ConnectivityDiagnosticsManager mManager;
@Before @Before
public void setUp() { public void setUp() {
mContext = mock(Context.class);
mService = mock(IConnectivityManager.class);
mCb = mock(ConnectivityDiagnosticsCallback.class); mCb = mock(ConnectivityDiagnosticsCallback.class);
mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR); mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
mManager = new ConnectivityDiagnosticsManager(mContext, mService);
}
@After
public void tearDown() {
// clear ConnectivityDiagnosticsManager callbacks map
ConnectivityDiagnosticsManager.sCallbacks.clear();
} }
private ConnectivityReport createSampleConnectivityReport() { private ConnectivityReport createSampleConnectivityReport() {
@@ -245,4 +263,53 @@ public class ConnectivityDiagnosticsManagerTest {
// latch without waiting. // latch without waiting.
verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity)); verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
} }
@Test
public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
verify(mService).registerConnectivityDiagnosticsCallback(
any(ConnectivityDiagnosticsBinder.class), eq(request));
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
}
@Test
public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
try {
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
fail("Duplicate callback registration should fail");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testUnregisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest request = new NetworkRequest.Builder().build();
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
mManager.unregisterConnectivityDiagnosticsCallback(mCb);
verify(mService).unregisterConnectivityDiagnosticsCallback(
any(ConnectivityDiagnosticsBinder.class));
assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
// verify that re-registering is successful
mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
any(ConnectivityDiagnosticsBinder.class), eq(request));
assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
}
@Test
public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception {
mManager.unregisterConnectivityDiagnosticsCallback(mCb);
verifyNoMoreInteractions(mService);
}
} }

View File

@@ -139,6 +139,7 @@ import android.net.ConnectivityManager.PacketKeepalive;
import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException; import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread; import android.net.ConnectivityThread;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.IDnsResolver; import android.net.IDnsResolver;
import android.net.IIpConnectivityMetrics; import android.net.IIpConnectivityMetrics;
import android.net.INetd; import android.net.INetd;
@@ -180,6 +181,7 @@ import android.os.Bundle;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.IBinder;
import android.os.INetworkManagementService; import android.os.INetworkManagementService;
import android.os.Looper; import android.os.Looper;
import android.os.Parcel; import android.os.Parcel;
@@ -210,6 +212,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.WakeupMessage; import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.connectivity.ConnectivityConstants; import com.android.server.connectivity.ConnectivityConstants;
import com.android.server.connectivity.DefaultNetworkMetrics; import com.android.server.connectivity.DefaultNetworkMetrics;
import com.android.server.connectivity.IpConnectivityMetrics; import com.android.server.connectivity.IpConnectivityMetrics;
@@ -322,6 +325,8 @@ public class ConnectivityServiceTest {
@Mock UserManager mUserManager; @Mock UserManager mUserManager;
@Mock NotificationManager mNotificationManager; @Mock NotificationManager mNotificationManager;
@Mock AlarmManager mAlarmManager; @Mock AlarmManager mAlarmManager;
@Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
@Mock IBinder mIBinder;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class); ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -6355,4 +6360,70 @@ public class ConnectivityServiceTest {
UserHandle.getAppId(uid)); UserHandle.getAppId(uid));
return packageInfo; return packageInfo;
} }
@Test
public void testRegisterConnectivityDiagnosticsCallbackInvalidRequest() throws Exception {
final NetworkRequest request =
new NetworkRequest(
new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
try {
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, request);
fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest wifiRequest =
new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, wifiRequest);
verify(mIBinder, timeout(TIMEOUT_MS))
.linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
assertTrue(
mService.mConnectivityDiagnosticsCallbacks.containsKey(
mConnectivityDiagnosticsCallback));
mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback);
verify(mIBinder, timeout(TIMEOUT_MS))
.unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
assertFalse(
mService.mConnectivityDiagnosticsCallbacks.containsKey(
mConnectivityDiagnosticsCallback));
verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder();
}
@Test
public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
final NetworkRequest wifiRequest =
new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, wifiRequest);
verify(mIBinder, timeout(TIMEOUT_MS))
.linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
verify(mConnectivityDiagnosticsCallback).asBinder();
assertTrue(
mService.mConnectivityDiagnosticsCallbacks.containsKey(
mConnectivityDiagnosticsCallback));
// Register the same callback again
mService.registerConnectivityDiagnosticsCallback(
mConnectivityDiagnosticsCallback, wifiRequest);
// Block until all other events are done processing.
HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
assertTrue(
mService.mConnectivityDiagnosticsCallbacks.containsKey(
mConnectivityDiagnosticsCallback));
}
} }