Support requesting async LinkProperties/NetworkCapabilities updates

Bug: 9580643
Change-Id: I1d7ba7645c20d7d53f6eef777dfce43727940f13
This commit is contained in:
Erik Kline
2016-07-07 16:50:58 +09:00
parent 1a1cb0e914
commit 0c04b74781
4 changed files with 270 additions and 90 deletions

View File

@@ -1034,6 +1034,26 @@ public class ConnectivityManager {
} }
} }
/**
* Request that this callback be invoked at ConnectivityService's earliest
* convenience with the current satisfying network's LinkProperties.
* If no such network exists no callback invocation is performed.
*
* The callback must have been registered with #requestNetwork() or
* #registerDefaultNetworkCallback(); callbacks registered with
* registerNetworkCallback() are not specific to any particular Network so
* do not cause any updates.
*
* @hide
*/
public void requestLinkProperties(NetworkCallback networkCallback) {
try {
mService.requestLinkProperties(networkCallback.networkRequest);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** /**
* Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This * Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This
* will return {@code null} if the network is unknown. * will return {@code null} if the network is unknown.
@@ -1051,6 +1071,26 @@ public class ConnectivityManager {
} }
} }
/**
* Request that this callback be invoked at ConnectivityService's earliest
* convenience with the current satisfying network's NetworkCapabilities.
* If no such network exists no callback invocation is performed.
*
* The callback must have been registered with #requestNetwork() or
* #registerDefaultNetworkCallback(); callbacks registered with
* registerNetworkCallback() are not specific to any particular Network so
* do not cause any updates.
*
* @hide
*/
public void requestNetworkCapabilities(NetworkCallback networkCallback) {
try {
mService.requestNetworkCapabilities(networkCallback.networkRequest);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/** /**
* Gets the URL that should be used for resolving whether a captive portal is present. * Gets the URL that should be used for resolving whether a captive portal is present.
* 1. This URL should respond with a 204 response to a GET request to indicate no captive * 1. This URL should respond with a 204 response to a GET request to indicate no captive

View File

@@ -156,6 +156,8 @@ interface IConnectivityManager
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities, void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation); in PendingIntent operation);
void requestLinkProperties(in NetworkRequest networkRequest);
void requestNetworkCapabilities(in NetworkRequest networkRequest);
void releaseNetworkRequest(in NetworkRequest networkRequest); void releaseNetworkRequest(in NetworkRequest networkRequest);
void setAcceptUnvalidated(in Network network, boolean accept, boolean always); void setAcceptUnvalidated(in Network network, boolean accept, boolean always);

View File

@@ -303,7 +303,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
/** /**
* indicates a timeout period is over - check if we had a network yet or not * indicates a timeout period is over - check if we had a network yet or not
* and if not, call the timeout calback (but leave the request live until they * and if not, call the timeout callback (but leave the request live until they
* cancel it. * cancel it.
* includes a NetworkRequestInfo * includes a NetworkRequestInfo
*/ */
@@ -380,6 +380,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/ */
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31; private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
/**
* Indicates a caller has requested to have its callback invoked with
* the latest LinkProperties or NetworkCapabilities.
*
* arg1 = UID of caller
* obj = NetworkRequest
*/
private static final int EVENT_REQUEST_LINKPROPERTIES = 32;
private static final int EVENT_REQUEST_NETCAPABILITIES = 33;
/** Handler thread used for both of the handlers below. */ /** Handler thread used for both of the handlers below. */
@VisibleForTesting @VisibleForTesting
protected final HandlerThread mHandlerThread; protected final HandlerThread mHandlerThread;
@@ -2447,13 +2457,54 @@ public class ConnectivityService extends IConnectivityManager.Stub
return true; return true;
} }
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) { private NetworkRequestInfo getNriForAppRequest(
NetworkRequestInfo nri = mNetworkRequests.get(request); NetworkRequest request, int callingUid, String requestedOperation) {
final NetworkRequestInfo nri = mNetworkRequests.get(request);
if (nri != null) { if (nri != null) {
if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) { if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
if (DBG) log("Attempt to release unowned NetworkRequest " + request); log(String.format("UID %d attempted to %s for unowned request %s",
return; callingUid, requestedOperation, nri));
return null;
} }
}
return nri;
}
private void handleRequestCallbackUpdate(NetworkRequest request, int callingUid,
String description, int callbackType) {
final NetworkRequestInfo nri = getNriForAppRequest(request, callingUid, description);
if (nri == null) return;
final NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
// The network that is satisfying this request may have changed since
// the application requested the update.
//
// - If the request is no longer satisfied, don't send any updates.
// - If the request is satisfied by a different network, it is the
// caller's responsibility to check that the Network object in the
// callback matches the network that was returned in the last
// onAvailable() callback for this request.
if (nai == null) return;
callCallbackForRequest(nri, nai, callbackType, 0);
}
private void handleRequestLinkProperties(NetworkRequest request, int callingUid) {
handleRequestCallbackUpdate(request, callingUid,
"request LinkProperties", ConnectivityManager.CALLBACK_IP_CHANGED);
}
private void handleRequestNetworkCapabilities(NetworkRequest request, int callingUid) {
handleRequestCallbackUpdate(request, callingUid,
"request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED);
}
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
final NetworkRequestInfo nri = getNriForAppRequest(
request, callingUid, "release NetworkRequest");
if (nri == null) return;
if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request); if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request);
nri.unlinkDeathRecipient(); nri.unlinkDeathRecipient();
mNetworkRequests.remove(request); mNetworkRequests.remove(request);
@@ -2547,7 +2598,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0); callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
} }
}
@Override @Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) { public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
@@ -2709,6 +2759,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
handleMobileDataAlwaysOn(); handleMobileDataAlwaysOn();
break; break;
} }
case EVENT_REQUEST_LINKPROPERTIES:
handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
break;
case EVENT_REQUEST_NETCAPABILITIES:
handleRequestNetworkCapabilities((NetworkRequest) msg.obj, msg.arg1);
break;
// Sent by KeepaliveTracker to process an app request on the state machine thread. // Sent by KeepaliveTracker to process an app request on the state machine thread.
case NetworkAgent.CMD_START_PACKET_KEEPALIVE: { case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
mKeepaliveTracker.handleStartKeepalive(msg); mKeepaliveTracker.handleStartKeepalive(msg);
@@ -4169,11 +4225,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
} }
@Override
public void requestLinkProperties(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
if (networkRequest.type == NetworkRequest.Type.LISTEN) return;
mHandler.sendMessage(mHandler.obtainMessage(
EVENT_REQUEST_LINKPROPERTIES, getCallingUid(), 0, networkRequest));
}
@Override
public void requestNetworkCapabilities(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
if (networkRequest.type == NetworkRequest.Type.LISTEN) return;
mHandler.sendMessage(mHandler.obtainMessage(
EVENT_REQUEST_NETCAPABILITIES, getCallingUid(), 0, networkRequest));
}
@Override @Override
public void releaseNetworkRequest(NetworkRequest networkRequest) { public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest); ensureNetworkRequestHasType(networkRequest);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), mHandler.sendMessage(mHandler.obtainMessage(
0, networkRequest)); EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest));
} }
@Override @Override

