Merge "Add callback registration in ConnectivityService." am: 29edc0ecc9 am: 89a5e805f9 am: 7d4ebb11d6
Change-Id: I596d4788f6d35f1adf110d8edd390f5632b4dc06
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user