Support timeouts for requestNetwork() invocations. [DO NOT MERGE]
Bug: 21414325 Change-Id: I08118be8e8cf92fc406d431e99a6c9191a863ff3
This commit is contained in:
@@ -2221,7 +2221,8 @@ public class ConnectivityManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called if no network is found in the given timeout time. If no timeout is given,
|
* Called if no network is found in the given timeout time. If no timeout is given,
|
||||||
* this will not be called.
|
* this will not be called. The associated {@link NetworkRequest} will have already
|
||||||
|
* been removed and released, as if {@link #unregisterNetworkCallback} had been called.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void onUnavailable() {}
|
public void onUnavailable() {}
|
||||||
@@ -2294,6 +2295,26 @@ public class ConnectivityManager {
|
|||||||
/** @hide */
|
/** @hide */
|
||||||
public static final int CALLBACK_RESUMED = BASE + 12;
|
public static final int CALLBACK_RESUMED = BASE + 12;
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public static String getCallbackName(int whichCallback) {
|
||||||
|
switch (whichCallback) {
|
||||||
|
case CALLBACK_PRECHECK: return "CALLBACK_PRECHECK";
|
||||||
|
case CALLBACK_AVAILABLE: return "CALLBACK_AVAILABLE";
|
||||||
|
case CALLBACK_LOSING: return "CALLBACK_LOSING";
|
||||||
|
case CALLBACK_LOST: return "CALLBACK_LOST";
|
||||||
|
case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL";
|
||||||
|
case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED";
|
||||||
|
case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED";
|
||||||
|
case CALLBACK_RELEASED: return "CALLBACK_RELEASED";
|
||||||
|
case CALLBACK_EXIT: return "CALLBACK_EXIT";
|
||||||
|
case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
|
||||||
|
case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED";
|
||||||
|
case CALLBACK_RESUMED: return "CALLBACK_RESUMED";
|
||||||
|
default:
|
||||||
|
return Integer.toString(whichCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class CallbackHandler extends Handler {
|
private class CallbackHandler extends Handler {
|
||||||
private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
|
private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
|
||||||
private final AtomicInteger mRefCount;
|
private final AtomicInteger mRefCount;
|
||||||
@@ -2458,7 +2479,7 @@ public class ConnectivityManager {
|
|||||||
private final static int REQUEST = 2;
|
private final static int REQUEST = 2;
|
||||||
|
|
||||||
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
|
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
|
||||||
NetworkCallback networkCallback, int timeoutSec, int action,
|
NetworkCallback networkCallback, int timeoutMs, int action,
|
||||||
int legacyType) {
|
int legacyType) {
|
||||||
if (networkCallback == null) {
|
if (networkCallback == null) {
|
||||||
throw new IllegalArgumentException("null NetworkCallback");
|
throw new IllegalArgumentException("null NetworkCallback");
|
||||||
@@ -2472,7 +2493,7 @@ public class ConnectivityManager {
|
|||||||
new Messenger(sCallbackHandler), new Binder());
|
new Messenger(sCallbackHandler), new Binder());
|
||||||
} else {
|
} else {
|
||||||
networkCallback.networkRequest = mService.requestNetwork(need,
|
networkCallback.networkRequest = mService.requestNetwork(need,
|
||||||
new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
|
new Messenger(sCallbackHandler), timeoutMs, new Binder(), legacyType);
|
||||||
}
|
}
|
||||||
if (networkCallback.networkRequest != null) {
|
if (networkCallback.networkRequest != null) {
|
||||||
sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
|
sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
|
||||||
|
|||||||
@@ -2321,17 +2321,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
|
||||||
|
if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
|
||||||
|
nri.request.requestId) == null) {
|
||||||
|
handleRemoveNetworkRequest(nri, Process.SYSTEM_UID,
|
||||||
|
ConnectivityManager.CALLBACK_UNAVAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
|
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
|
||||||
NetworkRequestInfo nri = mNetworkRequests.get(request);
|
final NetworkRequestInfo nri = mNetworkRequests.get(request);
|
||||||
if (nri != null) {
|
if (nri != null) {
|
||||||
|
handleRemoveNetworkRequest(nri, callingUid, ConnectivityManager.CALLBACK_RELEASED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRemoveNetworkRequest(
|
||||||
|
final NetworkRequestInfo nri, final int callingUid, final int whichCallback) {
|
||||||
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);
|
if (DBG) log("Attempt to release unowned NetworkRequest " + nri.request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DBG) log("releasing NetworkRequest " + request);
|
final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
|
||||||
|
if (DBG) log("releasing NetworkRequest " + nri.request + " (" + logCallbackType + ")");
|
||||||
nri.unlinkDeathRecipient();
|
nri.unlinkDeathRecipient();
|
||||||
mNetworkRequests.remove(request);
|
mNetworkRequests.remove(nri.request);
|
||||||
mNetworkRequestInfoLogs.log("RELEASE " + nri);
|
mNetworkRequestInfoLogs.log("RELEASE " + nri + " (" + logCallbackType + ")");
|
||||||
if (nri.isRequest) {
|
if (nri.isRequest) {
|
||||||
// Find all networks that are satisfying this request and remove the request
|
// Find all networks that are satisfying this request and remove the request
|
||||||
// from their request lists.
|
// from their request lists.
|
||||||
@@ -2401,8 +2416,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
|
callCallbackForRequest(nri, null, whichCallback);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
|
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
|
||||||
@@ -2552,6 +2566,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
handleRegisterNetworkRequestWithIntent(msg);
|
handleRegisterNetworkRequestWithIntent(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EVENT_TIMEOUT_NETWORK_REQUEST: {
|
||||||
|
NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
|
||||||
|
handleTimedOutNetworkRequest(nri);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
|
case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
|
||||||
handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
|
handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -960,7 +960,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
NONE,
|
NONE,
|
||||||
AVAILABLE,
|
AVAILABLE,
|
||||||
LOSING,
|
LOSING,
|
||||||
LOST
|
LOST,
|
||||||
|
UNAVAILABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -990,6 +991,13 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
mConditionVariable.open();
|
mConditionVariable.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnavailable() {
|
||||||
|
assertEquals(CallbackState.NONE, mLastCallback);
|
||||||
|
mLastCallback = CallbackState.UNAVAILABLE;
|
||||||
|
mConditionVariable.open();
|
||||||
|
}
|
||||||
|
|
||||||
void expectCallback(CallbackState state) {
|
void expectCallback(CallbackState state) {
|
||||||
waitFor(mConditionVariable);
|
waitFor(mConditionVariable);
|
||||||
assertEquals(state, mLastCallback);
|
assertEquals(state, mLastCallback);
|
||||||
@@ -1352,6 +1360,83 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
execptionCalled);
|
execptionCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that a satisfied network request does not trigger onUnavailable() once the
|
||||||
|
* time-out period expires.
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
|
||||||
|
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
|
||||||
|
NetworkCapabilities.TRANSPORT_WIFI).build();
|
||||||
|
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
||||||
|
mCm.requestNetwork(nr, networkCallback, 10);
|
||||||
|
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.connect(false);
|
||||||
|
networkCallback.expectCallback(CallbackState.AVAILABLE);
|
||||||
|
|
||||||
|
// pass timeout and validate that UNAVAILABLE is not called
|
||||||
|
try {
|
||||||
|
Thread.sleep(15);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
networkCallback.assertNoCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that when a time-out is specified for a network request the onUnavailable()
|
||||||
|
* callback is called when time-out expires. Then validate that if network request is
|
||||||
|
* (somehow) satisfied - the callback isn't called later.
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
public void testTimedoutNetworkRequest() {
|
||||||
|
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
|
||||||
|
NetworkCapabilities.TRANSPORT_WIFI).build();
|
||||||
|
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
||||||
|
mCm.requestNetwork(nr, networkCallback, 10);
|
||||||
|
|
||||||
|
// pass timeout and validate that UNAVAILABLE is called
|
||||||
|
try {
|
||||||
|
Thread.sleep(15);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
networkCallback.expectCallback(CallbackState.UNAVAILABLE);
|
||||||
|
|
||||||
|
// create a network satisfying request - validate that request not triggered
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.connect(false);
|
||||||
|
networkCallback.assertNoCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that when a network request is unregistered (cancelled) the time-out for that
|
||||||
|
* request doesn't trigger the onUnavailable() callback.
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
public void testTimedoutAfterUnregisteredNetworkRequest() {
|
||||||
|
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
|
||||||
|
NetworkCapabilities.TRANSPORT_WIFI).build();
|
||||||
|
final TestNetworkCallback networkCallback = new TestNetworkCallback();
|
||||||
|
mCm.requestNetwork(nr, networkCallback, 10);
|
||||||
|
|
||||||
|
// remove request
|
||||||
|
mCm.unregisterNetworkCallback(networkCallback);
|
||||||
|
|
||||||
|
// pass timeout and validate that no callbacks
|
||||||
|
// Note: doesn't validate that nothing called from CS since even if called the CM already
|
||||||
|
// unregisters the callback and won't pass it through!
|
||||||
|
try {
|
||||||
|
Thread.sleep(15);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
networkCallback.assertNoCallback();
|
||||||
|
|
||||||
|
// create a network satisfying request - validate that request not triggered
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.connect(false);
|
||||||
|
networkCallback.assertNoCallback();
|
||||||
|
}
|
||||||
|
|
||||||
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
|
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
|
||||||
|
|
||||||
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
|
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
|
||||||
|
|||||||
Reference in New Issue
Block a user