Merge "Extract test utilities for ConnectivityService"

This commit is contained in:
Treehugger Robot
2019-08-06 11:04:36 +00:00
committed by Gerrit Code Review
8 changed files with 947 additions and 739 deletions

View File

@@ -149,7 +149,6 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.Xml;
@@ -167,7 +166,6 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
@@ -304,7 +302,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
/** Flag indicating if background data is restricted. */
private boolean mRestrictBackground;
final private Context mContext;
private final Context mContext;
private final Dependencies mDeps;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
@@ -585,11 +584,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
private NetworkNotificationManager mNotifier;
private LingerMonitor mLingerMonitor;
// sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
private static final int MIN_NET_ID = 100; // some reserved marks
private static final int MAX_NET_ID = 65535 - 0x0400; // Top 1024 bits reserved by IpSecService
private int mNextNetId = MIN_NET_ID;
// sequence number of NetworkRequests
private int mNextNetworkRequestId = 1;
@@ -833,19 +827,113 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
};
/**
* Dependencies of ConnectivityService, for injection in tests.
*/
@VisibleForTesting
public static class Dependencies {
/**
* Get system properties to use in ConnectivityService.
*/
public MockableSystemProperties getSystemProperties() {
return new MockableSystemProperties();
}
/**
* Create a HandlerThread to use in ConnectivityService.
*/
public HandlerThread makeHandlerThread() {
return new HandlerThread("ConnectivityServiceThread");
}
/**
* Get a reference to the NetworkStackClient.
*/
public NetworkStackClient getNetworkStack() {
return NetworkStackClient.getInstance();
}
/**
* @see Tethering
*/
public Tethering makeTethering(@NonNull Context context,
@NonNull INetworkManagementService nms,
@NonNull INetworkStatsService statsService,
@NonNull INetworkPolicyManager policyManager,
@NonNull TetheringDependencies tetheringDeps) {
return new Tethering(context, nms, statsService, policyManager,
IoThread.get().getLooper(), getSystemProperties(), tetheringDeps);
}
/**
* @see ProxyTracker
*/
public ProxyTracker makeProxyTracker(@NonNull Context context,
@NonNull Handler connServiceHandler) {
return new ProxyTracker(context, connServiceHandler, EVENT_PROXY_HAS_CHANGED);
}
/**
* @see NetIdManager
*/
public NetIdManager makeNetIdManager() {
return new NetIdManager();
}
/**
* @see NetworkUtils#queryUserAccess(int, int)
*/
public boolean queryUserAccess(int uid, int netId) {
return NetworkUtils.queryUserAccess(uid, netId);
}
/**
* @see MultinetworkPolicyTracker
*/
public MultinetworkPolicyTracker makeMultinetworkPolicyTracker(
@NonNull Context c, @NonNull Handler h, @NonNull Runnable r) {
return new MultinetworkPolicyTracker(c, h, r);
}
/**
* @see ServiceManager#checkService(String)
*/
public boolean hasService(@NonNull String name) {
return ServiceManager.checkService(name) != null;
}
/**
* @see IpConnectivityMetrics.Logger
*/
public IpConnectivityMetrics.Logger getMetricsLogger() {
return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
"no IpConnectivityMetrics service");
}
/**
* @see IpConnectivityMetrics
*/
public IIpConnectivityMetrics getIpConnectivityMetrics() {
return IIpConnectivityMetrics.Stub.asInterface(
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
}
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
this(context, netManager, statsService, policyManager,
getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance());
this(context, netManager, statsService, policyManager, getDnsResolver(),
new IpConnectivityLog(), NetdService.getInstance(), new Dependencies());
}
@VisibleForTesting
protected ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) {
IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
if (DBG) log("ConnectivityService starting up");
mSystemProperties = getSystemProperties();
mDeps = checkNotNull(deps, "missing Dependencies");
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mMetricsLog = logger;
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -862,7 +950,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDefaultWifiRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST);
mHandlerThread = new HandlerThread("ConnectivityServiceThread");
mHandlerThread = mDeps.makeHandlerThread();
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
@@ -880,7 +968,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = makeProxyTracker();
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
mNetd = netd;
mKeyStore = KeyStore.getInstance();
@@ -948,7 +1036,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Do the same for Ethernet, since it's often not specified in the configs, although many
// devices can use it via USB host adapters.
if (mNetConfigs[TYPE_ETHERNET] == null && hasService(Context.ETHERNET_SERVICE)) {
if (mNetConfigs[TYPE_ETHERNET] == null && mDeps.hasService(Context.ETHERNET_SERVICE)) {
mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
mNetworksDefined++;
}
@@ -968,7 +1056,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mTethering = makeTethering();
mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
makeTetheringDependencies());
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -1027,7 +1116,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
mMultinetworkPolicyTracker = createMultinetworkPolicyTracker(
mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
mMultinetworkPolicyTracker.start();
@@ -1037,10 +1126,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
registerPrivateDnsSettingsCallbacks();
}
@VisibleForTesting
protected Tethering makeTethering() {
// TODO: Move other elements into @Overridden getters.
final TetheringDependencies deps = new TetheringDependencies() {
private TetheringDependencies makeTetheringDependencies() {
return new TetheringDependencies() {
@Override
public boolean isTetheringSupported() {
return ConnectivityService.this.isTetheringSupported();
@@ -1050,14 +1137,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return mDefaultRequest;
}
};
return new Tethering(mContext, mNMS, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
}
@VisibleForTesting
protected ProxyTracker makeProxyTracker() {
return new ProxyTracker(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
}
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
@@ -1149,22 +1228,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return mNextNetworkRequestId++;
}
@VisibleForTesting
protected int reserveNetId() {
synchronized (mNetworkForNetId) {
for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
int netId = mNextNetId;
if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
// Make sure NetID unused. http://b/16815182
if (!mNetIdInUse.get(netId)) {
mNetIdInUse.put(netId, true);
return netId;
}
}
}
throw new IllegalStateException("No free netIds");
}
private NetworkState getFilteredNetworkState(int networkType, int uid) {
if (mLegacyTypeTracker.isTypeSupported(networkType)) {
final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
@@ -1796,11 +1859,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
};
@VisibleForTesting
protected void registerNetdEventCallback() {
final IIpConnectivityMetrics ipConnectivityMetrics =
IIpConnectivityMetrics.Stub.asInterface(
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
private void registerNetdEventCallback() {
final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
if (ipConnectivityMetrics == null) {
Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
return;
@@ -2236,12 +2296,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd";
// Overridden for testing purposes to avoid writing to SystemProperties.
@VisibleForTesting
protected MockableSystemProperties getSystemProperties() {
return new MockableSystemProperties();
}
private void updateTcpBufferSizes(String tcpBufferSizes) {
String[] values = null;
if (tcpBufferSizes != null) {
@@ -2631,8 +2685,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (valid != nai.lastValidated) {
if (wasDefault) {
metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
SystemClock.elapsedRealtime(), valid);
mDeps.getMetricsLogger()
.defaultNetworkMetrics().logDefaultNetworkValidity(
SystemClock.elapsedRealtime(), valid);
}
final int oldScore = nai.getCurrentScore();
nai.lastValidated = valid;
@@ -2967,8 +3022,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final boolean wasDefault = isDefaultNetwork(nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.remove(nai.network.netId);
mNetIdInUse.delete(nai.network.netId);
}
mNetIdManager.releaseNetId(nai.network.netId);
// Just in case.
mLegacyTypeTracker.remove(nai, wasDefault);
}
@@ -3015,7 +3070,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
// whose timestamps tell how long it takes to recover a default network.
long now = SystemClock.elapsedRealtime();
metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
}
notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -3069,9 +3124,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
destroyNativeNetwork(nai);
mDnsManager.removeNetwork(nai.network);
}
synchronized (mNetworkForNetId) {
mNetIdInUse.delete(nai.network.netId);
}
mNetIdManager.releaseNetId(nai.network.netId);
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -4155,7 +4208,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
} else if (queryUserAccess(Binder.getCallingUid(), network.netId)) {
} else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -4164,10 +4217,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return null;
}
@VisibleForTesting
protected boolean queryUserAccess(int uid, int netId) {
return NetworkUtils.queryUserAccess(uid, netId);
}
private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -4760,7 +4809,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final long ident = Binder.clearCallingIdentity();
try {
// Concatenate the range of types onto the range of NetIDs.
int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
int id = NetIdManager.MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
mNotifier.setProvNotificationVisible(visible, id, action);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -5371,10 +5420,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
@GuardedBy("mNetworkForNetId")
private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
// NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
// An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
// An entry is first reserved with NetIdManager, prior to being added to mNetworkForNetId, so
// there may not be a strict 1:1 correlation between the two.
@GuardedBy("mNetworkForNetId")
private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
private final NetIdManager mNetIdManager;
// NetworkAgentInfo keyed off its connecting messenger
// TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
@@ -5476,9 +5524,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
mNMS, factorySerialNumber);
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
mDnsResolver, mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
@@ -5487,7 +5535,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (DBG) log("registerNetworkAgent " + nai);
final long token = Binder.clearCallingIdentity();
try {
getNetworkStack().makeNetworkMonitor(
mDeps.getNetworkStack().makeNetworkMonitor(
nai.network, name, new NetworkMonitorCallbacks(nai));
} finally {
Binder.restoreCallingIdentity(token);
@@ -5499,11 +5547,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return nai.network.netId;
}
@VisibleForTesting
protected NetworkStackClient getNetworkStack() {
return NetworkStackClient.getInstance();
}
private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
nai.onNetworkMonitorCreated(networkMonitor);
if (VDBG) log("Got NetworkAgent Messenger");
@@ -6312,7 +6355,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Notify system services that this network is up.
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
now, newNetwork, oldDefaultNetwork);
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
@@ -6983,27 +7026,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return nwm.getWatchlistConfigHash();
}
@VisibleForTesting
MultinetworkPolicyTracker createMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
return new MultinetworkPolicyTracker(c, h, r);
}
@VisibleForTesting
public WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int cmd, Object obj) {
return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
}
@VisibleForTesting
public boolean hasService(String name) {
return ServiceManager.checkService(name) != null;
}
@VisibleForTesting
protected IpConnectivityMetrics.Logger metricsLogger() {
return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
"no IpConnectivityMetrics service");
}
private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
int[] transports = nai.networkCapabilities.getTransportTypes();
mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server;
import android.annotation.NonNull;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
/**
* Class used to reserve and release net IDs.
*
* <p>Instances of this class are thread-safe.
*/
public class NetIdManager {
// Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
public static final int MIN_NET_ID = 100; // some reserved marks
// Top IDs reserved by IpSecService
public static final int MAX_NET_ID = 65535 - IpSecService.TUN_INTF_NETID_RANGE;
@GuardedBy("mNetIdInUse")
private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
@GuardedBy("mNetIdInUse")
private int mLastNetId = MIN_NET_ID - 1;
/**
* Get the first netId that follows the provided lastId and is available.
*/
private static int getNextAvailableNetIdLocked(
int lastId, @NonNull SparseBooleanArray netIdInUse) {
int netId = lastId;
for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
netId = netId < MAX_NET_ID ? netId + 1 : MIN_NET_ID;
if (!netIdInUse.get(netId)) {
return netId;
}
}
throw new IllegalStateException("No free netIds");
}
/**
* Reserve a new ID for a network.
*/
public int reserveNetId() {
synchronized (mNetIdInUse) {
mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
// Make sure NetID unused. http://b/16815182
mNetIdInUse.put(mLastNetId, true);
return mLastNetId;
}
}
/**
* Clear a previously reserved ID for a network.
*/
public void releaseNetId(int id) {
synchronized (mNetIdInUse) {
mNetIdInUse.delete(id);
}
}
}

