Merge "Update UpstreamNetworkMonitor to use custom Handlers"

am: 35c89886c2

Change-Id: I76433822a9b7c124e4b7cfcf2a20cb0e43a60199
This commit is contained in:
Erik Kline
2017-02-24 08:15:19 +00:00
committed by android-build-merger
3 changed files with 115 additions and 34 deletions

View File

@@ -2930,15 +2930,6 @@ public class ConnectivityManager {
* @hide * @hide
*/ */
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback, public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs, int legacyType) {
requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
}
/**
* Helper function to request a network with a particular legacy type.
* @hide
*/
private void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs, int legacyType, Handler handler) { int timeoutMs, int legacyType, Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler); CallbackHandler cbHandler = new CallbackHandler(handler);
NetworkCapabilities nc = request.networkCapabilities; NetworkCapabilities nc = request.networkCapabilities;
@@ -3040,7 +3031,7 @@ public class ConnectivityManager {
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback, public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
int timeoutMs) { int timeoutMs) {
int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities); int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
requestNetwork(request, networkCallback, timeoutMs, legacyType); requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
} }

View File

@@ -20,6 +20,8 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -72,6 +74,7 @@ public class UpstreamNetworkMonitor {
private final Context mContext; private final Context mContext;
private final StateMachine mTarget; private final StateMachine mTarget;
private final Handler mHandler;
private final int mWhat; private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
private ConnectivityManager mCM; private ConnectivityManager mCM;
@@ -84,6 +87,7 @@ public class UpstreamNetworkMonitor {
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) { public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
mContext = ctx; mContext = ctx;
mTarget = tgt; mTarget = tgt;
mHandler = mTarget.getHandler();
mWhat = what; mWhat = what;
} }
@@ -99,10 +103,10 @@ public class UpstreamNetworkMonitor {
final NetworkRequest listenAllRequest = new NetworkRequest.Builder() final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
.clearCapabilities().build(); .clearCapabilities().build();
mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL); mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
cm().registerNetworkCallback(listenAllRequest, mListenAllCallback); cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT); mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
cm().registerDefaultNetworkCallback(mDefaultNetworkCallback); cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
} }
public void stop() { public void stop() {
@@ -154,7 +158,7 @@ public class UpstreamNetworkMonitor {
// Additionally, we log a message to aid in any subsequent debugging. // Additionally, we log a message to aid in any subsequent debugging.
Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest); Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType); cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
} }
public void releaseMobileNetworkRequest() { public void releaseMobileNetworkRequest() {
@@ -185,11 +189,13 @@ public class UpstreamNetworkMonitor {
case CALLBACK_TRACK_DEFAULT: case CALLBACK_TRACK_DEFAULT:
if (mDefaultNetworkCallback == null) { if (mDefaultNetworkCallback == null) {
// The callback was unregistered in the interval between // The callback was unregistered in the interval between
// ConnectivityService calling onAvailable() and our // ConnectivityService enqueueing onAvailable() and our
// handling of it here on the mTarget.getHandler() thread. // handling of it here on the mHandler thread.
//
// Clean-up of this network entry is deferred to the // Clean-up of this network entry is deferred to the
// handling of onLost() by other callbacks. // handling of onLost() by other callbacks.
// TODO: change to Log.wtf() after oag/331764 is merged. //
// These request*() calls can be deleted post oag/339444.
return; return;
} }
@@ -200,11 +206,13 @@ public class UpstreamNetworkMonitor {
case CALLBACK_MOBILE_REQUEST: case CALLBACK_MOBILE_REQUEST:
if (mMobileNetworkCallback == null) { if (mMobileNetworkCallback == null) {
// The callback was unregistered in the interval between // The callback was unregistered in the interval between
// ConnectivityService calling onAvailable() and our // ConnectivityService enqueueing onAvailable() and our
// handling of it here on the mTarget.getHandler() thread. // handling of it here on the mHandler thread.
//
// Clean-up of this network entry is deferred to the // Clean-up of this network entry is deferred to the
// handling of onLost() by other callbacks. // handling of onLost() by other callbacks.
// TODO: change to Log.wtf() after oag/331764 is merged. //
// These request*() calls can be deleted post oag/339444.
return; return;
} }
@@ -312,8 +320,9 @@ public class UpstreamNetworkMonitor {
} }
/** /**
* A NetworkCallback class that relays information of interest to the * A NetworkCallback class that handles information of interest directly
* tethering master state machine thread for subsequent processing. * in the thread on which it is invoked. To avoid locking, this MUST be
* run on the same thread as the target state machine's handler.
*/ */
private class UpstreamNetworkCallback extends NetworkCallback { private class UpstreamNetworkCallback extends NetworkCallback {
private final int mCallbackType; private final int mCallbackType;
@@ -324,22 +333,35 @@ public class UpstreamNetworkMonitor {
@Override @Override
public void onAvailable(Network network) { public void onAvailable(Network network) {
mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network)); checkExpectedThread();
handleAvailable(mCallbackType, network);
} }
@Override @Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
mTarget.getHandler().post(() -> handleNetCap(network, newNc)); checkExpectedThread();
handleNetCap(network, newNc);
} }
@Override @Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
mTarget.getHandler().post(() -> handleLinkProp(network, newLp)); checkExpectedThread();
handleLinkProp(network, newLp);
} }
// TODO: Handle onNetworkSuspended();
// TODO: Handle onNetworkResumed();
@Override @Override
public void onLost(Network network) { public void onLost(Network network) {
mTarget.getHandler().post(() -> handleLost(mCallbackType, network)); checkExpectedThread();
handleLost(mCallbackType, network);
}
private void checkExpectedThread() {
if (Looper.myLooper() != mHandler.getLooper()) {
Log.wtf(TAG, "Handling callback in unexpected thread.");
}
} }
} }

