DO NOT MERGE: Support timeouts for requestNetwork() invocations.
(cherry-pick of0b7a74842b) (cherry picked from commit155a59aa63) Bug: 21414325 (cherry picked from commit5791c5f681) Change-Id: I640c43315a071ecbf881e5ce898164915e0b787f
This commit is contained in:
committed by
Lorenzo Colitti
parent
9e98fecd15
commit
ee83e11aeb
@@ -2606,7 +2606,8 @@ public class ConnectivityManager {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void onUnavailable() {}
|
||||
@@ -2679,6 +2680,26 @@ public class ConnectivityManager {
|
||||
/** @hide */
|
||||
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 final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
|
||||
private final AtomicInteger mRefCount;
|
||||
@@ -2845,7 +2866,7 @@ public class ConnectivityManager {
|
||||
private final static int REQUEST = 2;
|
||||
|
||||
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
|
||||
NetworkCallback networkCallback, int timeoutSec, int action,
|
||||
NetworkCallback networkCallback, int timeoutMs, int action,
|
||||
int legacyType) {
|
||||
if (networkCallback == null) {
|
||||
throw new IllegalArgumentException("null NetworkCallback");
|
||||
@@ -2861,7 +2882,7 @@ public class ConnectivityManager {
|
||||
new Messenger(sCallbackHandler), new Binder());
|
||||
} else {
|
||||
networkCallback.networkRequest = mService.requestNetwork(need,
|
||||
new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
|
||||
new Messenger(sCallbackHandler), timeoutMs, new Binder(), legacyType);
|
||||
}
|
||||
if (networkCallback.networkRequest != null) {
|
||||
sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
|
||||
|
||||
@@ -2605,14 +2605,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
"request NetworkCapabilities", ConnectivityManager.CALLBACK_CAP_CHANGED);
|
||||
}
|
||||
|
||||
private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
|
||||
if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
|
||||
nri.request.requestId) == null) {
|
||||
handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
|
||||
final NetworkRequestInfo nri = getNriForAppRequest(
|
||||
request, callingUid, "release NetworkRequest");
|
||||
if (nri == null) return;
|
||||
if (nri != null) {
|
||||
handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED);
|
||||
}
|
||||
}
|
||||
|
||||
if (VDBG || (DBG && nri.request.isRequest())) log("releasing " + request);
|
||||
private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) {
|
||||
final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
|
||||
if (VDBG || (DBG && nri.request.isRequest())) {
|
||||
log("releasing " + nri.request + " (" + logCallbackType + ")");
|
||||
}
|
||||
nri.unlinkDeathRecipient();
|
||||
mNetworkRequests.remove(request);
|
||||
mNetworkRequests.remove(nri.request);
|
||||
synchronized (mUidToNetworkRequestCount) {
|
||||
int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
|
||||
if (requests < 1) {
|
||||
@@ -2706,7 +2720,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
}
|
||||
}
|
||||
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED, 0);
|
||||
callCallbackForRequest(nri, null, whichCallback, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2943,6 +2957,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
handleRegisterNetworkRequestWithIntent(msg);
|
||||
break;
|
||||
}
|
||||
case EVENT_TIMEOUT_NETWORK_REQUEST: {
|
||||
NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
|
||||
handleTimedOutNetworkRequest(nri);
|
||||
break;
|
||||
}
|
||||
case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
|
||||
handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
|
||||
break;
|
||||
|
||||
@@ -1086,7 +1086,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
NETWORK_CAPABILITIES,
|
||||
LINK_PROPERTIES,
|
||||
LOSING,
|
||||
LOST
|
||||
LOST,
|
||||
UNAVAILABLE
|
||||
}
|
||||
|
||||
private static class CallbackInfo {
|
||||
@@ -1134,6 +1135,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
setLastCallback(CallbackState.AVAILABLE, network, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnavailable() {
|
||||
setLastCallback(CallbackState.UNAVAILABLE, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLosing(Network network, int maxMsToLive) {
|
||||
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
|
||||
@@ -2291,6 +2297,79 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
mCm.unregisterNetworkCallback(defaultCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, mWiFiNetworkAgent);
|
||||
|
||||
// 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
|
||||
networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
|
||||
|
||||
// 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 {
|
||||
|
||||
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
|
||||
|
||||
Reference in New Issue
Block a user