View File

@@ -580,10 +580,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
}
if (newExpiry > 0) {
mLingerMessage = mConnService.makeWakeupMessage(
mLingerMessage = new WakeupMessage(
mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.netId,
EVENT_NETWORK_LINGER_COMPLETE, this);
"NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */,
EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
this /* obj (NetworkAgentInfo) */);
mLingerMessage.schedule(newExpiry);
}

View File

@@ -56,6 +56,7 @@ android_test {
"androidx.test.rules",
"FrameworksNetCommonTests",
"frameworks-base-testutils",
"frameworks-net-integration-testutils",
"framework-protos",
"mockito-target-minus-junit4",
"net-tests-utils",

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server
import android.net.ConnectivityManager.TYPE_BLUETOOTH
import android.net.ConnectivityManager.TYPE_ETHERNET
import android.net.ConnectivityManager.TYPE_MOBILE
import android.net.ConnectivityManager.TYPE_NONE
import android.net.ConnectivityManager.TYPE_TEST
import android.net.ConnectivityManager.TYPE_VPN
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
fun transportToLegacyType(transport: Int) = when (transport) {
TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
TRANSPORT_CELLULAR -> TYPE_MOBILE
TRANSPORT_ETHERNET -> TYPE_ETHERNET
TRANSPORT_TEST -> TYPE_TEST
TRANSPORT_VPN -> TYPE_VPN
TRANSPORT_WIFI -> TYPE_WIFI
else -> TYPE_NONE
}

View File

@@ -0,0 +1,267 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
import android.net.NetworkSpecifier;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.os.ConditionVariable;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.testutils.HandlerUtilsKt;
import com.android.testutils.TestableNetworkCallback;
import java.util.Set;
public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
private final NetworkInfo mNetworkInfo;
private final NetworkCapabilities mNetworkCapabilities;
private final HandlerThread mHandlerThread;
private final Context mContext;
private final String mLogTag;
private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
private int mScore;
private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
private Integer mExpectedKeepaliveSlot = null;
public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
throws Exception {
final int type = transportToLegacyType(transport);
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
mScore = 70;
break;
case TRANSPORT_WIFI:
mScore = 60;
break;
case TRANSPORT_CELLULAR:
mScore = 50;
break;
case TRANSPORT_WIFI_AWARE:
mScore = 20;
break;
case TRANSPORT_VPN:
mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
break;
default:
throw new UnsupportedOperationException("unimplemented network type");
}
mContext = context;
mLogTag = "Mock-" + typeName;
mHandlerThread = new HandlerThread(mLogTag);
mHandlerThread.start();
mNetworkAgent = makeNetworkAgent(linkProperties);
}
protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties)
throws Exception {
return new InstrumentedNetworkAgent(this, linkProperties);
}
public static class InstrumentedNetworkAgent extends NetworkAgent {
private final NetworkAgentWrapper mWrapper;
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
new NetworkMisc(), NetworkFactory.SerialNumber.NONE);
mWrapper = wrapper;
}
@Override
public void unwanted() {
mWrapper.mDisconnected.open();
}
@Override
public void startSocketKeepalive(Message msg) {
int slot = msg.arg1;
if (mWrapper.mExpectedKeepaliveSlot != null) {
assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
}
onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
}
@Override
public void stopSocketKeepalive(Message msg) {
onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
}
@Override
protected void preventAutomaticReconnect() {
mWrapper.mPreventReconnectReceived.open();
}
@Override
protected void addKeepalivePacketFilter(Message msg) {
Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
}
@Override
protected void removeKeepalivePacketFilter(Message msg) {
Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
}
}
public void adjustScore(int change) {
mScore += change;
mNetworkAgent.sendNetworkScore(mScore);
}
public int getScore() {
return mScore;
}
public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
}
public void addCapability(int capability) {
mNetworkCapabilities.addCapability(capability);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void removeCapability(int capability) {
mNetworkCapabilities.removeCapability(capability);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setSignalStrength(int signalStrength) {
mNetworkCapabilities.setSignalStrength(signalStrength);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
mNetworkCapabilities.set(nc);
if (sendToConnectivityService) {
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
}
public void connect() {
assertNotEquals("MockNetworkAgents can only be connected once",
getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
public void suspend() {
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
public void resume() {
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
public void disconnect() {
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
@Override
public Network getNetwork() {
return new Network(mNetworkAgent.netId);
}
public void expectPreventReconnectReceived(long timeoutMs) {
assertTrue(mPreventReconnectReceived.block(timeoutMs));
}
public void expectDisconnected(long timeoutMs) {
assertTrue(mDisconnected.block(timeoutMs));
}
public void sendLinkProperties(LinkProperties lp) {
mNetworkAgent.sendLinkProperties(lp);
}
public void setStartKeepaliveEvent(int reason) {
mStartKeepaliveError = reason;
}
public void setStopKeepaliveEvent(int reason) {
mStopKeepaliveError = reason;
}
public void setExpectedKeepaliveSlot(Integer slot) {
mExpectedKeepaliveSlot = slot;
}
public NetworkAgent getNetworkAgent() {
return mNetworkAgent;
}
public NetworkInfo getNetworkInfo() {
return mNetworkInfo;
}
public NetworkCapabilities getNetworkCapabilities() {
return mNetworkCapabilities;
}
public void waitForIdle(long timeoutMs) {
HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server
import java.util.concurrent.atomic.AtomicInteger
/**
* A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
* than starting from [NetIdManager.MIN_NET_ID] and increasing.
*
* Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
* overlapping with netIDs used by the real ConnectivityService on the device.
*
* IDs may still overlap if many networks have been used on the device (so the "real" netIDs
* are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
* is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
* the real ConnectivityService could start using netIds that have been used by the test in the
* past.
*/
class TestNetIdManager : NetIdManager() {
private val nextId = AtomicInteger(MAX_NET_ID)
override fun reserveNetId() = nextId.decrementAndGet()
override fun releaseNetId(id: Int) = Unit
}

File diff suppressed because it is too large Load Diff