View File

@@ -32,6 +32,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager; import android.net.IConnectivityManager;
@@ -42,6 +44,10 @@ import android.net.NetworkRequest;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.Test; import org.junit.Test;
@@ -49,6 +55,7 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@@ -63,6 +70,7 @@ public class UpstreamNetworkMonitorTest {
@Mock private Context mContext; @Mock private Context mContext;
@Mock private IConnectivityManager mCS; @Mock private IConnectivityManager mCS;
private TestStateMachine mSM;
private TestConnectivityManager mCM; private TestConnectivityManager mCM;
private UpstreamNetworkMonitor mUNM; private UpstreamNetworkMonitor mUNM;
@@ -72,7 +80,15 @@ public class UpstreamNetworkMonitorTest {
reset(mCS); reset(mCS);
mCM = spy(new TestConnectivityManager(mContext, mCS)); mCM = spy(new TestConnectivityManager(mContext, mCS));
mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM); mSM = new TestStateMachine();
mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
}
@After public void tearDown() throws Exception {
if (mSM != null) {
mSM.quit();
mSM = null;
}
} }
@Test @Test
@@ -139,15 +155,17 @@ public class UpstreamNetworkMonitorTest {
mUNM.start(); mUNM.start();
verify(mCM, Mockito.times(1)).registerNetworkCallback( verify(mCM, Mockito.times(1)).registerNetworkCallback(
any(NetworkRequest.class), any(NetworkCallback.class)); any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class)); verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
any(NetworkCallback.class), any(Handler.class));
assertFalse(mUNM.mobileNetworkRequested()); assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size()); assertEquals(0, mCM.requested.size());
mUNM.updateMobileRequiresDun(true); mUNM.updateMobileRequiresDun(true);
mUNM.registerMobileNetworkRequest(); mUNM.registerMobileNetworkRequest();
verify(mCM, Mockito.times(1)).requestNetwork( verify(mCM, Mockito.times(1)).requestNetwork(
any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt()); any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
any(Handler.class));
assertTrue(mUNM.mobileNetworkRequested()); assertTrue(mUNM.mobileNetworkRequested());
assertUpstreamTypeRequested(TYPE_MOBILE_DUN); assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
@@ -224,6 +242,7 @@ public class UpstreamNetworkMonitorTest {
} }
public static class TestConnectivityManager extends ConnectivityManager { public static class TestConnectivityManager extends ConnectivityManager {
public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
public Set<NetworkCallback> trackingDefault = new HashSet<>(); public Set<NetworkCallback> trackingDefault = new HashSet<>();
public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>(); public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>(); public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -234,7 +253,8 @@ public class UpstreamNetworkMonitorTest {
} }
boolean hasNoCallbacks() { boolean hasNoCallbacks() {
return trackingDefault.isEmpty() && return allCallbacks.isEmpty() &&
trackingDefault.isEmpty() &&
listening.isEmpty() && listening.isEmpty() &&
requested.isEmpty() && requested.isEmpty() &&
legacyTypeMap.isEmpty(); legacyTypeMap.isEmpty();
@@ -262,14 +282,23 @@ public class UpstreamNetworkMonitorTest {
} }
@Override @Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb) { public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
assertFalse(allCallbacks.containsKey(cb));
allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb)); assertFalse(requested.containsKey(cb));
requested.put(cb, req); requested.put(cb, req);
} }
@Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
fail("Should never be called.");
}
@Override @Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb, public void requestNetwork(NetworkRequest req, NetworkCallback cb,
int timeoutMs, int legacyType) { int timeoutMs, int legacyType, Handler h) {
assertFalse(allCallbacks.containsKey(cb));
allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb)); assertFalse(requested.containsKey(cb));
requested.put(cb, req); requested.put(cb, req);
assertFalse(legacyTypeMap.containsKey(cb)); assertFalse(legacyTypeMap.containsKey(cb));
@@ -279,17 +308,31 @@ public class UpstreamNetworkMonitorTest {
} }
@Override @Override
public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) { public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
assertFalse(allCallbacks.containsKey(cb));
allCallbacks.put(cb, h);
assertFalse(listening.containsKey(cb)); assertFalse(listening.containsKey(cb));
listening.put(cb, req); listening.put(cb, req);
} }
@Override @Override
public void registerDefaultNetworkCallback(NetworkCallback cb) { public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
fail("Should never be called.");
}
@Override
public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
assertFalse(allCallbacks.containsKey(cb));
allCallbacks.put(cb, h);
assertFalse(trackingDefault.contains(cb)); assertFalse(trackingDefault.contains(cb));
trackingDefault.add(cb); trackingDefault.add(cb);
} }
@Override
public void registerDefaultNetworkCallback(NetworkCallback cb) {
fail("Should never be called.");
}
@Override @Override
public void unregisterNetworkCallback(NetworkCallback cb) { public void unregisterNetworkCallback(NetworkCallback cb) {
if (trackingDefault.contains(cb)) { if (trackingDefault.contains(cb)) {
@@ -302,10 +345,35 @@ public class UpstreamNetworkMonitorTest {
} else { } else {
fail("Unexpected callback removed"); fail("Unexpected callback removed");
} }
allCallbacks.remove(cb);
assertFalse(allCallbacks.containsKey(cb));
assertFalse(trackingDefault.contains(cb)); assertFalse(trackingDefault.contains(cb));
assertFalse(listening.containsKey(cb)); assertFalse(listening.containsKey(cb));
assertFalse(requested.containsKey(cb)); assertFalse(requested.containsKey(cb));
} }
} }
public static class TestStateMachine extends StateMachine {
public final ArrayList<Message> messages = new ArrayList<>();
private final State mLoggingState = new LoggingState();
class LoggingState extends State {
@Override public void enter() { messages.clear(); }
@Override public void exit() { messages.clear(); }
@Override public boolean processMessage(Message msg) {
messages.add(msg);
return true;
}
}
public TestStateMachine() {
super("UpstreamNetworkMonitor.TestStateMachine");
addState(mLoggingState);
setInitialState(mLoggingState);
super.start();
}
}
} }