View File

@@ -1040,6 +1040,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
enum CallbackState { enum CallbackState {
NONE, NONE,
AVAILABLE, AVAILABLE,
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
LOSING, LOSING,
LOST LOST
} }
@@ -1072,18 +1074,21 @@ public class ConnectivityServiceTest extends AndroidTestCase {
} }
private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>(); private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
private void setLastCallback(CallbackState state, Network network, Object o) { protected void setLastCallback(CallbackState state, Network network, Object o) {
mCallbacks.offer(new CallbackInfo(state, network, o)); mCallbacks.offer(new CallbackInfo(state, network, o));
} }
@Override
public void onAvailable(Network network) { public void onAvailable(Network network) {
setLastCallback(CallbackState.AVAILABLE, network, null); setLastCallback(CallbackState.AVAILABLE, network, null);
} }
@Override
public void onLosing(Network network, int maxMsToLive) { public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */); setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
} }
@Override
public void onLost(Network network) { public void onLost(Network network) {
setLastCallback(CallbackState.LOST, network, null); setLastCallback(CallbackState.LOST, network, null);
} }
@@ -1744,6 +1749,67 @@ public class ConnectivityServiceTest extends AndroidTestCase {
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
} }
private class TestRequestUpdateCallback extends TestNetworkCallback {
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
}
}
@LargeTest
public void testRequestCallbackUpdates() throws Exception {
// File a network request for mobile.
final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
// Bring up the mobile network.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
// We should get onAvailable().
cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
// We should get onCapabilitiesChanged(), when the mobile network successfully validates.
cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Update LinkProperties.
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName("foonet_data0");
mCellNetworkAgent.sendLinkProperties(lp);
// We should get onLinkPropertiesChanged().
cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Register a garden variety default network request.
final TestNetworkCallback dfltNetworkCallback = new TestRequestUpdateCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
// Only onAvailable() is called; no other information is delivered.
dfltNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
dfltNetworkCallback.assertNoCallback();
// Request a NetworkCapabilities update; only the requesting callback is notified.
mCm.requestNetworkCapabilities(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback.assertNoCallback();
// Request a LinkProperties update; only the requesting callback is notified.
mCm.requestLinkProperties(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback.assertNoCallback();
mCm.unregisterNetworkCallback(dfltNetworkCallback);
mCm.unregisterNetworkCallback(cellNetworkCallback);
}
@SmallTest @SmallTest
public void testRequestBenchmark() throws Exception { public void testRequestBenchmark() throws Exception {
// Benchmarks connecting and switching performance in the presence of a large number of // Benchmarks connecting and switching performance in the presence of a large number of