am 682fd6ae
: am a991c66c
: Merge "Fix missing onLost NetworkCallbacks when network loses capability" into mnc-dev
* commit '682fd6aedea87e345f033b489ef9f6008bd19c30': Fix missing onLost NetworkCallbacks when network loses capability
This commit is contained in:
@ -792,6 +792,7 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
case NET_CAPABILITY_TRUSTED: capabilities += "TRUSTED"; break;
|
case NET_CAPABILITY_TRUSTED: capabilities += "TRUSTED"; break;
|
||||||
case NET_CAPABILITY_NOT_VPN: capabilities += "NOT_VPN"; break;
|
case NET_CAPABILITY_NOT_VPN: capabilities += "NOT_VPN"; break;
|
||||||
case NET_CAPABILITY_VALIDATED: capabilities += "VALIDATED"; break;
|
case NET_CAPABILITY_VALIDATED: capabilities += "VALIDATED"; break;
|
||||||
|
case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break;
|
||||||
}
|
}
|
||||||
if (++i < types.length) capabilities += "&";
|
if (++i < types.length) capabilities += "&";
|
||||||
}
|
}
|
||||||
|
@ -2171,6 +2171,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mDefaultInetConditionPublished = 0;
|
mDefaultInetConditionPublished = 0;
|
||||||
}
|
}
|
||||||
notifyIfacesChanged();
|
notifyIfacesChanged();
|
||||||
|
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
|
||||||
|
// by other networks that are already connected. Perhaps that can be done by
|
||||||
|
// sending all CALLBACK_LOST messages (for requests, not listens) at the end
|
||||||
|
// of rematchAllNetworksAndRequests
|
||||||
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
|
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
|
||||||
mKeepaliveTracker.handleStopAllKeepalives(nai,
|
mKeepaliveTracker.handleStopAllKeepalives(nai,
|
||||||
ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
|
ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
|
||||||
@ -2288,7 +2292,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// is currently satisfying the request. This is desirable when
|
// is currently satisfying the request. This is desirable when
|
||||||
// cellular ends up validating but WiFi does not.
|
// cellular ends up validating but WiFi does not.
|
||||||
// 2. Unvalidated WiFi will not be reaped when validated cellular
|
// 2. Unvalidated WiFi will not be reaped when validated cellular
|
||||||
// is currently satsifying the request. This is desirable when
|
// is currently satisfying the request. This is desirable when
|
||||||
// WiFi ends up validating and out scoring cellular.
|
// WiFi ends up validating and out scoring cellular.
|
||||||
mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
|
mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
|
||||||
nai.getCurrentScoreAsValidated())) {
|
nai.getCurrentScoreAsValidated())) {
|
||||||
@ -3866,10 +3870,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
|
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
|
||||||
// satisfies mDefaultRequest.
|
// satisfies mDefaultRequest.
|
||||||
NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
|
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
|
||||||
new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
|
new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
|
||||||
linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
|
linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
|
||||||
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest);
|
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
nai.networkMonitor.systemReady = mSystemReady;
|
nai.networkMonitor.systemReady = mSystemReady;
|
||||||
}
|
}
|
||||||
@ -4265,8 +4269,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
|
ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
|
||||||
if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
|
if (VDBG) log(" network has: " + newNetwork.networkCapabilities);
|
||||||
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
|
||||||
NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
|
final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
|
||||||
if (newNetwork == currentNetwork) {
|
final boolean satisfies = newNetwork.satisfies(nri.request);
|
||||||
|
if (newNetwork == currentNetwork && satisfies) {
|
||||||
if (VDBG) {
|
if (VDBG) {
|
||||||
log("Network " + newNetwork.name() + " was already satisfying" +
|
log("Network " + newNetwork.name() + " was already satisfying" +
|
||||||
" request " + nri.request.requestId + ". No change.");
|
" request " + nri.request.requestId + ". No change.");
|
||||||
@ -4277,7 +4282,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
// check if it satisfies the NetworkCapabilities
|
// check if it satisfies the NetworkCapabilities
|
||||||
if (VDBG) log(" checking if request is satisfied: " + nri.request);
|
if (VDBG) log(" checking if request is satisfied: " + nri.request);
|
||||||
if (newNetwork.satisfies(nri.request)) {
|
if (satisfies) {
|
||||||
if (!nri.isRequest) {
|
if (!nri.isRequest) {
|
||||||
// This is not a request, it's a callback listener.
|
// This is not a request, it's a callback listener.
|
||||||
// Add it to newNetwork regardless of score.
|
// Add it to newNetwork regardless of score.
|
||||||
@ -4320,6 +4325,37 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
oldDefaultNetwork = currentNetwork;
|
oldDefaultNetwork = currentNetwork;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (newNetwork.networkRequests.get(nri.request.requestId) != null) {
|
||||||
|
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
|
||||||
|
// mark it as no longer satisfying "nri". Because networks are processed by
|
||||||
|
// rematchAllNetworkAndRequests() in descending score order, "currentNetwork" will
|
||||||
|
// match "newNetwork" before this loop will encounter a "currentNetwork" with higher
|
||||||
|
// score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
|
||||||
|
// This means this code doesn't have to handle the case where "currentNetwork" no
|
||||||
|
// longer satisfies "nri" when "currentNetwork" does not equal "newNetwork".
|
||||||
|
if (DBG) {
|
||||||
|
log("Network " + newNetwork.name() + " stopped satisfying" +
|
||||||
|
" request " + nri.request.requestId);
|
||||||
|
}
|
||||||
|
newNetwork.networkRequests.remove(nri.request.requestId);
|
||||||
|
if (currentNetwork == newNetwork) {
|
||||||
|
mNetworkForRequestId.remove(nri.request.requestId);
|
||||||
|
sendUpdatedScoreToFactories(nri.request, 0);
|
||||||
|
} else {
|
||||||
|
if (nri.isRequest == true) {
|
||||||
|
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
|
||||||
|
newNetwork.name() +
|
||||||
|
" without updating mNetworkForRequestId or factories!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: technically, sending CALLBACK_LOST here is
|
||||||
|
// incorrect if nri is a request (not a listen) and there
|
||||||
|
// is a replacement network currently connected that can
|
||||||
|
// satisfy it. However, the only capability that can both
|
||||||
|
// a) be requested and b) change is NET_CAPABILITY_TRUSTED,
|
||||||
|
// so this code is only incorrect for a network that loses
|
||||||
|
// the TRUSTED capability, which is a rare case.
|
||||||
|
callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Linger any networks that are no longer needed.
|
// Linger any networks that are no longer needed.
|
||||||
@ -4338,41 +4374,41 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
unlinger(nai);
|
unlinger(nai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isNewDefault) {
|
||||||
|
// Notify system services that this network is up.
|
||||||
|
makeDefault(newNetwork);
|
||||||
|
synchronized (ConnectivityService.this) {
|
||||||
|
// have a new default network, release the transition wakelock in
|
||||||
|
// a second if it's held. The second pause is to allow apps
|
||||||
|
// to reconnect over the new network
|
||||||
|
if (mNetTransitionWakeLock.isHeld()) {
|
||||||
|
mHandler.sendMessageDelayed(mHandler.obtainMessage(
|
||||||
|
EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
|
||||||
|
mNetTransitionWakeLockSerialNumber, 0),
|
||||||
|
1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// do this after the default net is switched, but
|
||||||
|
// before LegacyTypeTracker sends legacy broadcasts
|
||||||
|
for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
|
||||||
|
|
||||||
|
if (isNewDefault) {
|
||||||
|
// Maintain the illusion: since the legacy API only
|
||||||
|
// understands one network at a time, we must pretend
|
||||||
|
// that the current default network disconnected before
|
||||||
|
// the new one connected.
|
||||||
|
if (oldDefaultNetwork != null) {
|
||||||
|
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
|
||||||
|
oldDefaultNetwork, true);
|
||||||
|
}
|
||||||
|
mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
|
||||||
|
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
|
||||||
|
notifyLockdownVpn(newNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
if (keep) {
|
if (keep) {
|
||||||
if (isNewDefault) {
|
|
||||||
// Notify system services that this network is up.
|
|
||||||
makeDefault(newNetwork);
|
|
||||||
synchronized (ConnectivityService.this) {
|
|
||||||
// have a new default network, release the transition wakelock in
|
|
||||||
// a second if it's held. The second pause is to allow apps
|
|
||||||
// to reconnect over the new network
|
|
||||||
if (mNetTransitionWakeLock.isHeld()) {
|
|
||||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(
|
|
||||||
EVENT_CLEAR_NET_TRANSITION_WAKELOCK,
|
|
||||||
mNetTransitionWakeLockSerialNumber, 0),
|
|
||||||
1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// do this after the default net is switched, but
|
|
||||||
// before LegacyTypeTracker sends legacy broadcasts
|
|
||||||
for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri);
|
|
||||||
|
|
||||||
if (isNewDefault) {
|
|
||||||
// Maintain the illusion: since the legacy API only
|
|
||||||
// understands one network at a time, we must pretend
|
|
||||||
// that the current default network disconnected before
|
|
||||||
// the new one connected.
|
|
||||||
if (oldDefaultNetwork != null) {
|
|
||||||
mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
|
|
||||||
oldDefaultNetwork, true);
|
|
||||||
}
|
|
||||||
mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
|
|
||||||
mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
|
|
||||||
notifyLockdownVpn(newNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify battery stats service about this network, both the normal
|
// Notify battery stats service about this network, both the normal
|
||||||
// interface and any stacked links.
|
// interface and any stacked links.
|
||||||
// TODO: Avoid redoing this; this must only be done once when a network comes online.
|
// TODO: Avoid redoing this; this must only be done once when a network comes online.
|
||||||
@ -4791,4 +4827,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
|
||||||
|
NetworkAgentInfo nai, NetworkRequest defaultRequest) {
|
||||||
|
return new NetworkMonitor(context, handler, nai, defaultRequest);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import android.os.Messenger;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.android.internal.util.AsyncChannel;
|
import com.android.internal.util.AsyncChannel;
|
||||||
|
import com.android.server.ConnectivityService;
|
||||||
import com.android.server.connectivity.NetworkMonitor;
|
import com.android.server.connectivity.NetworkMonitor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -51,7 +52,7 @@ import java.util.Comparator;
|
|||||||
// ConnectivityService will tell netd to create the network and immediately transition to
|
// ConnectivityService will tell netd to create the network and immediately transition to
|
||||||
// state #3.
|
// state #3.
|
||||||
// 3. registered, created, connected, unvalidated
|
// 3. registered, created, connected, unvalidated
|
||||||
// If this network can satsify the default NetworkRequest, then NetworkMonitor will
|
// If this network can satisfy the default NetworkRequest, then NetworkMonitor will
|
||||||
// probe for Internet connectivity.
|
// probe for Internet connectivity.
|
||||||
// If this network cannot satisfy the default NetworkRequest, it will immediately be
|
// If this network cannot satisfy the default NetworkRequest, it will immediately be
|
||||||
// transitioned to state #4.
|
// transitioned to state #4.
|
||||||
@ -164,7 +165,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
|
|
||||||
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
|
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
|
||||||
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
|
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
|
||||||
NetworkMisc misc, NetworkRequest defaultRequest) {
|
NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
|
||||||
this.messenger = messenger;
|
this.messenger = messenger;
|
||||||
asyncChannel = ac;
|
asyncChannel = ac;
|
||||||
network = net;
|
network = net;
|
||||||
@ -172,7 +173,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
|
|||||||
linkProperties = lp;
|
linkProperties = lp;
|
||||||
networkCapabilities = nc;
|
networkCapabilities = nc;
|
||||||
currentScore = score;
|
currentScore = score;
|
||||||
networkMonitor = new NetworkMonitor(context, handler, this, defaultRequest);
|
networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
|
||||||
networkMisc = misc;
|
networkMisc = misc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ public class NetworkMonitor extends StateMachine {
|
|||||||
// Being in the ValidatedState State indicates a Network is:
|
// Being in the ValidatedState State indicates a Network is:
|
||||||
// - Successfully validated, or
|
// - Successfully validated, or
|
||||||
// - Wanted "as is" by the user, or
|
// - Wanted "as is" by the user, or
|
||||||
// - Does not satsify the default NetworkRequest and so validation has been skipped.
|
// - Does not satisfy the default NetworkRequest and so validation has been skipped.
|
||||||
private class ValidatedState extends State {
|
private class ValidatedState extends State {
|
||||||
@Override
|
@Override
|
||||||
public void enter() {
|
public void enter() {
|
||||||
@ -558,7 +558,7 @@ public class NetworkMonitor extends StateMachine {
|
|||||||
|
|
||||||
// Being in the LingeringState State indicates a Network's validated bit is true and it once
|
// Being in the LingeringState State indicates a Network's validated bit is true and it once
|
||||||
// was the highest scoring Network satisfying a particular NetworkRequest, but since then
|
// was the highest scoring Network satisfying a particular NetworkRequest, but since then
|
||||||
// another Network satsified the NetworkRequest with a higher score and hence this Network
|
// another Network satisfied the NetworkRequest with a higher score and hence this Network
|
||||||
// is "lingered" for a fixed period of time before it is disconnected. This period of time
|
// is "lingered" for a fixed period of time before it is disconnected. This period of time
|
||||||
// allows apps to wrap up communication and allows for seamless reactivation if the other
|
// allows apps to wrap up communication and allows for seamless reactivation if the other
|
||||||
// higher scoring Network happens to disconnect.
|
// higher scoring Network happens to disconnect.
|
||||||
@ -633,7 +633,8 @@ public class NetworkMonitor extends StateMachine {
|
|||||||
* Do a URL fetch on a known server to see if we get the data we expect.
|
* Do a URL fetch on a known server to see if we get the data we expect.
|
||||||
* Returns HTTP response code.
|
* Returns HTTP response code.
|
||||||
*/
|
*/
|
||||||
private int isCaptivePortal() {
|
@VisibleForTesting
|
||||||
|
protected int isCaptivePortal() {
|
||||||
if (!mIsCaptivePortalCheckEnabled) return 204;
|
if (!mIsCaptivePortalCheckEnabled) return 204;
|
||||||
|
|
||||||
HttpURLConnection urlConnection = null;
|
HttpURLConnection urlConnection = null;
|
||||||
|
@ -81,6 +81,7 @@ import android.test.suitebuilder.annotation.LargeTest;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.LogPrinter;
|
import android.util.LogPrinter;
|
||||||
|
|
||||||
|
import com.android.server.connectivity.NetworkAgentInfo;
|
||||||
import com.android.server.connectivity.NetworkMonitor;
|
import com.android.server.connectivity.NetworkMonitor;
|
||||||
|
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
@ -118,7 +119,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
private INetworkPolicyManager mPolicyService;
|
private INetworkPolicyManager mPolicyService;
|
||||||
|
|
||||||
private BroadcastInterceptingContext mServiceContext;
|
private BroadcastInterceptingContext mServiceContext;
|
||||||
private ConnectivityService mService;
|
private WrappedConnectivityService mService;
|
||||||
private ConnectivityManager mCm;
|
private ConnectivityManager mCm;
|
||||||
private MockNetworkAgent mWiFiNetworkAgent;
|
private MockNetworkAgent mWiFiNetworkAgent;
|
||||||
private MockNetworkAgent mCellNetworkAgent;
|
private MockNetworkAgent mCellNetworkAgent;
|
||||||
@ -148,6 +149,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class MockNetworkAgent {
|
private class MockNetworkAgent {
|
||||||
|
private final WrappedNetworkMonitor mWrappedNetworkMonitor;
|
||||||
private final NetworkInfo mNetworkInfo;
|
private final NetworkInfo mNetworkInfo;
|
||||||
private final NetworkCapabilities mNetworkCapabilities;
|
private final NetworkCapabilities mNetworkCapabilities;
|
||||||
private final Thread mThread;
|
private final Thread mThread;
|
||||||
@ -172,6 +174,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
throw new UnsupportedOperationException("unimplemented network type");
|
throw new UnsupportedOperationException("unimplemented network type");
|
||||||
}
|
}
|
||||||
final ConditionVariable initComplete = new ConditionVariable();
|
final ConditionVariable initComplete = new ConditionVariable();
|
||||||
|
final ConditionVariable networkMonitorAvailable = mService.getNetworkMonitorCreatedCV();
|
||||||
mThread = new Thread() {
|
mThread = new Thread() {
|
||||||
public void run() {
|
public void run() {
|
||||||
Looper.prepare();
|
Looper.prepare();
|
||||||
@ -186,6 +189,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
};
|
};
|
||||||
mThread.start();
|
mThread.start();
|
||||||
waitFor(initComplete);
|
waitFor(initComplete);
|
||||||
|
waitFor(networkMonitorAvailable);
|
||||||
|
mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void adjustScore(int change) {
|
public void adjustScore(int change) {
|
||||||
@ -211,44 +216,46 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
assertEquals(mNetworkInfo.getDetailedState(), DetailedState.IDLE);
|
assertEquals(mNetworkInfo.getDetailedState(), DetailedState.IDLE);
|
||||||
assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
|
assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
|
||||||
|
|
||||||
// To pretend network is validated, we transition it to the CONNECTED state without
|
|
||||||
// NET_CAPABILITY_INTERNET so NetworkMonitor doesn't bother trying to validate and
|
|
||||||
// just rubber stamps it as validated. Afterwards we add NET_CAPABILITY_INTERNET so
|
|
||||||
// the network can satisfy the default request.
|
|
||||||
NetworkCallback callback = null;
|
NetworkCallback callback = null;
|
||||||
final ConditionVariable validatedCv = new ConditionVariable();
|
final ConditionVariable validatedCv = new ConditionVariable();
|
||||||
if (validated) {
|
if (validated) {
|
||||||
// If we connect a network without INTERNET capability, it'll get reaped.
|
mWrappedNetworkMonitor.gen204ProbeResult = 204;
|
||||||
// Prevent the reaping by adding a NetworkRequest.
|
|
||||||
NetworkRequest request = new NetworkRequest.Builder()
|
NetworkRequest request = new NetworkRequest.Builder()
|
||||||
.addTransportType(mNetworkCapabilities.getTransportTypes()[0])
|
.addTransportType(mNetworkCapabilities.getTransportTypes()[0])
|
||||||
.build();
|
.build();
|
||||||
callback = new NetworkCallback() {
|
callback = new NetworkCallback() {
|
||||||
public void onCapabilitiesChanged(Network network,
|
public void onCapabilitiesChanged(Network network,
|
||||||
NetworkCapabilities networkCapabilities) {
|
NetworkCapabilities networkCapabilities) {
|
||||||
if (networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
|
if (network.equals(getNetwork()) &&
|
||||||
|
networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
|
||||||
validatedCv.open();
|
validatedCv.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mCm.requestNetwork(request, callback);
|
mCm.registerNetworkCallback(request, callback);
|
||||||
} else {
|
|
||||||
mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
|
|
||||||
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
|
||||||
}
|
}
|
||||||
|
addCapability(NET_CAPABILITY_INTERNET);
|
||||||
|
|
||||||
connectWithoutInternet();
|
connectWithoutInternet();
|
||||||
|
|
||||||
if (validated) {
|
if (validated) {
|
||||||
// Wait for network to validate.
|
// Wait for network to validate.
|
||||||
waitFor(validatedCv);
|
waitFor(validatedCv);
|
||||||
mNetworkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
|
mWrappedNetworkMonitor.gen204ProbeResult = 500;
|
||||||
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback != null) mCm.unregisterNetworkCallback(callback);
|
if (callback != null) mCm.unregisterNetworkCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void connectWithCaptivePortal() {
|
||||||
|
mWrappedNetworkMonitor.gen204ProbeResult = 200;
|
||||||
|
connect(false);
|
||||||
|
waitFor(new Criteria() { public boolean get() {
|
||||||
|
NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork());
|
||||||
|
return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} });
|
||||||
|
mWrappedNetworkMonitor.gen204ProbeResult = 500;
|
||||||
|
}
|
||||||
|
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
|
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
|
||||||
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
|
||||||
@ -261,14 +268,18 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
public ConditionVariable getDisconnectedCV() {
|
public ConditionVariable getDisconnectedCV() {
|
||||||
return mDisconnected;
|
return mDisconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WrappedNetworkMonitor getWrappedNetworkMonitor() {
|
||||||
|
return mWrappedNetworkMonitor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockNetworkFactory extends NetworkFactory {
|
private static class MockNetworkFactory extends NetworkFactory {
|
||||||
final ConditionVariable mNetworkStartedCV = new ConditionVariable();
|
private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
|
||||||
final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
|
private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
|
||||||
final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
|
private final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
|
||||||
final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
|
private final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
|
||||||
final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
|
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
|
||||||
|
|
||||||
public MockNetworkFactory(Looper looper, Context context, String logTag,
|
public MockNetworkFactory(Looper looper, Context context, String logTag,
|
||||||
NetworkCapabilities filter) {
|
NetworkCapabilities filter) {
|
||||||
@ -328,7 +339,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
|
||||||
|
private class WrappedNetworkMonitor extends NetworkMonitor {
|
||||||
|
// HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
|
||||||
|
public int gen204ProbeResult = 500;
|
||||||
|
|
||||||
|
public WrappedNetworkMonitor(Context context, Handler handler,
|
||||||
|
NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) {
|
||||||
|
super(context, handler, networkAgentInfo, defaultRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int isCaptivePortal() {
|
||||||
|
return gen204ProbeResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class WrappedConnectivityService extends ConnectivityService {
|
private class WrappedConnectivityService extends ConnectivityService {
|
||||||
|
private final ConditionVariable mNetworkMonitorCreated = new ConditionVariable();
|
||||||
|
private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
|
||||||
|
|
||||||
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
|
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
|
||||||
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
|
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
|
||||||
super(context, netManager, statsService, policyManager);
|
super(context, netManager, statsService, policyManager);
|
||||||
@ -360,6 +390,25 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
return netId;
|
return netId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
|
||||||
|
NetworkAgentInfo nai, NetworkRequest defaultRequest) {
|
||||||
|
final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(context, handler, nai,
|
||||||
|
defaultRequest);
|
||||||
|
mLastCreatedNetworkMonitor = monitor;
|
||||||
|
mNetworkMonitorCreated.open();
|
||||||
|
return monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
|
||||||
|
return mLastCreatedNetworkMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConditionVariable getNetworkMonitorCreatedCV() {
|
||||||
|
mNetworkMonitorCreated.close();
|
||||||
|
return mNetworkMonitorCreated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface Criteria {
|
private interface Criteria {
|
||||||
@ -586,29 +635,29 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
public void testUnlingeringDoesNotValidate() throws Exception {
|
public void testUnlingeringDoesNotValidate() throws Exception {
|
||||||
// Test bringing up unvalidated cellular.
|
// Test bringing up unvalidated WiFi.
|
||||||
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
|
||||||
ConditionVariable cv = waitForConnectivityBroadcasts(1);
|
|
||||||
mCellNetworkAgent.connect(false);
|
|
||||||
waitFor(cv);
|
|
||||||
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
|
||||||
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
|
||||||
NET_CAPABILITY_VALIDATED));
|
|
||||||
// Test bringing up validated WiFi.
|
|
||||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
cv = waitForConnectivityBroadcasts(2);
|
ConditionVariable cv = waitForConnectivityBroadcasts(1);
|
||||||
mWiFiNetworkAgent.connect(true);
|
mWiFiNetworkAgent.connect(false);
|
||||||
waitFor(cv);
|
waitFor(cv);
|
||||||
verifyActiveNetwork(TRANSPORT_WIFI);
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||||
NET_CAPABILITY_VALIDATED));
|
NET_CAPABILITY_VALIDATED));
|
||||||
// Test WiFi disconnect.
|
// Test bringing up validated cellular.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
cv = waitForConnectivityBroadcasts(2);
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
mWiFiNetworkAgent.disconnect();
|
mCellNetworkAgent.connect(true);
|
||||||
waitFor(cv);
|
waitFor(cv);
|
||||||
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
// Test cellular disconnect.
|
||||||
|
cv = waitForConnectivityBroadcasts(2);
|
||||||
|
mCellNetworkAgent.disconnect();
|
||||||
|
waitFor(cv);
|
||||||
|
verifyActiveNetwork(TRANSPORT_WIFI);
|
||||||
// Unlingering a network should not cause it to be marked as validated.
|
// Unlingering a network should not cause it to be marked as validated.
|
||||||
assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
|
assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
|
||||||
NET_CAPABILITY_VALIDATED));
|
NET_CAPABILITY_VALIDATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,12 +895,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
|
|
||||||
cellCv = cellNetworkCallback.getConditionVariable();
|
cellCv = cellNetworkCallback.getConditionVariable();
|
||||||
wifiCv = wifiNetworkCallback.getConditionVariable();
|
wifiCv = wifiNetworkCallback.getConditionVariable();
|
||||||
// Our method for faking successful validation generates an additional callback, so wait
|
|
||||||
// for broadcast instead.
|
|
||||||
cv = waitForConnectivityBroadcasts(1);
|
|
||||||
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
mCellNetworkAgent.connect(true);
|
mCellNetworkAgent.connect(true);
|
||||||
waitFor(cv);
|
|
||||||
waitFor(cellCv);
|
waitFor(cellCv);
|
||||||
assertEquals(CallbackState.AVAILABLE, cellNetworkCallback.getLastCallback());
|
assertEquals(CallbackState.AVAILABLE, cellNetworkCallback.getLastCallback());
|
||||||
assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
|
assertEquals(CallbackState.NONE, wifiNetworkCallback.getLastCallback());
|
||||||
@ -868,12 +913,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
|
|
||||||
cellCv = cellNetworkCallback.getConditionVariable();
|
cellCv = cellNetworkCallback.getConditionVariable();
|
||||||
wifiCv = wifiNetworkCallback.getConditionVariable();
|
wifiCv = wifiNetworkCallback.getConditionVariable();
|
||||||
// Our method for faking successful validation generates an additional callback, so wait
|
|
||||||
// for broadcast instead.
|
|
||||||
cv = waitForConnectivityBroadcasts(1);
|
|
||||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
mWiFiNetworkAgent.connect(true);
|
mWiFiNetworkAgent.connect(true);
|
||||||
waitFor(cv);
|
|
||||||
waitFor(wifiCv);
|
waitFor(wifiCv);
|
||||||
assertEquals(CallbackState.AVAILABLE, wifiNetworkCallback.getLastCallback());
|
assertEquals(CallbackState.AVAILABLE, wifiNetworkCallback.getLastCallback());
|
||||||
waitFor(cellCv);
|
waitFor(cellCv);
|
||||||
@ -1075,6 +1116,63 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
verifyActiveNetwork(TRANSPORT_CELLULAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
public void testCaptivePortal() {
|
||||||
|
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
|
||||||
|
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
|
||||||
|
.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
|
||||||
|
mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
|
||||||
|
|
||||||
|
final TestNetworkCallback validatedCallback = new TestNetworkCallback();
|
||||||
|
final NetworkRequest validatedRequest = new NetworkRequest.Builder()
|
||||||
|
.addCapability(NET_CAPABILITY_VALIDATED).build();
|
||||||
|
mCm.registerNetworkCallback(validatedRequest, validatedCallback);
|
||||||
|
ConditionVariable validatedCv = validatedCallback.getConditionVariable();
|
||||||
|
|
||||||
|
// Bring up a network with a captive portal.
|
||||||
|
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
|
||||||
|
ConditionVariable cv = captivePortalCallback.getConditionVariable();
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.connectWithCaptivePortal();
|
||||||
|
waitFor(cv);
|
||||||
|
assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());
|
||||||
|
|
||||||
|
// Take down network.
|
||||||
|
// Expect onLost callback.
|
||||||
|
cv = captivePortalCallback.getConditionVariable();
|
||||||
|
mWiFiNetworkAgent.disconnect();
|
||||||
|
waitFor(cv);
|
||||||
|
assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());
|
||||||
|
|
||||||
|
// Bring up a network with a captive portal.
|
||||||
|
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
|
||||||
|
cv = captivePortalCallback.getConditionVariable();
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.connectWithCaptivePortal();
|
||||||
|
waitFor(cv);
|
||||||
|
assertEquals(CallbackState.AVAILABLE, captivePortalCallback.getLastCallback());
|
||||||
|
|
||||||
|
// Make captive portal disappear then revalidate.
|
||||||
|
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
|
||||||
|
cv = captivePortalCallback.getConditionVariable();
|
||||||
|
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
|
||||||
|
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
|
||||||
|
waitFor(cv);
|
||||||
|
assertEquals(CallbackState.LOST, captivePortalCallback.getLastCallback());
|
||||||
|
|
||||||
|
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
|
||||||
|
waitFor(validatedCv);
|
||||||
|
assertEquals(CallbackState.AVAILABLE, validatedCallback.getLastCallback());
|
||||||
|
|
||||||
|
// Break network connectivity.
|
||||||
|
// Expect NET_CAPABILITY_VALIDATED onLost callback.
|
||||||
|
validatedCv = validatedCallback.getConditionVariable();
|
||||||
|
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
|
||||||
|
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
|
||||||
|
waitFor(validatedCv);
|
||||||
|
assertEquals(CallbackState.LOST, validatedCallback.getLastCallback());
|
||||||
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public void tearDown() throws Exception {
|
// public void tearDown() throws Exception {
|
||||||
// super.tearDown();
|
// super.tearDown();
|
||||||
|
Reference in New Issue
Block a user