Merge "Followup to CL 1103896"
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index 25e111e..a66fcae 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -78,7 +78,7 @@
out.writeStrongBinder(mBinder);
}
- public static final Parcelable.Creator<CaptivePortal> CREATOR
+ public static final @android.annotation.NonNull Parcelable.Creator<CaptivePortal> CREATOR
= new Parcelable.Creator<CaptivePortal>() {
@Override
public CaptivePortal createFromParcel(Parcel in) {
diff --git a/core/java/android/net/ConnectionInfo.java b/core/java/android/net/ConnectionInfo.java
index 58d0e05..4514a84 100644
--- a/core/java/android/net/ConnectionInfo.java
+++ b/core/java/android/net/ConnectionInfo.java
@@ -54,7 +54,7 @@
out.writeInt(remote.getPort());
}
- public static final Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
+ public static final @android.annotation.NonNull Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
public ConnectionInfo createFromParcel(Parcel in) {
int protocol = in.readInt();
InetAddress localAddress;
diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java
index 788d7d9..98bab44 100644
--- a/core/java/android/net/DhcpInfo.java
+++ b/core/java/android/net/DhcpInfo.java
@@ -84,7 +84,7 @@
}
/** Implement the Parcelable interface {@hide} */
- public static final Creator<DhcpInfo> CREATOR =
+ public static final @android.annotation.NonNull Creator<DhcpInfo> CREATOR =
new Creator<DhcpInfo>() {
public DhcpInfo createFromParcel(Parcel in) {
DhcpInfo info = new DhcpInfo();
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 3319f33..2af82d7 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -189,7 +189,7 @@
}
/** Implement the Parcelable interface */
- public static final Creator<IpConfiguration> CREATOR =
+ public static final @android.annotation.NonNull Creator<IpConfiguration> CREATOR =
new Creator<IpConfiguration>() {
public IpConfiguration createFromParcel(Parcel in) {
IpConfiguration config = new IpConfiguration();
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 416157c..8cfe6df 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -288,7 +288,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<IpPrefix> CREATOR =
+ public static final @android.annotation.NonNull Creator<IpPrefix> CREATOR =
new Creator<IpPrefix>() {
public IpPrefix createFromParcel(Parcel in) {
byte[] address = in.createByteArray();
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index 18726f7..9b8b732 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -105,7 +105,7 @@
}
/** Parcelable Creator */
- public static final Parcelable.Creator<KeepalivePacketData> CREATOR =
+ public static final @android.annotation.NonNull Parcelable.Creator<KeepalivePacketData> CREATOR =
new Parcelable.Creator<KeepalivePacketData>() {
public KeepalivePacketData createFromParcel(Parcel in) {
return new KeepalivePacketData(in);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index f17adea..93dd2e4 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -378,7 +378,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<LinkAddress> CREATOR =
+ public static final @android.annotation.NonNull Creator<LinkAddress> CREATOR =
new Creator<LinkAddress>() {
public LinkAddress createFromParcel(Parcel in) {
InetAddress address = null;
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index ad67763..d3f48ac 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -1627,7 +1627,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<LinkProperties> CREATOR =
+ public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
new Creator<LinkProperties>() {
public LinkProperties createFromParcel(Parcel in) {
LinkProperties netProp = new LinkProperties();
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index e15da2e..2cf2a65 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -171,7 +171,7 @@
return 0;
}
- public static final Parcelable.Creator<MacAddress> CREATOR =
+ public static final @android.annotation.NonNull Parcelable.Creator<MacAddress> CREATOR =
new Parcelable.Creator<MacAddress>() {
public MacAddress createFromParcel(Parcel in) {
return new MacAddress(in.readLong());
@@ -410,6 +410,21 @@
}
/**
+ * Checks if this MAC Address matches the provided range.
+ *
+ * @param baseAddress MacAddress representing the base address to compare with.
+ * @param mask MacAddress representing the mask to use during comparison.
+ * @return true if this MAC Address matches the given range.
+ *
+ * @hide
+ */
+ public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ Preconditions.checkNotNull(baseAddress);
+ Preconditions.checkNotNull(mask);
+ return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
+ }
+
+ /**
* Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted
* to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local
* IPv6 address per RFC 4862.
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 09a86fc..3f56def 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -471,7 +471,7 @@
dest.writeInt(netId);
}
- public static final Creator<Network> CREATOR =
+ public static final @android.annotation.NonNull Creator<Network> CREATOR =
new Creator<Network>() {
public Network createFromParcel(Parcel in) {
int netId = in.readInt();
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index b3f829a..43ea589 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -516,7 +516,7 @@
}
/**
- * Requests that the network hardware stops sending keepalive packets.
+ * Requests that the network hardware send the specified packet at the specified interval.
*/
protected void stopSocketKeepalive(Message msg) {
onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index dfd7089..3e325b7 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -1481,7 +1481,7 @@
dest.writeString(mSSID);
}
- public static final Creator<NetworkCapabilities> CREATOR =
+ public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
new Creator<NetworkCapabilities>() {
@Override
public NetworkCapabilities createFromParcel(Parcel in) {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 8fb5a20..92f105f 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -560,7 +560,7 @@
}
}
- public static final Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
+ public static final @android.annotation.NonNull Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
@Override
public NetworkInfo createFromParcel(Parcel in) {
int netType = in.readInt();
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 6fb2390..9ba3bd9 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -106,7 +106,7 @@
out.writeInt(skip464xlat ? 1 : 0);
}
- public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
+ public static final @android.annotation.NonNull Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@Override
public NetworkMisc createFromParcel(Parcel in) {
NetworkMisc networkMisc = new NetworkMisc();
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index acafa13..4270740 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -368,7 +368,7 @@
dest.writeInt(requestId);
dest.writeString(type.name());
}
- public static final Creator<NetworkRequest> CREATOR =
+ public static final @android.annotation.NonNull Creator<NetworkRequest> CREATOR =
new Creator<NetworkRequest>() {
public NetworkRequest createFromParcel(Parcel in) {
NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 97fb3fb..292cf50 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -87,7 +87,7 @@
}
@UnsupportedAppUsage
- public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
+ public static final @android.annotation.NonNull Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
@Override
public NetworkState createFromParcel(Parcel in) {
return new NetworkState(in);
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 228e62d..d0f54b4 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,10 +16,15 @@
package android.net;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.net.shared.Inet4AddressUtils;
import android.os.Build;
import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -454,4 +459,30 @@
}
return routedIPCount;
}
+
+ private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
+
+ /**
+ * Returns true if the hostname is weakly validated.
+ * @param hostname Name of host to validate.
+ * @return True if it's a valid-ish hostname.
+ *
+ * @hide
+ */
+ public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
+ // TODO(b/34953048): Use a validation method that permits more accurate,
+ // but still inexpensive, checking of likely valid DNS hostnames.
+ final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
+ if (!hostname.matches(weakHostnameRegex)) {
+ return false;
+ }
+
+ for (int address_family : ADDRESS_FAMILIES) {
+ if (Os.inet_pton(address_family, hostname) != null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index ef2269a..807c467 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -342,7 +342,7 @@
dest.writeStringArray(mParsedExclusionList);
}
- public static final Creator<ProxyInfo> CREATOR =
+ public static final @android.annotation.NonNull Creator<ProxyInfo> CREATOR =
new Creator<ProxyInfo>() {
public ProxyInfo createFromParcel(Parcel in) {
String host = null;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index fdd904a..52d3fc4 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -527,7 +527,7 @@
/**
* Implement the Parcelable interface.
*/
- public static final Creator<RouteInfo> CREATOR =
+ public static final @android.annotation.NonNull Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
public RouteInfo createFromParcel(Parcel in) {
IpPrefix dest = in.readParcelable(null);
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 0600036..5bc9953 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -236,6 +236,7 @@
return lp;
}
+ @NonNull
@Override
public String toString() {
StringBuffer str = new StringBuffer();
@@ -267,7 +268,7 @@
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (!(obj instanceof StaticIpConfiguration)) return false;
@@ -282,7 +283,7 @@
}
/** Implement the Parcelable interface */
- public static final Creator<StaticIpConfiguration> CREATOR =
+ public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR =
new Creator<StaticIpConfiguration>() {
public StaticIpConfiguration createFromParcel(Parcel in) {
return readFromParcel(in);
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index a1ac960..d75c43d 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -111,7 +111,7 @@
dest.writeInt(stop);
}
- public static final Creator<UidRange> CREATOR =
+ public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
new Creator<UidRange>() {
@Override
public UidRange createFromParcel(Parcel in) {
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index 4dd2ace..b1de74e 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -17,6 +17,7 @@
package android.net.apf;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.res.Resources;
@@ -91,6 +92,7 @@
}
};
+ @NonNull
@Override
public String toString() {
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
@@ -98,7 +100,7 @@
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (!(obj instanceof ApfCapabilities)) return false;
final ApfCapabilities other = (ApfCapabilities) obj;
return apfVersionSupported == other.apfVersionSupported
diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java
index f7e494d..4e88149 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -64,7 +64,7 @@
private final Context mContext;
private final Handler mHandler;
- private final Runnable mReevaluateRunnable;
+ private final Runnable mAvoidBadWifiCallback;
private final List<Uri> mSettingsUris;
private final ContentResolver mResolver;
private final SettingObserver mSettingObserver;
@@ -81,12 +81,7 @@
public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
mContext = ctx;
mHandler = handler;
- mReevaluateRunnable = () -> {
- if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
- avoidBadWifiCallback.run();
- }
- updateMeteredMultipathPreference();
- };
+ mAvoidBadWifiCallback = avoidBadWifiCallback;
mSettingsUris = Arrays.asList(
Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
@@ -95,15 +90,15 @@
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- reevaluate();
+ reevaluateInternal();
}
};
- TelephonyManager.from(ctx).listen(new PhoneStateListener() {
+ TelephonyManager.from(ctx).listen(new PhoneStateListener(handler.getLooper()) {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
mActiveSubId = subId;
- reevaluate();
+ reevaluateInternal();
}
}, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
@@ -119,7 +114,7 @@
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
mContext.registerReceiverAsUser(
- mBroadcastReceiver, UserHandle.ALL, intentFilter, null, null);
+ mBroadcastReceiver, UserHandle.ALL, intentFilter, null, mHandler);
reevaluate();
}
@@ -164,7 +159,17 @@
@VisibleForTesting
public void reevaluate() {
- mHandler.post(mReevaluateRunnable);
+ mHandler.post(this::reevaluateInternal);
+ }
+
+ /**
+ * Reevaluate the settings. Must be called on the handler thread.
+ */
+ private void reevaluateInternal() {
+ if (updateAvoidBadWifi() && mAvoidBadWifiCallback != null) {
+ mAvoidBadWifiCallback.run();
+ }
+ updateMeteredMultipathPreference();
}
public boolean updateAvoidBadWifi() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 667445b..18a8148 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.NETID_UNSET;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_VPN;
@@ -1101,7 +1102,7 @@
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
- final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext);
+ final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler);
dataConnectionStats.startMonitoring();
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
@@ -2164,7 +2165,11 @@
}
}
- void systemReady() {
+ /**
+ * Called when the system is ready and ConnectivityService can initialize remaining components.
+ */
+ @VisibleForTesting
+ public void systemReady() {
mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
mTethering.systemReady();
@@ -2806,7 +2811,7 @@
switch (msg.what) {
default:
return false;
- case android.net.NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: {
+ case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: {
handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid,
/* callOnUnavailable */ true);
break;
@@ -4550,7 +4555,7 @@
Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
return false;
}
- setLockdownTracker(new LockdownVpnTracker(mContext, mNMS, this, vpn, profile));
+ setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
} else {
setLockdownTracker(null);
}
@@ -7011,6 +7016,12 @@
}
}
+ // restore private DNS settings to default mode (opportunistic)
+ if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+ }
+
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
}
diff --git a/services/core/java/com/android/server/NetIdManager.java b/services/core/java/com/android/server/NetIdManager.java
index 11533be..097fb3a 100644
--- a/services/core/java/com/android/server/NetIdManager.java
+++ b/services/core/java/com/android/server/NetIdManager.java
@@ -20,6 +20,7 @@
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
/**
* Class used to reserve and release net IDs.
@@ -38,14 +39,25 @@
@GuardedBy("mNetIdInUse")
private int mLastNetId = MIN_NET_ID - 1;
+ private final int mMaxNetId;
+
+ public NetIdManager() {
+ this(MAX_NET_ID);
+ }
+
+ @VisibleForTesting
+ NetIdManager(int maxNetId) {
+ mMaxNetId = maxNetId;
+ }
+
/**
* Get the first netId that follows the provided lastId and is available.
*/
- private static int getNextAvailableNetIdLocked(
+ private 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;
+ for (int i = MIN_NET_ID; i <= mMaxNetId; i++) {
+ netId = netId < mMaxNetId ? netId + 1 : MIN_NET_ID;
if (!netIdInUse.get(netId)) {
return netId;
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index fbe2589..29c4bad 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -130,6 +130,11 @@
}
@Override
+ public void onPackageChanged(@NonNull String packageName, int uid) {
+ sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
+ }
+
+ @Override
public void onPackageRemoved(String packageName, int uid) {
sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
}
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 502aa97..e91abb6 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -20,8 +20,6 @@
"libdl_android",
"libhidl-gen-utils",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libjsoncpp",
"liblog",
"liblzma",
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
new file mode 100644
index 0000000..91b3cd9
--- /dev/null
+++ b/tests/net/integration/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.server.net.integrationtests">
+
+ <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <!-- PermissionMonitor sets network permissions for each user -->
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <!-- ConnectivityService sends notifications to BatteryStats -->
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+
+ <!-- This manifest is merged with the base manifest of the real NetworkStack app.
+ Remove the NetworkStackService from the base (real) manifest, and replace with a test
+ service that responds to the same intent -->
+ <service android:name="com.android.server.NetworkStackService" tools:node="remove"/>
+ <service android:name=".TestNetworkStackService"
+ android:process="com.android.server.net.integrationtests.testnetworkstack">
+ <intent-filter>
+ <action android:name="android.net.INetworkStackConnector.Test"/>
+ </intent-filter>
+ </service>
+ <service android:name=".NetworkStackInstrumentationService"
+ android:process="com.android.server.net.integrationtests.testnetworkstack">
+ <intent-filter>
+ <action android:name=".INetworkStackInstrumentation"/>
+ </intent-filter>
+ </service>
+ <service tools:replace="android:process"
+ android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
+ android:process="com.android.server.net.integrationtests.testnetworkstack"/>
+
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.net.integrationtests"
+ android:label="Frameworks Net Integration Tests" />
+
+</manifest>
diff --git a/tests/net/integration/res/values/config.xml b/tests/net/integration/res/values/config.xml
new file mode 100644
index 0000000..2c8046f
--- /dev/null
+++ b/tests/net/integration/res/values/config.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!--
+ Override configuration for testing. The below settings use the config_ variants, which are
+ normally used by RROs to override the setting with highest priority. -->
+ <integer name="config_captive_portal_dns_probe_timeout">12500</integer>
+ <string name="config_captive_portal_http_url" translatable="false">http://test.android.com</string>
+ <string name="config_captive_portal_https_url" translatable="false">https://secure.test.android.com</string>
+ <string-array name="config_captive_portal_fallback_urls" translatable="false">
+ <item>http://fallback1.android.com</item>
+ <item>http://fallback2.android.com</item>
+ </string-array>
+ <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
+ </string-array>
+</resources>
diff --git a/tests/net/integration/src/android/net/TestNetworkStackClient.kt b/tests/net/integration/src/android/net/TestNetworkStackClient.kt
new file mode 100644
index 0000000..01eb514
--- /dev/null
+++ b/tests/net/integration/src/android/net/TestNetworkStackClient.kt
@@ -0,0 +1,80 @@
+/*
+ * 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 android.net
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.os.IBinder
+import com.android.server.net.integrationtests.TestNetworkStackService
+import org.mockito.Mockito.any
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.timeout
+import org.mockito.Mockito.verify
+import kotlin.test.fail
+
+const val TEST_ACTION_SUFFIX = ".Test"
+
+class TestNetworkStackClient(context: Context) : NetworkStackClient(TestDependencies(context)) {
+ // TODO: consider switching to TrackRecord for more expressive checks
+ private val lastCallbacks = HashMap<Network, INetworkMonitorCallbacks>()
+
+ private class TestDependencies(private val context: Context) : Dependencies {
+ override fun addToServiceManager(service: IBinder) = Unit
+ override fun checkCallerUid() = Unit
+
+ override fun getConnectivityModuleConnector(): ConnectivityModuleConnector {
+ return ConnectivityModuleConnector { _, _, _, inSystemProcess ->
+ getNetworkStackIntent(inSystemProcess)
+ }.also { it.init(context) }
+ }
+
+ private fun getNetworkStackIntent(inSystemProcess: Boolean): Intent? {
+ // Simulate out-of-system-process config: in-process service not found (null intent)
+ if (inSystemProcess) return null
+ val intent = Intent(INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX)
+ val serviceName = TestNetworkStackService::class.qualifiedName
+ ?: fail("TestNetworkStackService name not found")
+ intent.component = ComponentName(context.packageName, serviceName)
+ return intent
+ }
+ }
+
+ // base may be an instance of an inaccessible subclass, so non-spyable.
+ // Use a known open class that delegates to the original instance for all methods except
+ // asBinder. asBinder needs to use its own non-delegated implementation as otherwise it would
+ // return a binder token to a class that is not spied on.
+ open class NetworkMonitorCallbacksWrapper(private val base: INetworkMonitorCallbacks) :
+ INetworkMonitorCallbacks.Stub(), INetworkMonitorCallbacks by base {
+ // asBinder is implemented by both base class and delegate: specify explicitly
+ override fun asBinder(): IBinder {
+ return super.asBinder()
+ }
+ }
+
+ override fun makeNetworkMonitor(network: Network, name: String?, cb: INetworkMonitorCallbacks) {
+ val cbSpy = spy(NetworkMonitorCallbacksWrapper(cb))
+ lastCallbacks[network] = cbSpy
+ super.makeNetworkMonitor(network, name, cbSpy)
+ }
+
+ fun verifyNetworkMonitorCreated(network: Network, timeoutMs: Long) {
+ val cb = lastCallbacks[network]
+ ?: fail("NetworkMonitor for network $network not requested")
+ verify(cb, timeout(timeoutMs)).onNetworkMonitorCreated(any())
+ }
+}
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
new file mode 100644
index 0000000..334b26d
--- /dev/null
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -0,0 +1,210 @@
+/*
+ * 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.net.integrationtests
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Context.BIND_AUTO_CREATE
+import android.content.Context.BIND_IMPORTANT
+import android.content.Intent
+import android.content.ServiceConnection
+import android.net.ConnectivityManager
+import android.net.IDnsResolver
+import android.net.INetd
+import android.net.INetworkPolicyManager
+import android.net.INetworkStatsService
+import android.net.LinkProperties
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkRequest
+import android.net.TestNetworkStackClient
+import android.net.metrics.IpConnectivityLog
+import android.os.ConditionVariable
+import android.os.IBinder
+import android.os.INetworkManagementService
+import android.testing.TestableContext
+import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.ConnectivityService
+import com.android.server.LocalServices
+import com.android.server.NetworkAgentWrapper
+import com.android.server.TestNetIdManager
+import com.android.server.connectivity.DefaultNetworkMetrics
+import com.android.server.connectivity.IpConnectivityMetrics
+import com.android.server.connectivity.MockableSystemProperties
+import com.android.server.connectivity.ProxyTracker
+import com.android.server.connectivity.Tethering
+import com.android.server.net.NetworkPolicyManagerInternal
+import com.android.testutils.TestableNetworkCallback
+import org.junit.After
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doNothing
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.MockitoAnnotations
+import org.mockito.Spy
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+import kotlin.test.fail
+
+const val SERVICE_BIND_TIMEOUT_MS = 5_000L
+const val TEST_TIMEOUT_MS = 1_000L
+
+/**
+ * Test that exercises an instrumented version of ConnectivityService against an instrumented
+ * NetworkStack in a different test process.
+ */
+@RunWith(AndroidJUnit4::class)
+class ConnectivityServiceIntegrationTest {
+ // lateinit used here for mocks as they need to be reinitialized between each test and the test
+ // should crash if they are used before being initialized.
+ @Mock
+ private lateinit var netManager: INetworkManagementService
+ @Mock
+ private lateinit var statsService: INetworkStatsService
+ @Mock
+ private lateinit var policyManager: INetworkPolicyManager
+ @Mock
+ private lateinit var log: IpConnectivityLog
+ @Mock
+ private lateinit var netd: INetd
+ @Mock
+ private lateinit var dnsResolver: IDnsResolver
+ @Mock
+ private lateinit var metricsLogger: IpConnectivityMetrics.Logger
+ @Mock
+ private lateinit var defaultMetrics: DefaultNetworkMetrics
+ @Spy
+ private var context = TestableContext(realContext)
+
+ // lateinit for these three classes under test, as they should be reset to a different instance
+ // for every test but should always be initialized before use (or the test should crash).
+ private lateinit var networkStackClient: TestNetworkStackClient
+ private lateinit var service: ConnectivityService
+ private lateinit var cm: ConnectivityManager
+
+ companion object {
+ // lateinit for this binder token, as it must be initialized before any test code is run
+ // and use of it before init should crash the test.
+ private lateinit var nsInstrumentation: INetworkStackInstrumentation
+ private val bindingCondition = ConditionVariable(false)
+
+ private val realContext get() = InstrumentationRegistry.getInstrumentation().context
+
+ private class InstrumentationServiceConnection : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
+ Log.i("TestNetworkStack", "Service connected")
+ try {
+ if (service == null) fail("Error binding to NetworkStack instrumentation")
+ if (::nsInstrumentation.isInitialized) fail("Service already connected")
+ nsInstrumentation = INetworkStackInstrumentation.Stub.asInterface(service)
+ } finally {
+ bindingCondition.open()
+ }
+ }
+
+ override fun onServiceDisconnected(name: ComponentName?) = Unit
+ }
+
+ @BeforeClass
+ @JvmStatic
+ fun setUpClass() {
+ val intent = Intent(realContext, NetworkStackInstrumentationService::class.java)
+ intent.action = INetworkStackInstrumentation::class.qualifiedName
+ assertTrue(realContext.bindService(intent, InstrumentationServiceConnection(),
+ BIND_AUTO_CREATE or BIND_IMPORTANT),
+ "Error binding to instrumentation service")
+ assertTrue(bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
+ "Timed out binding to instrumentation service " +
+ "after $SERVICE_BIND_TIMEOUT_MS ms")
+ }
+ }
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ doReturn(defaultMetrics).`when`(metricsLogger).defaultNetworkMetrics()
+ doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any())
+
+ networkStackClient = TestNetworkStackClient(realContext)
+ networkStackClient.init()
+ networkStackClient.start()
+
+ LocalServices.removeServiceForTest(NetworkPolicyManagerInternal::class.java)
+ LocalServices.addService(NetworkPolicyManagerInternal::class.java,
+ mock(NetworkPolicyManagerInternal::class.java))
+
+ service = TestConnectivityService(makeDependencies())
+ cm = ConnectivityManager(context, service)
+ context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
+
+ service.systemReady()
+ }
+
+ private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
+ context, netManager, statsService, policyManager, dnsResolver, log, netd, deps)
+
+ private fun makeDependencies(): ConnectivityService.Dependencies {
+ val deps = spy(ConnectivityService.Dependencies())
+ doReturn(networkStackClient).`when`(deps).networkStack
+ doReturn(metricsLogger).`when`(deps).metricsLogger
+ doReturn(mock(Tethering::class.java)).`when`(deps).makeTethering(
+ any(), any(), any(), any(), any())
+ doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
+ doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
+ doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
+ return deps
+ }
+
+ @After
+ fun tearDown() {
+ nsInstrumentation.clearAllState()
+ }
+
+ @Test
+ fun testValidation() {
+ val request = NetworkRequest.Builder()
+ .clearCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build()
+ val testCallback = TestableNetworkCallback()
+
+ cm.registerNetworkCallback(request, testCallback)
+ nsInstrumentation.addHttpResponse(HttpResponse(
+ "http://test.android.com",
+ responseCode = 204, contentLength = 42, redirectUrl = null))
+ nsInstrumentation.addHttpResponse(HttpResponse(
+ "https://secure.test.android.com",
+ responseCode = 204, contentLength = 42, redirectUrl = null))
+
+ val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), context)
+ networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
+
+ na.addCapability(NET_CAPABILITY_INTERNET)
+ na.connect()
+
+ testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS)
+ assertEquals(2, nsInstrumentation.getRequestUrls().size)
+ }
+}
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
new file mode 100644
index 0000000..45073d8
--- /dev/null
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.net.integrationtests
+
+import android.os.Parcel
+import android.os.Parcelable
+
+data class HttpResponse(
+ val requestUrl: String,
+ val responseCode: Int,
+ val contentLength: Long,
+ val redirectUrl: String?
+) : Parcelable {
+ constructor(p: Parcel): this(p.readString(), p.readInt(), p.readLong(), p.readString())
+
+ override fun writeToParcel(dest: Parcel, flags: Int) {
+ with(dest) {
+ writeString(requestUrl)
+ writeInt(responseCode)
+ writeLong(contentLength)
+ writeString(redirectUrl)
+ }
+ }
+
+ override fun describeContents() = 0
+ companion object CREATOR : Parcelable.Creator<HttpResponse> {
+ override fun createFromParcel(source: Parcel) = HttpResponse(source)
+ override fun newArray(size: Int) = arrayOfNulls<HttpResponse?>(size)
+ }
+}
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
new file mode 100644
index 0000000..4827d29
--- /dev/null
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.net.integrationtests
+
+import android.app.Service
+import android.content.Intent
+import java.net.URL
+import java.util.Collections
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.ConcurrentLinkedQueue
+import kotlin.collections.ArrayList
+import kotlin.test.fail
+
+/**
+ * An instrumentation interface for the NetworkStack that allows controlling behavior to
+ * facilitate integration tests.
+ */
+class NetworkStackInstrumentationService : Service() {
+ override fun onBind(intent: Intent) = InstrumentationConnector.asBinder()
+
+ object InstrumentationConnector : INetworkStackInstrumentation.Stub() {
+ private val httpResponses = ConcurrentHashMap<String, ConcurrentLinkedQueue<HttpResponse>>()
+ .run {
+ withDefault { key -> getOrPut(key) { ConcurrentLinkedQueue() } }
+ }
+ private val httpRequestUrls = Collections.synchronizedList(ArrayList<String>())
+
+ /**
+ * Called when an HTTP request is being processed by NetworkMonitor. Returns the response
+ * that should be simulated.
+ */
+ fun processRequest(url: URL): HttpResponse {
+ val strUrl = url.toString()
+ httpRequestUrls.add(strUrl)
+ return httpResponses[strUrl]?.poll()
+ ?: fail("No mocked response for request: $strUrl. " +
+ "Mocked URL keys are: ${httpResponses.keys}")
+ }
+
+ /**
+ * Clear all state of this connector. This is intended for use between two tests, so all
+ * state should be reset as if the connector was just created.
+ */
+ override fun clearAllState() {
+ httpResponses.clear()
+ httpRequestUrls.clear()
+ }
+
+ /**
+ * Add a response to a future HTTP request.
+ *
+ * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be
+ * used to mock the query response.
+ */
+ override fun addHttpResponse(response: HttpResponse) {
+ httpResponses.getValue(response.requestUrl).add(response)
+ }
+
+ /**
+ * Get the ordered list of request URLs that have been sent by NetworkMonitor, and were
+ * answered based on mock responses.
+ */
+ override fun getRequestUrls(): List<String> {
+ return ArrayList(httpRequestUrls)
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
new file mode 100644
index 0000000..8e4a9dd
--- /dev/null
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.net.integrationtests
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.net.INetworkMonitorCallbacks
+import android.net.Network
+import android.net.metrics.IpConnectivityLog
+import android.net.util.SharedLog
+import android.os.IBinder
+import com.android.networkstack.metrics.DataStallStatsUtils
+import com.android.server.NetworkStackService.NetworkMonitorConnector
+import com.android.server.NetworkStackService.NetworkStackConnector
+import com.android.server.connectivity.NetworkMonitor
+import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import java.net.HttpURLConnection
+import java.net.URL
+import java.net.URLConnection
+
+private const val TEST_NETID = 42
+
+/**
+ * Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
+ * through [NetworkStackInstrumentationService].
+ * Useful in tests to create test instrumented NetworkStack components that can receive
+ * instrumentation commands through [NetworkStackInstrumentationService].
+ */
+class TestNetworkStackService : Service() {
+ override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
+
+ private fun makeTestContext() = spy(applicationContext).also {
+ doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
+ }
+
+ private class TestPermissionChecker : NetworkStackConnector.PermissionChecker() {
+ override fun enforceNetworkStackCallingPermission() = Unit
+ }
+
+ private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
+ NetworkMonitor.Dependencies() {
+ override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
+ override fun sendNetworkConditionsBroadcast(context: Context, broadcast: Intent) = Unit
+ }
+
+ private inner class TestNetworkStackConnector(context: Context) :
+ NetworkStackConnector(context, TestPermissionChecker()) {
+
+ private val network = Network(TEST_NETID)
+ private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
+
+ private inner class TestNetwork(netId: Int) : Network(netId) {
+ override fun openConnection(url: URL): URLConnection {
+ val response = InstrumentationConnector.processRequest(url)
+
+ val connection = mock(HttpURLConnection::class.java)
+ doReturn(response.responseCode).`when`(connection).responseCode
+ doReturn(response.contentLength).`when`(connection).contentLengthLong
+ doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
+ return connection
+ }
+ }
+
+ override fun makeNetworkMonitor(
+ network: Network,
+ name: String?,
+ cb: INetworkMonitorCallbacks
+ ) {
+ val nm = NetworkMonitor(this@TestNetworkStackService, cb,
+ this.network,
+ mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
+ NetworkMonitorDeps(privateDnsBypassNetwork),
+ mock(DataStallStatsUtils::class.java))
+ cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index b0e5fb1..daf187d 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -254,6 +254,39 @@
}
}
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
/**
* Tests that link-local address generation from MAC is valid.
*/
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a028a54..f2f258a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -184,6 +184,7 @@
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -2259,9 +2260,8 @@
// If user accepted partial connectivity network before,
// NetworkMonitor#setAcceptPartialConnectivity() will be called in
// ConnectivityService#updateNetworkInfo().
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
@@ -2281,9 +2281,8 @@
// If user accepted partial connectivity network before,
// NetworkMonitor#setAcceptPartialConnectivity() will be called in
// ConnectivityService#updateNetworkInfo().
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
@@ -2306,9 +2305,8 @@
// valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
// notifyNetworkConnected.
mWiFiNetworkAgent.connectWithPartialValidConnectivity();
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(
NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
@@ -3425,7 +3423,7 @@
testFactory.setScoreFilter(40);
// Register the factory and expect it to receive the default request.
- testFactory.expectAddRequestsWithScores(0); // default request score is 0, not served yet
+ testFactory.expectAddRequestsWithScores(0);
testFactory.register();
SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
@@ -3633,6 +3631,7 @@
}
@Test
+ @FlakyTest(bugId = 140305589)
public void testPacketKeepalives() throws Exception {
InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
@@ -5692,26 +5691,40 @@
String[] values = tcpBufferSizes.split(",");
String rmemValues = String.join(" ", values[0], values[1], values[2]);
String wmemValues = String.join(" ", values[3], values[4], values[5]);
- waitForIdle();
verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
reset(mMockNetd);
}
@Test
+ @FlakyTest(bugId = 140305678)
public void testTcpBufferReset() throws Exception {
final String testTcpBufferSizes = "1,2,3,4,5,6";
+ final NetworkRequest networkRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
reset(mMockNetd);
// Switching default network updates TCP buffer sizes.
mCellNetworkAgent.connect(false);
+ networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
// Change link Properties should have updated tcp buffer size.
LinkProperties lp = new LinkProperties();
lp.setTcpBufferSizes(testTcpBufferSizes);
mCellNetworkAgent.sendLinkProperties(lp);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verifyTcpBufferSizeChange(testTcpBufferSizes);
+
+ // Clean up.
+ mCellNetworkAgent.disconnect();
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ networkCallback.assertNoCallback();
+ mCm.unregisterNetworkCallback(networkCallback);
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 7c40adf..71b72b8 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -32,6 +32,7 @@
import android.app.AppOpsManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.net.INetd;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
@@ -57,6 +58,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import java.net.Inet4Address;
import java.net.Socket;
import java.util.Arrays;
import java.util.Collection;
@@ -119,6 +121,11 @@
}
@Override
+ public PackageManager getPackageManager() {
+ return mMockPkgMgr;
+ }
+
+ @Override
public void enforceCallingOrSelfPermission(String permission, String message) {
if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
return;
@@ -128,6 +135,7 @@
};
INetd mMockNetd;
+ PackageManager mMockPkgMgr;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
Network fakeNetwork = new Network(0xAB);
@@ -152,11 +160,16 @@
@Before
public void setUp() throws Exception {
mMockNetd = mock(INetd.class);
+ mMockPkgMgr = mock(PackageManager.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+
+ // PackageManager should always return true (feature flag tests in IpSecServiceTest)
+ when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
+
// A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
.thenReturn(AppOpsManager.MODE_ALLOWED);
@@ -709,4 +722,18 @@
} catch (SecurityException expected) {
}
}
+
+ @Test
+ public void testFeatureFlagVerification() throws Exception {
+ when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS)))
+ .thenReturn(false);
+
+ try {
+ String addr = Inet4Address.getLoopbackAddress().getHostAddress();
+ mIpSecService.createTunnelInterface(
+ addr, addr, new Network(0), new Binder(), "blessedPackage");
+ fail("Expected UnsupportedOperationException for disabled feature");
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/tests/net/java/com/android/server/NetIdManagerTest.kt
new file mode 100644
index 0000000..045f89f
--- /dev/null
+++ b/tests/net/java/com/android/server/NetIdManagerTest.kt
@@ -0,0 +1,53 @@
+/*
+ * 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 androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.server.NetIdManager.MIN_NET_ID
+import com.android.testutils.ExceptionUtils.ThrowingRunnable
+import com.android.testutils.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class NetIdManagerTest {
+ @Test
+ fun testReserveReleaseNetId() {
+ val manager = NetIdManager(MIN_NET_ID + 4)
+ assertEquals(MIN_NET_ID, manager.reserveNetId())
+ assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
+ assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
+ assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
+
+ manager.releaseNetId(MIN_NET_ID + 1)
+ manager.releaseNetId(MIN_NET_ID + 3)
+ // IDs only loop once there is no higher ID available
+ assertEquals(MIN_NET_ID + 4, manager.reserveNetId())
+ assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
+ assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
+ assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
+ manager.releaseNetId(MIN_NET_ID + 5)
+ // Still no ID available: MIN_NET_ID + 5 was not reserved
+ assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
+ manager.releaseNetId(MIN_NET_ID + 2)
+ // Throwing an exception still leaves the manager in a working state
+ assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
+ }
+}
\ No newline at end of file