Merge "Extract test utilities for ConnectivityService"
am: ecaff61c4b
Change-Id: I0ac2a480f961bb6fd1d83dedad6a7942ee03858f
This commit is contained in:
@@ -150,7 +150,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;
|
||||
|
||||
@@ -168,7 +167,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;
|
||||
@@ -305,7 +303,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;
|
||||
|
||||
@@ -586,11 +585,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;
|
||||
|
||||
@@ -834,19 +828,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);
|
||||
@@ -863,7 +951,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());
|
||||
@@ -881,7 +969,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();
|
||||
@@ -949,7 +1037,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++;
|
||||
}
|
||||
@@ -969,7 +1057,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);
|
||||
|
||||
@@ -1028,7 +1117,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();
|
||||
|
||||
@@ -1038,10 +1127,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();
|
||||
@@ -1051,14 +1138,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) {
|
||||
@@ -1150,22 +1229,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);
|
||||
@@ -1797,11 +1860,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;
|
||||
@@ -2237,12 +2297,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) {
|
||||
@@ -2632,8 +2686,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;
|
||||
@@ -2968,8 +3023,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);
|
||||
}
|
||||
@@ -3016,7 +3071,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
|
||||
@@ -3070,9 +3125,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) {
|
||||
@@ -4156,7 +4209,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);
|
||||
@@ -4165,10 +4218,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);
|
||||
@@ -4761,7 +4810,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);
|
||||
@@ -5372,10 +5421,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
|
||||
@@ -5477,9 +5525,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();
|
||||
@@ -5488,7 +5536,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);
|
||||
@@ -5500,11 +5548,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");
|
||||
@@ -6313,7 +6356,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();
|
||||
@@ -6990,27 +7033,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));
|
||||
|
||||
76
services/core/java/com/android/server/NetIdManager.java
Normal file
76
services/core/java/com/android/server/NetIdManager.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user