Merge "Use system API to obtain IDnsResolver IBinder"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cf5d4e5..540ea5c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2108,17 +2108,6 @@
// ignored
}
- /** {@hide} */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
- try {
- return mService.getActiveNetworkQuotaInfo();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/**
* @hide
* @deprecated Talk to TelephonyManager directly
@@ -3163,9 +3152,9 @@
}
/**
- * Set sign in error notification to visible or in visible
+ * Set sign in error notification to visible or invisible
*
- * {@hide}
+ * @hide
* @deprecated Doesn't properly deal with multiple connected networks of the same type.
*/
@Deprecated
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4173200..95a2f2e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -25,13 +25,13 @@
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.INetworkActivityListener;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -76,7 +76,6 @@
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
- NetworkQuotaInfo getActiveNetworkQuotaInfo();
boolean isActiveNetworkMetered();
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress,
@@ -235,4 +234,10 @@
in PersistableBundle extras);
void systemReady();
+
+ void registerNetworkActivityListener(in INetworkActivityListener l);
+
+ void unregisterNetworkActivityListener(in INetworkActivityListener l);
+
+ boolean isDefaultNetworkActive();
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0941e7d..486e2d7 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -20,12 +20,13 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.LinkPropertiesUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.net.module.util.LinkPropertiesUtils;
+
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 178183d..c7116b4 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -20,13 +20,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d84ee2a..b5962c5 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,14 +16,9 @@
package android.net;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.system.ErrnoException;
-import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -155,14 +150,6 @@
public static native Network getDnsNetwork() throws ErrnoException;
/**
- * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
- *
- * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
- * and DNS lookups.
- */
- public static native void setAllowNetworkingForProcess(boolean allowNetworking);
-
- /**
* Get the tcp repair window associated with the {@code fd}.
*
* @param fd the tcp socket's {@link FileDescriptor}.
@@ -437,60 +424,4 @@
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;
- }
-
- /**
- * Safely multiple a value by a rational.
- * <p>
- * Internally it uses integer-based math whenever possible, but switches
- * over to double-based math if values would overflow.
- * @hide
- */
- public static long multiplySafeByRational(long value, long num, long den) {
- if (den == 0) {
- throw new ArithmeticException("Invalid Denominator");
- }
- long x = value;
- long y = num;
-
- // Logic shamelessly borrowed from Math.multiplyExact()
- long r = x * y;
- long ax = Math.abs(x);
- long ay = Math.abs(y);
- if (((ax | ay) >>> 31 != 0)) {
- // Some bits greater than 2^31 that might cause overflow
- // Check the result using the divide operator
- // and check for the special case of Long.MIN_VALUE * -1
- if (((y != 0) && (r / y != x)) ||
- (x == Long.MIN_VALUE && y == -1)) {
- // Use double math to avoid overflowing
- return (long) (((double) num / den) * value);
- }
- }
- return r / den;
- }
}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 6166a75..94f849f 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -21,11 +21,12 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.NetUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.net.module.util.NetUtils;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java
new file mode 100644
index 0000000..ddb3a6a
--- /dev/null
+++ b/core/java/android/net/TcpKeepalivePacketData.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2020 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.util.Objects;
+
+/**
+ * Represents the actual tcp keep alive packets which will be used for hardware offload.
+ * @hide
+ */
+@SystemApi
+public final class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
+ private static final String TAG = "TcpKeepalivePacketData";
+
+ /** TCP sequence number. */
+ public final int tcpSeq;
+
+ /** TCP ACK number. */
+ public final int tcpAck;
+
+ /** TCP RCV window. */
+ public final int tcpWindow;
+
+ /** TCP RCV window scale. */
+ public final int tcpWindowScale;
+
+ /** IP TOS. */
+ public final int ipTos;
+
+ /** IP TTL. */
+ public final int ipTtl;
+
+ public TcpKeepalivePacketData(@NonNull final InetAddress srcAddress, int srcPort,
+ @NonNull final InetAddress dstAddress, int dstPort, @NonNull final byte[] data,
+ int tcpSeq, int tcpAck, int tcpWindow, int tcpWindowScale, int ipTos, int ipTtl)
+ throws InvalidPacketException {
+ super(srcAddress, srcPort, dstAddress, dstPort, data);
+ this.tcpSeq = tcpSeq;
+ this.tcpAck = tcpAck;
+ this.tcpWindow = tcpWindow;
+ this.tcpWindowScale = tcpWindowScale;
+ this.ipTos = ipTos;
+ this.ipTtl = ipTtl;
+ }
+
+ @Override
+ public boolean equals(@Nullable final Object o) {
+ if (!(o instanceof TcpKeepalivePacketData)) return false;
+ final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o;
+ final InetAddress srcAddress = getSrcAddress();
+ final InetAddress dstAddress = getDstAddress();
+ return srcAddress.equals(other.getSrcAddress())
+ && dstAddress.equals(other.getDstAddress())
+ && getSrcPort() == other.getSrcPort()
+ && getDstPort() == other.getDstPort()
+ && this.tcpAck == other.tcpAck
+ && this.tcpSeq == other.tcpSeq
+ && this.tcpWindow == other.tcpWindow
+ && this.tcpWindowScale == other.tcpWindowScale
+ && this.ipTos == other.ipTos
+ && this.ipTtl == other.ipTtl;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(),
+ tcpAck, tcpSeq, tcpWindow, tcpWindowScale, ipTos, ipTtl);
+ }
+
+ /**
+ * Parcelable Implementation.
+ * Note that this object implements parcelable (and needs to keep doing this as it inherits
+ * from a class that does), but should usually be parceled as a stable parcelable using
+ * the toStableParcelable() and fromStableParcelable() methods.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel. */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeString(getSrcAddress().getHostAddress());
+ out.writeString(getDstAddress().getHostAddress());
+ out.writeInt(getSrcPort());
+ out.writeInt(getDstPort());
+ out.writeByteArray(getPacket());
+ out.writeInt(tcpSeq);
+ out.writeInt(tcpAck);
+ out.writeInt(tcpWindow);
+ out.writeInt(tcpWindowScale);
+ out.writeInt(ipTos);
+ out.writeInt(ipTtl);
+ }
+
+ private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException {
+ InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString());
+ InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString());
+ int srcPort = in.readInt();
+ int dstPort = in.readInt();
+ byte[] packet = in.createByteArray();
+ int tcpSeq = in.readInt();
+ int tcpAck = in.readInt();
+ int tcpWnd = in.readInt();
+ int tcpWndScale = in.readInt();
+ int ipTos = in.readInt();
+ int ipTtl = in.readInt();
+ return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq,
+ tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl);
+ }
+
+ /** Parcelable Creator. */
+ public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+ new Parcelable.Creator<TcpKeepalivePacketData>() {
+ public TcpKeepalivePacketData createFromParcel(Parcel in) {
+ try {
+ return readFromParcel(in);
+ } catch (InvalidPacketException e) {
+ throw new IllegalArgumentException(
+ "Invalid TCP keepalive data: " + e.getError());
+ }
+ }
+
+ public TcpKeepalivePacketData[] newArray(int size) {
+ return new TcpKeepalivePacketData[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "saddr: " + getSrcAddress()
+ + " daddr: " + getDstAddress()
+ + " sport: " + getSrcPort()
+ + " dport: " + getDstPort()
+ + " seq: " + tcpSeq
+ + " ack: " + tcpAck
+ + " window: " + tcpWindow
+ + " windowScale: " + tcpWindowScale
+ + " tos: " + ipTos
+ + " ttl: " + ipTtl;
+ }
+}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8d4c4e5..2155246 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, The Android Open Source Project
+ * Copyright 2020, 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.
@@ -28,7 +28,6 @@
#include <netinet/udp.h>
#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
-#include <android_runtime/AndroidRuntime.h>
#include <cutils/properties.h>
#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -226,11 +225,6 @@
class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass);
}
-static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
- jboolean hasConnectivity) {
- setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
-}
-
static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
if (javaFd == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -288,7 +282,6 @@
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
{ "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
- { "setAllowNetworkingForProcess", "(Z)V", (void *)android_net_utils_setAllowNetworkingForProcess },
};
// clang-format on
diff --git a/service/Android.bp b/service/Android.bp
new file mode 100644
index 0000000..a26f715
--- /dev/null
+++ b/service/Android.bp
@@ -0,0 +1,79 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_defaults {
+ name: "libservice-connectivity-defaults",
+ // TODO: build against the NDK (sdk_version: "30" for example)
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wthread-safety",
+ ],
+ srcs: [
+ "jni/com_android_server_TestNetworkService.cpp",
+ "jni/com_android_server_connectivity_Vpn.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libnativehelper",
+ // TODO: remove dependency on ifc_[add/del]_address by having Java code to add/delete
+ // addresses, and remove dependency on libnetutils.
+ "libnetutils",
+ ],
+}
+
+cc_library_shared {
+ name: "libservice-connectivity",
+ defaults: ["libservice-connectivity-defaults"],
+ srcs: [
+ "jni/onload.cpp",
+ ],
+ apex_available: [
+ // TODO: move this library to the tethering APEX and remove libservice-connectivity-static
+ // "com.android.tethering",
+ ],
+}
+
+// Static library linked into libservices.core until libservice-connectivity can be loaded from
+// the tethering APEX instead.
+cc_library_static {
+ name: "libservice-connectivity-static",
+ defaults: ["libservice-connectivity-defaults"],
+}
+
+java_library {
+ name: "service-connectivity",
+ srcs: [
+ ":connectivity-service-srcs",
+ ],
+ installable: true,
+ jarjar_rules: "jarjar-rules.txt",
+ libs: [
+ "android.net.ipsec.ike",
+ "services.core",
+ "services.net",
+ "unsupportedappusage",
+ ],
+ static_libs: [
+ "net-utils-device-common",
+ "net-utils-framework-common",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ ],
+}
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
new file mode 100644
index 0000000..ef53ebb
--- /dev/null
+++ b/service/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.android.net.module.util.** com.android.connectivity.util.@1
\ No newline at end of file
diff --git a/services/core/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
similarity index 100%
rename from services/core/jni/com_android_server_TestNetworkService.cpp
rename to service/jni/com_android_server_TestNetworkService.cpp
diff --git a/service/jni/com_android_server_connectivity_Vpn.cpp b/service/jni/com_android_server_connectivity_Vpn.cpp
new file mode 100644
index 0000000..ea5e718
--- /dev/null
+++ b/service/jni/com_android_server_connectivity_Vpn.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "VpnJni"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/route.h>
+#include <linux/ipv6_route.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <android/log.h>
+
+#include "netutils/ifc.h"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+
+namespace android
+{
+
+static int inet4 = -1;
+static int inet6 = -1;
+
+static inline in_addr_t *as_in_addr(sockaddr *sa) {
+ return &((sockaddr_in *)sa)->sin_addr.s_addr;
+}
+
+//------------------------------------------------------------------------------
+
+#define SYSTEM_ERROR (-1)
+#define BAD_ARGUMENT (-2)
+
+static int create_interface(int mtu)
+{
+ int tun = open("/dev/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC);
+
+ ifreq ifr4;
+ memset(&ifr4, 0, sizeof(ifr4));
+
+ // Allocate interface.
+ ifr4.ifr_flags = IFF_TUN | IFF_NO_PI;
+ if (ioctl(tun, TUNSETIFF, &ifr4)) {
+ ALOGE("Cannot allocate TUN: %s", strerror(errno));
+ goto error;
+ }
+
+ // Activate interface.
+ ifr4.ifr_flags = IFF_UP;
+ if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) {
+ ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno));
+ goto error;
+ }
+
+ // Set MTU if it is specified.
+ ifr4.ifr_mtu = mtu;
+ if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) {
+ ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno));
+ goto error;
+ }
+
+ return tun;
+
+error:
+ close(tun);
+ return SYSTEM_ERROR;
+}
+
+static int get_interface_name(char *name, int tun)
+{
+ ifreq ifr4;
+ if (ioctl(tun, TUNGETIFF, &ifr4)) {
+ ALOGE("Cannot get interface name: %s", strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+ return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+ ALOGE("Cannot get index of %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
+{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
+ ifreq ifr4;
+ memset(&ifr4, 0, sizeof(ifr4));
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_addr.sa_family = AF_INET;
+ ifr4.ifr_netmask.sa_family = AF_INET;
+
+ in6_ifreq ifr6;
+ memset(&ifr6, 0, sizeof(ifr6));
+ ifr6.ifr6_ifindex = index;
+
+ char address[65];
+ int prefix;
+ int chars;
+ int count = 0;
+
+ while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) {
+ addresses += chars;
+
+ if (strchr(address, ':')) {
+ // Add an IPv6 address.
+ if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 ||
+ prefix < 0 || prefix > 128) {
+ count = BAD_ARGUMENT;
+ break;
+ }
+
+ ifr6.ifr6_prefixlen = prefix;
+ if (ioctl(inet6, SIOCSIFADDR, &ifr6)) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+ } else {
+ // Add an IPv4 address.
+ if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 ||
+ prefix < 0 || prefix > 32) {
+ count = BAD_ARGUMENT;
+ break;
+ }
+
+ if (count) {
+ snprintf(ifr4.ifr_name, sizeof(ifr4.ifr_name), "%s:%d", name, count);
+ }
+ if (ioctl(inet4, SIOCSIFADDR, &ifr4)) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+
+ in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
+ *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
+ if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
+ count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
+ break;
+ }
+ }
+ ALOGD("Address added on %s: %s/%d", name, address, prefix);
+ ++count;
+ }
+
+ if (count == BAD_ARGUMENT) {
+ ALOGE("Invalid address: %s/%d", address, prefix);
+ } else if (count == SYSTEM_ERROR) {
+ ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno));
+ } else if (*addresses) {
+ ALOGE("Invalid address: %s", addresses);
+ count = BAD_ARGUMENT;
+ }
+
+ return count;
+}
+
+static int reset_interface(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
+
+ if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
+ ALOGE("Cannot reset %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+static int check_interface(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
+
+ if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
+ ALOGE("Cannot check %s: %s", name, strerror(errno));
+ }
+ return ifr4.ifr_flags;
+}
+
+static bool modifyAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
+ jint jPrefixLength, bool add)
+{
+ int error = SYSTEM_ERROR;
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *address = jAddress ? env->GetStringUTFChars(jAddress, NULL) : NULL;
+
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ } else if (!address) {
+ jniThrowNullPointerException(env, "address");
+ } else {
+ if (add) {
+ if ((error = ifc_add_address(name, address, jPrefixLength)) != 0) {
+ ALOGE("Cannot add address %s/%d on interface %s (%s)", address, jPrefixLength, name,
+ strerror(-error));
+ }
+ } else {
+ if ((error = ifc_del_address(name, address, jPrefixLength)) != 0) {
+ ALOGE("Cannot del address %s/%d on interface %s (%s)", address, jPrefixLength, name,
+ strerror(-error));
+ }
+ }
+ }
+
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (address) {
+ env->ReleaseStringUTFChars(jAddress, address);
+ }
+ return !error;
+}
+
+//------------------------------------------------------------------------------
+
+static void throwException(JNIEnv *env, int error, const char *message)
+{
+ if (error == SYSTEM_ERROR) {
+ jniThrowException(env, "java/lang/IllegalStateException", message);
+ } else {
+ jniThrowException(env, "java/lang/IllegalArgumentException", message);
+ }
+}
+
+static jint create(JNIEnv *env, jobject /* thiz */, jint mtu)
+{
+ int tun = create_interface(mtu);
+ if (tun < 0) {
+ throwException(env, tun, "Cannot create interface");
+ return -1;
+ }
+ return tun;
+}
+
+static jstring getName(JNIEnv *env, jobject /* thiz */, jint tun)
+{
+ char name[IFNAMSIZ];
+ if (get_interface_name(name, tun) < 0) {
+ throwException(env, SYSTEM_ERROR, "Cannot get interface name");
+ return NULL;
+ }
+ return env->NewStringUTF(name);
+}
+
+static jint setAddresses(JNIEnv *env, jobject /* thiz */, jstring jName,
+ jstring jAddresses)
+{
+ const char *name = NULL;
+ const char *addresses = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
+ if (!addresses) {
+ jniThrowNullPointerException(env, "addresses");
+ goto error;
+ }
+ count = set_addresses(name, addresses);
+ if (count < 0) {
+ throwException(env, count, "Cannot set address");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (addresses) {
+ env->ReleaseStringUTFChars(jAddresses, addresses);
+ }
+ return count;
+}
+
+static void reset(JNIEnv *env, jobject /* thiz */, jstring jName)
+{
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ return;
+ }
+ if (reset_interface(name) < 0) {
+ throwException(env, SYSTEM_ERROR, "Cannot reset interface");
+ }
+ env->ReleaseStringUTFChars(jName, name);
+}
+
+static jint check(JNIEnv *env, jobject /* thiz */, jstring jName)
+{
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ return 0;
+ }
+ int flags = check_interface(name);
+ env->ReleaseStringUTFChars(jName, name);
+ return flags;
+}
+
+static bool addAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
+ jint jPrefixLength)
+{
+ return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, true);
+}
+
+static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress,
+ jint jPrefixLength)
+{
+ return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, false);
+}
+
+//------------------------------------------------------------------------------
+
+static const JNINativeMethod gMethods[] = {
+ {"jniCreate", "(I)I", (void *)create},
+ {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
+ {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+ {"jniReset", "(Ljava/lang/String;)V", (void *)reset},
+ {"jniCheck", "(Ljava/lang/String;)I", (void *)check},
+ {"jniAddAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)addAddress},
+ {"jniDelAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)delAddress},
+};
+
+int register_android_server_connectivity_Vpn(JNIEnv *env)
+{
+ if (inet4 == -1) {
+ inet4 = socket(AF_INET, SOCK_DGRAM, 0);
+ }
+ if (inet6 == -1) {
+ inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ }
+ return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
+ gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/service/jni/onload.cpp b/service/jni/onload.cpp
new file mode 100644
index 0000000..3afcb0e
--- /dev/null
+++ b/service/jni/onload.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
+
+namespace android {
+
+int register_android_server_connectivity_Vpn(JNIEnv* env);
+int register_android_server_TestNetworkService(JNIEnv* env);
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+ JNIEnv *env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("GetEnv failed");
+ return JNI_ERR;
+ }
+
+ if (register_android_server_connectivity_Vpn(env) < 0
+ || register_android_server_TestNetworkService(env) < 0) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
+
+};
\ No newline at end of file
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 037fac5..26c0e59 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -114,7 +114,6 @@
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkProvider;
-import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
@@ -138,8 +137,6 @@
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.shared.PrivateDnsConfig;
-import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
import android.os.Binder;
@@ -148,6 +145,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
@@ -193,6 +191,8 @@
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.BasicShellCommandHandler;
+import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
@@ -202,7 +202,6 @@
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.LingerMonitor;
import com.android.server.connectivity.MockableSystemProperties;
-import com.android.server.connectivity.MultipathPolicyTracker;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkNotificationManager;
@@ -443,11 +442,6 @@
private static final int EVENT_EXPIRE_NET_TRANSITION_WAKELOCK = 24;
/**
- * Used internally to indicate the system is ready.
- */
- private static final int EVENT_SYSTEM_READY = 25;
-
- /**
* used to add a network request with a pending intent
* obj = NetworkRequestInfo
*/
@@ -661,9 +655,6 @@
final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
@VisibleForTesting
- final MultipathPolicyTracker mMultipathPolicyTracker;
-
- @VisibleForTesting
final Map<IBinder, ConnectivityDiagnosticsCallbackInfo> mConnectivityDiagnosticsCallbacks =
new HashMap<>();
@@ -877,6 +868,10 @@
*/
@VisibleForTesting
public static class Dependencies {
+ public int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+
/**
* Get system properties to use in ConnectivityService.
*/
@@ -1163,8 +1158,6 @@
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
mMultinetworkPolicyTracker.start();
- mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
-
mDnsManager = new DnsManager(mContext, mDnsResolver);
registerPrivateDnsSettingsCallbacks();
}
@@ -1377,8 +1370,11 @@
return;
}
final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest();
+ final int requestId = satisfiedRequest != null
+ ? satisfiedRequest.requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.getNetId()));
+ "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
}
/**
@@ -1409,7 +1405,7 @@
@Override
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
final NetworkState state = getUnfilteredActiveNetworkState(uid);
filterNetworkStateForUid(state, uid, false);
maybeLogBlockedNetworkInfo(state.networkInfo, uid);
@@ -1419,7 +1415,7 @@
@Override
public Network getActiveNetwork() {
enforceAccessPermission();
- return getActiveNetworkForUidInternal(Binder.getCallingUid(), false);
+ return getActiveNetworkForUidInternal(mDeps.getCallingUid(), false);
}
@Override
@@ -1459,7 +1455,7 @@
// Public because it's used by mLockdownTracker.
public NetworkInfo getActiveNetworkInfoUnfiltered() {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
NetworkState state = getUnfilteredActiveNetworkState(uid);
return state.networkInfo;
}
@@ -1475,7 +1471,7 @@
@Override
public NetworkInfo getNetworkInfo(int networkType) {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
if (getVpnUnderlyingNetworks(uid) != null) {
// A VPN is active, so we may need to return one of its underlying networks. This
// information is not available in LegacyTypeTracker, so we have to get it from
@@ -1520,7 +1516,7 @@
@Override
public Network getNetworkForType(int networkType) {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
NetworkState state = getFilteredNetworkState(networkType, uid);
if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) {
return state.network;
@@ -1567,7 +1563,7 @@
result.put(
nai.network,
maybeSanitizeLocationInfoForCaller(
- nc, Binder.getCallingUid(), callingPackageName));
+ nc, mDeps.getCallingUid(), callingPackageName));
}
synchronized (mVpns) {
@@ -1582,7 +1578,7 @@
result.put(
network,
maybeSanitizeLocationInfoForCaller(
- nc, Binder.getCallingUid(), callingPackageName));
+ nc, mDeps.getCallingUid(), callingPackageName));
}
}
}
@@ -1612,7 +1608,7 @@
@Override
public LinkProperties getActiveLinkProperties() {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
NetworkState state = getUnfilteredActiveNetworkState(uid);
if (state.linkProperties == null) return null;
return linkPropertiesRestrictedForCallerPermissions(state.linkProperties,
@@ -1626,7 +1622,7 @@
final LinkProperties lp = getLinkProperties(nai);
if (lp == null) return null;
return linkPropertiesRestrictedForCallerPermissions(
- lp, Binder.getCallingPid(), Binder.getCallingUid());
+ lp, Binder.getCallingPid(), mDeps.getCallingUid());
}
// TODO - this should be ALL networks
@@ -1636,7 +1632,7 @@
final LinkProperties lp = getLinkProperties(getNetworkAgentInfoForNetwork(network));
if (lp == null) return null;
return linkPropertiesRestrictedForCallerPermissions(
- lp, Binder.getCallingPid(), Binder.getCallingUid());
+ lp, Binder.getCallingPid(), mDeps.getCallingUid());
}
@Nullable
@@ -1658,17 +1654,17 @@
synchronized (nai) {
if (nai.networkCapabilities == null) return null;
return networkCapabilitiesRestrictedForCallerPermissions(
- nai.networkCapabilities, Binder.getCallingPid(), Binder.getCallingUid());
+ nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid());
}
}
@Override
public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName) {
- mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName);
+ mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
enforceAccessPermission();
return maybeSanitizeLocationInfoForCaller(
getNetworkCapabilitiesInternal(network),
- Binder.getCallingUid(), callingPackageName);
+ mDeps.getCallingUid(), callingPackageName);
}
@VisibleForTesting
@@ -1706,16 +1702,17 @@
return newNc;
}
- Binder.withCleanCallingIdentity(
- () -> {
- if (!mLocationPermissionChecker.checkLocationPermission(
- callerPkgName, null /* featureId */, callerUid, null /* message */)) {
- // Caller does not have the requisite location permissions. Reset the
- // owner's UID in the NetworkCapabilities.
- newNc.setOwnerUid(INVALID_UID);
- }
- }
- );
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mLocationPermissionChecker.checkLocationPermission(
+ callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+ // Caller does not have the requisite location permissions. Reset the
+ // owner's UID in the NetworkCapabilities.
+ newNc.setOwnerUid(INVALID_UID);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
return newNc;
}
@@ -1756,7 +1753,7 @@
}
private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
- if (!mPermissionMonitor.hasUseBackgroundNetworksPermission(Binder.getCallingUid())) {
+ if (!mPermissionMonitor.hasUseBackgroundNetworksPermission(mDeps.getCallingUid())) {
nc.addCapability(NET_CAPABILITY_FOREGROUND);
}
}
@@ -1781,14 +1778,6 @@
}
@Override
- @Deprecated
- public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
- Log.w(TAG, "Shame on UID " + Binder.getCallingUid()
- + " for calling the hidden API getNetworkQuotaInfo(). Shame!");
- return new NetworkQuotaInfo();
- }
-
- @Override
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
@@ -1803,9 +1792,9 @@
private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
@Override
- public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
- int deviceType = Integer.parseInt(label);
- sendDataActivityBroadcast(deviceType, active, tsNanos);
+ public void interfaceClassDataActivityChanged(int networkType, boolean active, long tsNanos,
+ int uid) {
+ sendDataActivityBroadcast(networkType, active, tsNanos);
}
};
@@ -1817,7 +1806,7 @@
// requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost
// for devices launched with Q and above. However, existing devices upgrading to Q and
// above must continued to be supported for few more releases.
- if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt(
+ if (isSystem(mDeps.getCallingUid()) && SystemProperties.getInt(
"ro.product.first_api_level", 0) > Build.VERSION_CODES.P) {
log("This method exists only for app backwards compatibility"
+ " and must not be called by system services.");
@@ -1883,7 +1872,7 @@
return false;
}
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
LinkProperties lp;
@@ -2303,7 +2292,7 @@
*/
@Override
public void systemReady() {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Calling Uid is not system uid.");
}
systemReadyInternal();
@@ -2314,10 +2303,13 @@
*/
@VisibleForTesting
public void systemReadyInternal() {
- // Let PermissionMonitor#startMonitoring() running in the beginning of the systemReady
- // before MultipathPolicyTracker.start(). Since mApps in PermissionMonitor needs to be
- // populated first to ensure that listening network request which is sent by
- // MultipathPolicyTracker won't be added NET_CAPABILITY_FOREGROUND capability.
+ // Since mApps in PermissionMonitor needs to be populated first to ensure that
+ // listening network request which is sent by MultipathPolicyTracker won't be added
+ // NET_CAPABILITY_FOREGROUND capability. Thus, MultipathPolicyTracker.start() must
+ // be called after PermissionMonitor#startMonitoring().
+ // Calling PermissionMonitor#startMonitoring() in systemReadyInternal() and the
+ // MultipathPolicyTracker.start() is called in NetworkPolicyManagerService#systemReady()
+ // to ensure the tracking will be initialized correctly.
mPermissionMonitor.startMonitoring();
mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
@@ -2336,8 +2328,31 @@
// Create network requests for always-on networks.
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
+ }
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
+ /**
+ * Start listening for default data network activity state changes.
+ */
+ @Override
+ public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
+ // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+ }
+
+ /**
+ * Stop listening for default data network activity state changes.
+ */
+ @Override
+ public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
+ // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+ }
+
+ /**
+ * Check whether the default network radio is currently active.
+ */
+ @Override
+ public boolean isDefaultNetworkActive() {
+ // TODO: Replace isNetworkActive() in NMS.
+ return false;
}
/**
@@ -2529,7 +2544,7 @@
if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump " + tag + " from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + Binder.getCallingPid() + ", uid=" + mDeps.getCallingUid()
+ " due to missing android.permission.DUMP permission");
return false;
} else {
@@ -2612,7 +2627,6 @@
dumpAvoidBadWifiSettings(pw);
pw.println();
- mMultipathPolicyTracker.dump(pw);
if (ArrayUtils.contains(args, SHORT_ARG) == false) {
pw.println();
@@ -2710,7 +2724,7 @@
* Return an array of all current NetworkRequest sorted by request id.
*/
@VisibleForTesting
- protected NetworkRequestInfo[] requestsSortedById() {
+ NetworkRequestInfo[] requestsSortedById() {
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
requests = mNetworkRequests.values().toArray(requests);
// Sort the array based off the NRI containing the min requestId in its requests.
@@ -3560,30 +3574,58 @@
return false;
}
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
+ if (reason == UnneededFor.LINGER
+ && !nri.isMultilayerRequest()
+ && nri.mRequests.get(0).isBackgroundRequest()) {
// Background requests don't affect lingering.
continue;
}
- // If this Network is already the highest scoring Network for a request, or if
- // there is hope for it to become one if it validated, then it is needed.
- if (nri.request.isRequest() && nai.satisfies(nri.request) &&
- (nai.isSatisfyingRequest(nri.request.requestId) ||
- // Note that this catches two important cases:
- // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
- // is currently satisfying the request. This is desirable when
- // cellular ends up validating but WiFi does not.
- // 2. Unvalidated WiFi will not be reaped when validated cellular
- // is currently satisfying the request. This is desirable when
- // WiFi ends up validating and out scoring cellular.
- nri.mSatisfier.getCurrentScore()
- < nai.getCurrentScoreAsValidated())) {
+ if (isNetworkPotentialSatisfier(nai, nri)) {
return false;
}
}
return true;
}
+ private boolean isNetworkPotentialSatisfier(
+ @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) {
+ // listen requests won't keep up a network satisfying it. If this is not a multilayer
+ // request, we can return immediately. For multilayer requests, we have to check to see if
+ // any of the multilayer requests may have a potential satisfier.
+ if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
+ return false;
+ }
+ for (final NetworkRequest req : nri.mRequests) {
+ // As non-multilayer listen requests have already returned, the below would only happen
+ // for a multilayer request therefore continue to the next request if available.
+ if (req.isListen()) {
+ continue;
+ }
+ // If this Network is already the highest scoring Network for a request, or if
+ // there is hope for it to become one if it validated, then it is needed.
+ if (candidate.satisfies(req)) {
+ // As soon as a network is found that satisfies a request, return. Specifically for
+ // multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request
+ // is important so as to not evaluate lower priority requests further in
+ // nri.mRequests.
+ final boolean isNetworkNeeded = candidate.isSatisfyingRequest(req.requestId)
+ // Note that this catches two important cases:
+ // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
+ // is currently satisfying the request. This is desirable when
+ // cellular ends up validating but WiFi does not.
+ // 2. Unvalidated WiFi will not be reaped when validated cellular
+ // is currently satisfying the request. This is desirable when
+ // WiFi ends up validating and out scoring cellular.
+ || nri.mSatisfier.getCurrentScore()
+ < candidate.getCurrentScoreAsValidated();
+ return isNetworkNeeded;
+ }
+ }
+
+ return false;
+ }
+
private NetworkRequestInfo getNriForAppRequest(
NetworkRequest request, int callingUid, String requestedOperation) {
final NetworkRequestInfo nri = mNetworkRequests.get(request);
@@ -3880,8 +3922,12 @@
new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
- Binder.withCleanCallingIdentity(() ->
- mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(appIntent, UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private class CaptivePortalImpl extends ICaptivePortal.Stub {
@@ -3909,7 +3955,7 @@
if (request == CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED) {
checkNetworkStackPermission();
- nm.forceReevaluation(Binder.getCallingUid());
+ nm.forceReevaluation(mDeps.getCallingUid());
}
}
@@ -4128,11 +4174,13 @@
return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
}
- Integer networkPreference = mMultipathPolicyTracker.getMultipathPreference(network);
- if (networkPreference != null) {
+ final NetworkPolicyManager netPolicyManager =
+ mContext.getSystemService(NetworkPolicyManager.class);
+
+ final int networkPreference = netPolicyManager.getMultipathPreference(network);
+ if (networkPreference != 0) {
return networkPreference;
}
-
return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
}
@@ -4236,10 +4284,6 @@
mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
break;
}
- case EVENT_SYSTEM_READY: {
- mMultipathPolicyTracker.start();
- break;
- }
case EVENT_REVALIDATE_NETWORK: {
handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
break;
@@ -4376,7 +4420,7 @@
public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
enforceAccessPermission();
enforceInternetPermission();
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
final int connectivityInfo = encodeBool(hasConnectivity);
// Handle ConnectivityDiagnostics event before attempting to revalidate the network. This
@@ -4446,13 +4490,13 @@
if (globalProxy != null) return globalProxy;
if (network == null) {
// Get the network associated with the calling UID.
- final Network activeNetwork = getActiveNetworkForUidInternal(Binder.getCallingUid(),
+ final Network activeNetwork = getActiveNetworkForUidInternal(mDeps.getCallingUid(),
true);
if (activeNetwork == null) {
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.getNetId())) {
+ } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network.getNetId())) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -4621,7 +4665,7 @@
*/
@Override
public ParcelFileDescriptor establishVpn(VpnConfig config) {
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
throwIfLockdownEnabled();
return mVpns.get(user).establish(config);
@@ -4642,7 +4686,7 @@
*/
@Override
public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
- final int user = UserHandle.getUserId(Binder.getCallingUid());
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
}
@@ -4660,7 +4704,7 @@
*/
@Override
public void deleteVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(Binder.getCallingUid());
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
}
@@ -4677,7 +4721,7 @@
*/
@Override
public void startVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(Binder.getCallingUid());
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
throwIfLockdownEnabled();
mVpns.get(user).startVpnProfile(packageName, mKeyStore);
@@ -4694,7 +4738,7 @@
*/
@Override
public void stopVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(Binder.getCallingUid());
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
mVpns.get(user).stopVpnProfile(packageName);
}
@@ -4706,7 +4750,7 @@
*/
@Override
public void startLegacyVpn(VpnProfile profile) {
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
final LinkProperties egress = getActiveLinkProperties();
if (egress == null) {
throw new IllegalStateException("Missing active network connection");
@@ -4855,7 +4899,7 @@
@Override
public boolean updateLockdownVpn() {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
logw("Lockdown VPN only available to AID_SYSTEM");
return false;
}
@@ -4877,7 +4921,7 @@
setLockdownTracker(null);
return true;
}
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
Vpn vpn = mVpns.get(user);
if (vpn == null) {
logw("VPN for user " + user + " not ready yet. Skipping lockdown");
@@ -5442,7 +5486,7 @@
messenger = null;
mBinder = null;
mPid = getCallingPid();
- mUid = getCallingUid();
+ mUid = mDeps.getCallingUid();
enforceRequestCountLimit();
}
@@ -5454,7 +5498,7 @@
ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder;
mPid = getCallingPid();
- mUid = getCallingUid();
+ mUid = mDeps.getCallingUid();
mPendingIntent = null;
enforceRequestCountLimit();
@@ -5469,6 +5513,10 @@
this(r, null);
}
+ boolean isMultilayerRequest() {
+ return mRequests.size() > 1;
+ }
+
private List<NetworkRequest> initializeRequests(NetworkRequest r) {
final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
tempRequests.add(new NetworkRequest(r));
@@ -5510,7 +5558,7 @@
public void binderDied() {
log("ConnectivityService NetworkRequestInfo binderDied(" +
mRequests + ", " + mBinder + ")");
- releaseNetworkRequest(mRequests);
+ releaseNetworkRequests(mRequests);
}
@Override
@@ -5543,13 +5591,15 @@
mAppOpsManager.checkPackage(callerUid, callerPackageName);
}
- private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
+ private ArrayList<Integer> getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
final SortedSet<Integer> thresholds = new TreeSet<>();
synchronized (nai) {
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.request.networkCapabilities.hasSignalStrength() &&
- nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
- thresholds.add(nri.request.networkCapabilities.getSignalStrength());
+ for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
+ for (final NetworkRequest req : nri.mRequests) {
+ if (req.networkCapabilities.hasSignalStrength()
+ && nai.satisfiesImmutableCapabilitiesOf(req)) {
+ thresholds.add(req.networkCapabilities.getSignalStrength());
+ }
}
}
}
@@ -5597,7 +5647,7 @@
}
private boolean checkUnsupportedStartingFrom(int version, String callingPackageName) {
- final UserHandle user = UserHandle.getUserHandleForUid(Binder.getCallingUid());
+ final UserHandle user = UserHandle.getUserHandleForUid(mDeps.getCallingUid());
final PackageManager pm =
mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
try {
@@ -5617,7 +5667,7 @@
throw new SecurityException("Insufficient permissions to specify legacy type");
}
}
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mDeps.getCallingUid();
final NetworkRequest.Type type = (networkCapabilities == null)
? NetworkRequest.Type.TRACK_DEFAULT
: NetworkRequest.Type.REQUEST;
@@ -5687,7 +5737,7 @@
if (nai != null) {
nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
synchronized (mBandwidthRequests) {
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
Integer uidReqs = mBandwidthRequests.get(uid);
if (uidReqs == null) {
uidReqs = 0;
@@ -5704,7 +5754,7 @@
}
private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
if (isSystem(uid)) {
// Exemption for system uid.
return;
@@ -5724,7 +5774,7 @@
PendingIntent operation, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mDeps.getCallingUid();
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
callingAttributionTag);
@@ -5783,7 +5833,7 @@
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, IBinder binder, @NonNull String callingPackageName) {
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
@@ -5813,7 +5863,7 @@
public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
PendingIntent operation, @NonNull String callingPackageName) {
Objects.requireNonNull(operation, "PendingIntent cannot be null.");
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mDeps.getCallingUid();
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
@@ -5836,7 +5886,7 @@
return mNextNetworkProviderId.getAndIncrement();
}
- private void releaseNetworkRequest(List<NetworkRequest> networkRequests) {
+ private void releaseNetworkRequests(List<NetworkRequest> networkRequests) {
for (int i = 0; i < networkRequests.size(); i++) {
releaseNetworkRequest(networkRequests.get(i));
}
@@ -5914,7 +5964,7 @@
} else {
enforceNetworkFactoryPermission();
}
- mHandler.post(() -> handleReleaseNetworkRequest(request, Binder.getCallingUid(), true));
+ mHandler.post(() -> handleReleaseNetworkRequest(request, mDeps.getCallingUid(), true));
}
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@@ -6008,7 +6058,7 @@
enforceNetworkFactoryPermission();
}
- final int uid = Binder.getCallingUid();
+ final int uid = mDeps.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
return registerNetworkAgentInternal(messenger, networkInfo, linkProperties,
@@ -7662,7 +7712,7 @@
@Override
public boolean addVpnAddress(String address, int prefixLength) {
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
throwIfLockdownEnabled();
return mVpns.get(user).addAddress(address, prefixLength);
@@ -7671,7 +7721,7 @@
@Override
public boolean removeVpnAddress(String address, int prefixLength) {
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
synchronized (mVpns) {
throwIfLockdownEnabled();
return mVpns.get(user).removeAddress(address, prefixLength);
@@ -7680,7 +7730,7 @@
@Override
public boolean setUnderlyingNetworksForVpn(Network[] networks) {
- int user = UserHandle.getUserId(Binder.getCallingUid());
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
final boolean success;
synchronized (mVpns) {
throwIfLockdownEnabled();
@@ -7768,10 +7818,13 @@
final int userId = UserHandle.getCallingUserId();
- Binder.withCleanCallingIdentity(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
ipMemoryStore.factoryReset();
- });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
// Turn airplane mode off
setAirplaneMode(false);
@@ -7907,7 +7960,7 @@
@GuardedBy("mVpns")
private Vpn getVpnIfOwner() {
- return getVpnIfOwner(Binder.getCallingUid());
+ return getVpnIfOwner(mDeps.getCallingUid());
}
@GuardedBy("mVpns")
@@ -8385,7 +8438,7 @@
throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
+ " Please use NetworkCapabilities instead.");
}
- final int callingUid = Binder.getCallingUid();
+ final int callingUid = mDeps.getCallingUid();
mAppOpsManager.checkPackage(callingUid, callingPackageName);
// This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
@@ -8420,7 +8473,7 @@
mConnectivityDiagnosticsHandler.obtainMessage(
ConnectivityDiagnosticsHandler
.EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
- Binder.getCallingUid(),
+ mDeps.getCallingUid(),
0,
callback));
}
@@ -8436,7 +8489,7 @@
}
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null || nai.creatorUid != Binder.getCallingUid()) {
+ if (nai == null || nai.creatorUid != mDeps.getCallingUid()) {
throw new SecurityException("Data Stall simulation is only possible for network "
+ "creators");
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 655d8ab..e8687e5 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -107,23 +107,23 @@
String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
- return Binder.withCleanCallingIdentity(
- () -> {
- try {
- ParcelFileDescriptor tunIntf =
- ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
- for (LinkAddress addr : linkAddrs) {
- mNetd.interfaceAddAddress(
- iface,
- addr.getAddress().getHostAddress(),
- addr.getPrefixLength());
- }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ ParcelFileDescriptor tunIntf =
+ ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
+ for (LinkAddress addr : linkAddrs) {
+ mNetd.interfaceAddAddress(
+ iface,
+ addr.getAddress().getHostAddress(),
+ addr.getPrefixLength());
+ }
- return new TestNetworkInterface(tunIntf, iface);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- });
+ return new TestNetworkInterface(tunIntf, iface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -317,7 +317,12 @@
try {
// This requires NETWORK_STACK privileges.
- Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mNMS.setInterfaceUp(iface);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
// Synchronize all accesses to mTestNetworkTracker to prevent the case where:
// 1. TestNetworkAgent successfully binds to death of binder
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 7795ed3..3d71b0a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -334,7 +334,13 @@
*/
public void setProvNotificationVisible(boolean visible, int id, String action) {
if (visible) {
- Intent intent = new Intent(action);
+ // For legacy purposes, action is sent as the action + the phone ID from DcTracker.
+ // Split the string here and send the phone ID as an extra instead.
+ String[] splitAction = action.split(":");
+ Intent intent = new Intent(splitAction[0]);
+ try {
+ intent.putExtra("provision.phone.id", Integer.parseInt(splitAction[1]));
+ } catch (NumberFormatException ignored) { }
PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
showNotification(id, NotificationType.SIGN_IN, null, null, pendingIntent, false);
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 5cb3d94..f6ca152 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -38,7 +38,9 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.net.module.util.ProxyUtils;
+import java.util.Collections;
import java.util.Objects;
/**
@@ -163,9 +165,10 @@
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyInfo(Uri.parse(pacFileUrl));
+ proxyProperties = ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
} else {
- proxyProperties = new ProxyInfo(host, port, exclList);
+ proxyProperties = ProxyInfo.buildDirectProxy(host, port,
+ ProxyUtils.exclusionStringAsList(exclList));
}
if (!proxyProperties.isValid()) {
if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
@@ -204,7 +207,8 @@
return false;
}
}
- final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
+ final ProxyInfo p = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
+ Collections.emptyList());
setGlobalProxy(p);
return true;
}
@@ -219,7 +223,8 @@
*/
public void sendProxyBroadcast() {
final ProxyInfo defaultProxy = getDefaultProxy();
- final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
+ final ProxyInfo proxyInfo = null != defaultProxy ?
+ defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
return;
}
@@ -261,7 +266,7 @@
mGlobalProxy = new ProxyInfo(proxyInfo);
host = mGlobalProxy.getHost();
port = mGlobalProxy.getPort();
- exclList = mGlobalProxy.getExclusionListAsString();
+ exclList = ProxyUtils.exclusionListAsString(mGlobalProxy.getExclusionList());
pacFileUrl = Uri.EMPTY.equals(proxyInfo.getPacFileUrl())
? "" : proxyInfo.getPacFileUrl().toString();
} else {
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index 1129899..b5f20d7 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -36,6 +36,7 @@
import android.net.TcpKeepalivePacketData;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.TcpRepairWindow;
+import android.net.util.KeepalivePacketDataUtil;
import android.os.Handler;
import android.os.MessageQueue;
import android.os.Messenger;
@@ -112,7 +113,7 @@
throws InvalidPacketException, InvalidSocketException {
try {
final TcpKeepalivePacketDataParcelable tcpDetails = switchToRepairMode(fd);
- return TcpKeepalivePacketData.tcpKeepalivePacket(tcpDetails);
+ return KeepalivePacketDataUtil.fromStableParcelable(tcpDetails);
} catch (InvalidPacketException | InvalidSocketException e) {
switchOutOfRepairMode(fd);
throw e;
@@ -122,7 +123,7 @@
* Switch the tcp socket to repair mode and query detail tcp information.
*
* @param fd the fd of socket on which to use keepalive offload.
- * @return a {@link TcpKeepalivePacketData#TcpKeepalivePacketDataParcelable} object for current
+ * @return a {@link TcpKeepalivePacketDataParcelable} object for current
* tcp/ip information.
*/
private static TcpKeepalivePacketDataParcelable switchToRepairMode(FileDescriptor fd)
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index 77e9f12..bcc9072 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -29,6 +29,7 @@
import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.isDevSdkInRange
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -173,10 +174,12 @@
@Test
fun testDeclareNetworkRequestUnfulfillable() {
val mockContext = mock(Context::class.java)
- val provider = createNetworkProvider(mockContext)
- // ConnectivityManager not required at creation time
- verifyNoMoreInteractions(mockContext)
doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+ val provider = createNetworkProvider(mockContext)
+ // ConnectivityManager not required at creation time after R
+ if (!isDevSdkInRange(0, Build.VERSION_CODES.R)) {
+ verifyNoMoreInteractions(mockContext)
+ }
mCm.registerNetworkProvider(provider)
diff --git a/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt b/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt
new file mode 100644
index 0000000..6770066
--- /dev/null
+++ b/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 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.net.InetAddresses.parseNumericAddress
+import android.os.Build
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertFieldCountEquals
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.net.InetAddress
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+import kotlin.test.assertTrue
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) // TcpKeepalivePacketData added to SDK in S
+class TcpKeepalivePacketDataTest {
+ private fun makeData(
+ srcAddress: InetAddress = parseNumericAddress("192.0.2.123"),
+ srcPort: Int = 1234,
+ dstAddress: InetAddress = parseNumericAddress("192.0.2.231"),
+ dstPort: Int = 4321,
+ data: ByteArray = byteArrayOf(1, 2, 3),
+ tcpSeq: Int = 135,
+ tcpAck: Int = 246,
+ tcpWnd: Int = 1234,
+ tcpWndScale: Int = 2,
+ ipTos: Int = 0x12,
+ ipTtl: Int = 10
+ ) = TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data, tcpSeq, tcpAck,
+ tcpWnd, tcpWndScale, ipTos, ipTtl)
+
+ @Test
+ fun testEquals() {
+ val data1 = makeData()
+ val data2 = makeData()
+ assertEquals(data1, data2)
+ assertEquals(data1.hashCode(), data2.hashCode())
+ }
+
+ @Test
+ fun testNotEquals() {
+ assertNotEquals(makeData(srcAddress = parseNumericAddress("192.0.2.124")), makeData())
+ assertNotEquals(makeData(srcPort = 1235), makeData())
+ assertNotEquals(makeData(dstAddress = parseNumericAddress("192.0.2.232")), makeData())
+ assertNotEquals(makeData(dstPort = 4322), makeData())
+ // .equals does not test .packet, as it should be generated from the other fields
+ assertNotEquals(makeData(tcpSeq = 136), makeData())
+ assertNotEquals(makeData(tcpAck = 247), makeData())
+ assertNotEquals(makeData(tcpWnd = 1235), makeData())
+ assertNotEquals(makeData(tcpWndScale = 3), makeData())
+ assertNotEquals(makeData(ipTos = 0x14), makeData())
+ assertNotEquals(makeData(ipTtl = 11), makeData())
+
+ // Update above assertions if field is added
+ assertFieldCountEquals(5, KeepalivePacketData::class.java)
+ assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
+ }
+
+ @Test
+ fun testParcelUnparcel() {
+ assertParcelSane(makeData(), fieldCount = 6) { a, b ->
+ // .equals() does not verify .packet
+ a == b && a.packet contentEquals b.packet
+ }
+ }
+
+ @Test
+ fun testToString() {
+ val data = makeData()
+ val str = data.toString()
+
+ assertTrue(str.contains(data.srcAddress.hostAddress))
+ assertTrue(str.contains(data.srcPort.toString()))
+ assertTrue(str.contains(data.dstAddress.hostAddress))
+ assertTrue(str.contains(data.dstPort.toString()))
+ // .packet not included in toString()
+ assertTrue(str.contains(data.tcpSeq.toString()))
+ assertTrue(str.contains(data.tcpAck.toString()))
+ assertTrue(str.contains(data.tcpWindow.toString()))
+ assertTrue(str.contains(data.tcpWindowScale.toString()))
+ assertTrue(str.contains(data.ipTos.toString()))
+ assertTrue(str.contains(data.ipTtl.toString()))
+
+ // Update above assertions if field is added
+ assertFieldCountEquals(5, KeepalivePacketData::class.java)
+ assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
+ }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
index ada5494..076e41d 100644
--- a/tests/net/java/android/net/Ikev2VpnProfileTest.java
+++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java
@@ -29,6 +29,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.net.VpnProfile;
+import com.android.net.module.util.ProxyUtils;
import com.android.org.bouncycastle.x509.X509V1CertificateGenerator;
import org.junit.Before;
@@ -67,7 +68,8 @@
return "fooPackage";
}
};
- private final ProxyInfo mProxy = new ProxyInfo(SERVER_ADDR_STRING, -1, EXCL_LIST);
+ private final ProxyInfo mProxy = ProxyInfo.buildDirectProxy(
+ SERVER_ADDR_STRING, -1, ProxyUtils.exclusionStringAsList(EXCL_LIST));
private X509Certificate mUserCert;
private X509Certificate mServerRootCa;
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/KeepalivePacketDataUtilTest.java
similarity index 65%
rename from tests/net/java/android/net/TcpKeepalivePacketDataTest.java
rename to tests/net/java/android/net/KeepalivePacketDataUtilTest.java
index c5b25bd..fc739fb 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/KeepalivePacketDataUtilTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -20,8 +20,11 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.net.util.KeepalivePacketDataUtil;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,7 +34,7 @@
import java.nio.ByteBuffer;
@RunWith(JUnit4.class)
-public final class TcpKeepalivePacketDataTest {
+public final class KeepalivePacketDataUtilTest {
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
@@ -39,7 +42,7 @@
public void setUp() {}
@Test
- public void testV4TcpKeepalivePacket() throws Exception {
+ public void testFromTcpKeepaliveStableParcelable() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int seq = 0x11111111;
@@ -61,7 +64,7 @@
testInfo.tos = tos;
testInfo.ttl = ttl;
try {
- resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
+ resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
} catch (InvalidPacketException e) {
fail("InvalidPacketException: " + e);
}
@@ -72,8 +75,8 @@
assertEquals(testInfo.dstPort, resultData.getDstPort());
assertEquals(testInfo.seq, resultData.tcpSeq);
assertEquals(testInfo.ack, resultData.tcpAck);
- assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
- assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
+ assertEquals(testInfo.rcvWnd, resultData.tcpWindow);
+ assertEquals(testInfo.rcvWndScale, resultData.tcpWindowScale);
assertEquals(testInfo.tos, resultData.ipTos);
assertEquals(testInfo.ttl, resultData.ipTtl);
@@ -113,7 +116,7 @@
//TODO: add ipv6 test when ipv6 supported
@Test
- public void testParcel() throws Exception {
+ public void testToTcpKeepaliveStableParcelable() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int sequence = 0x11111111;
@@ -135,8 +138,8 @@
testInfo.ttl = ttl;
TcpKeepalivePacketData testData = null;
TcpKeepalivePacketDataParcelable resultData = null;
- testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
- resultData = testData.toStableParcelable();
+ testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
+ resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
assertEquals(resultData.srcPort, srcPort);
@@ -154,4 +157,49 @@
+ " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
assertEquals(expected, resultData.toString());
}
+
+ @Test
+ public void testParseTcpKeepalivePacketData() throws Exception {
+ final int srcPort = 1234;
+ final int dstPort = 4321;
+ final int sequence = 0x11111111;
+ final int ack = 0x22222222;
+ final int wnd = 4800;
+ final int wndScale = 2;
+ final int tos = 4;
+ final int ttl = 64;
+ final TcpKeepalivePacketDataParcelable testParcel = new TcpKeepalivePacketDataParcelable();
+ testParcel.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
+ testParcel.srcPort = srcPort;
+ testParcel.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
+ testParcel.dstPort = dstPort;
+ testParcel.seq = sequence;
+ testParcel.ack = ack;
+ testParcel.rcvWnd = wnd;
+ testParcel.rcvWndScale = wndScale;
+ testParcel.tos = tos;
+ testParcel.ttl = ttl;
+
+ final KeepalivePacketData testData =
+ KeepalivePacketDataUtil.fromStableParcelable(testParcel);
+ final TcpKeepalivePacketDataParcelable parsedParcelable =
+ KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
+ final TcpKeepalivePacketData roundTripData =
+ KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
+
+ // Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
+ assertTrue(testData.getPacket().length > 0);
+ assertArrayEquals(testData.getPacket(), roundTripData.getPacket());
+
+ testParcel.rcvWndScale = 0;
+ final KeepalivePacketData noScaleTestData =
+ KeepalivePacketDataUtil.fromStableParcelable(testParcel);
+ final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
+ KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
+ final TcpKeepalivePacketData noScaleRoundTripData =
+ KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
+ assertEquals(noScaleTestData, noScaleRoundTripData);
+ assertTrue(noScaleTestData.getPacket().length > 0);
+ assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
+ }
}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 91c9a2a..6de31f6 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -22,11 +22,11 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.util.MacAddressUtils;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 3158cc8..7748288 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,24 +16,10 @@
package android.net;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.EPERM;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
import androidx.test.runner.AndroidJUnit4;
-import libcore.io.IoUtils;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -139,50 +125,4 @@
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
-
- private static void expectSocketSuccess(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- } catch (ErrnoException e) {
- fail(msg + e.getMessage());
- }
- }
-
- private static void expectSocketPemissionError(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- fail(msg);
- } catch (ErrnoException e) {
- assertEquals(msg, e.errno, EPERM);
- }
- }
-
- private static void expectHasNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
- AF_INET, SOCK_DGRAM);
- expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
- AF_INET6, SOCK_DGRAM);
- }
-
- private static void expectNoNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketPemissionError(
- "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
- AF_INET, SOCK_DGRAM);
- expectSocketPemissionError(
- "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
- AF_INET6, SOCK_DGRAM);
- }
-
- @Test
- public void testSetAllowNetworkingForProcess() {
- expectHasNetworking();
- NetworkUtils.setAllowNetworkingForProcess(false);
- expectNoNetworking();
- NetworkUtils.setAllowNetworkingForProcess(true);
- expectHasNetworking();
- }
}
diff --git a/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java b/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
new file mode 100644
index 0000000..3cfecd5
--- /dev/null
+++ b/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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.internal.net;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.EPERM;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.fail;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import libcore.io.IoUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class NetworkUtilsInternalTest {
+
+ private static void expectSocketSuccess(String msg, int domain, int type) {
+ try {
+ IoUtils.closeQuietly(Os.socket(domain, type, 0));
+ } catch (ErrnoException e) {
+ fail(msg + e.getMessage());
+ }
+ }
+
+ private static void expectSocketPemissionError(String msg, int domain, int type) {
+ try {
+ IoUtils.closeQuietly(Os.socket(domain, type, 0));
+ fail(msg);
+ } catch (ErrnoException e) {
+ assertEquals(msg, e.errno, EPERM);
+ }
+ }
+
+ private static void expectHasNetworking() {
+ expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+ AF_UNIX, SOCK_STREAM);
+ expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
+ AF_INET, SOCK_DGRAM);
+ expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
+ AF_INET6, SOCK_DGRAM);
+ }
+
+ private static void expectNoNetworking() {
+ expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+ AF_UNIX, SOCK_STREAM);
+ expectSocketPemissionError(
+ "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
+ AF_INET, SOCK_DGRAM);
+ expectSocketPemissionError(
+ "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
+ AF_INET6, SOCK_DGRAM);
+ }
+
+ @Test
+ public void testSetAllowNetworkingForProcess() {
+ expectHasNetworking();
+ NetworkUtilsInternal.setAllowNetworkingForProcess(false);
+ expectNoNetworking();
+ NetworkUtilsInternal.setAllowNetworkingForProcess(true);
+ expectHasNetworking();
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8c403f1..a613e5e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -39,6 +39,7 @@
import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
+import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
@@ -101,6 +102,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
@@ -132,6 +135,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
@@ -140,6 +144,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.location.LocationManager;
@@ -176,6 +182,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
@@ -332,12 +339,13 @@
private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
private static final String VPN_IFNAME = "tun10042";
private static final String TEST_PACKAGE_NAME = "com.android.test.package";
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn";
private static final String INTERFACE_NAME = "interface";
private MockContext mServiceContext;
private HandlerThread mCsHandlerThread;
+ private ConnectivityService.Dependencies mDeps;
private ConnectivityService mService;
private WrappedConnectivityManager mCm;
private TestNetworkAgentWrapper mWiFiNetworkAgent;
@@ -353,6 +361,7 @@
@Mock IIpConnectivityMetrics mIpConnectivityMetrics;
@Mock IpConnectivityMetrics.Logger mMetricsService;
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
+ @Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
@Mock IBatteryStats mBatteryStatsService;
@@ -450,6 +459,15 @@
}
@Override
+ public ComponentName startService(Intent service) {
+ final String action = service.getAction();
+ if (!VpnConfig.SERVICE_INTERFACE.equals(action)) {
+ fail("Attempt to start unknown service, action=" + action);
+ }
+ return new ComponentName(service.getPackage(), "com.android.test.Service");
+ }
+
+ @Override
public Object getSystemService(String name) {
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
@@ -1055,9 +1073,19 @@
private VpnInfo mVpnInfo;
public MockVpn(int userId) {
- super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
- mMockNetd, userId, mock(KeyStore.class));
- mConfig = new VpnConfig();
+ super(startHandlerThreadAndReturnLooper(), mServiceContext,
+ new Dependencies() {
+ @Override
+ public boolean isCallerSystem() {
+ return true;
+ }
+
+ @Override
+ public DeviceIdleInternal getDeviceIdleInternal() {
+ return mDeviceIdleInternal;
+ }
+ },
+ mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class));
}
public void setUids(Set<UidRange> uids) {
@@ -1086,9 +1114,16 @@
return mVpnType;
}
+ private LinkProperties makeLinkProperties() {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(VPN_IFNAME);
+ return lp;
+ }
+
private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
throws Exception {
if (mAgentRegistered) throw new IllegalStateException("already registered");
+ mConfig = new VpnConfig();
setUids(uids);
if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
mInterface = VPN_IFNAME;
@@ -1101,12 +1136,13 @@
verify(mMockNetd, never())
.networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
mAgentRegistered = true;
+ updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
}
private void registerAgent(Set<UidRange> uids) throws Exception {
- registerAgent(false /* isAlwaysMetered */, uids, new LinkProperties());
+ registerAgent(false /* isAlwaysMetered */, uids, makeLinkProperties());
}
private void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
@@ -1142,12 +1178,12 @@
public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode)
throws Exception {
final int uid = Process.myUid();
- establish(new LinkProperties(), uid, uidRangesForUid(uid), validated, hasInternet,
+ establish(makeLinkProperties(), uid, uidRangesForUid(uid), validated, hasInternet,
isStrictMode);
}
public void establishForMyUid() throws Exception {
- establishForMyUid(new LinkProperties());
+ establishForMyUid(makeLinkProperties());
}
public void sendLinkProperties(LinkProperties lp) {
@@ -1155,7 +1191,10 @@
}
public void disconnect() {
- if (mMockNetworkAgent != null) mMockNetworkAgent.disconnect();
+ if (mMockNetworkAgent != null) {
+ mMockNetworkAgent.disconnect();
+ updateState(NetworkInfo.DetailedState.DISCONNECTED, "disconnect");
+ }
mAgentRegistered = false;
}
@@ -1229,6 +1268,17 @@
fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
}
+ private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
+ int uid) {
+ when(mDeps.getCallingUid()).thenReturn(uid);
+ try {
+ mCm.registerNetworkCallback(request, callback);
+ waitForIdle();
+ } finally {
+ returnRealCallingUid();
+ }
+ }
+
private static final int VPN_USER = 0;
private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
@@ -1271,7 +1321,8 @@
initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
mCsHandlerThread = new HandlerThread("TestConnectivityService");
- final ConnectivityService.Dependencies deps = makeDependencies();
+ mDeps = makeDependencies();
+ returnRealCallingUid();
mService = new ConnectivityService(mServiceContext,
mNetworkManagementService,
mStatsService,
@@ -1279,9 +1330,9 @@
mMockDnsResolver,
mock(IpConnectivityLog.class),
mMockNetd,
- deps);
+ mDeps);
mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
- verify(deps).makeMultinetworkPolicyTracker(any(), any(), any());
+ verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -1301,6 +1352,10 @@
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
}
+ private void returnRealCallingUid() {
+ doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
+ }
+
private ConnectivityService.Dependencies makeDependencies() {
doReturn(TEST_TCP_INIT_RWND).when(mSystemProperties)
.getInt("net.tcp.default_init_rwnd", 0);
@@ -1376,13 +1431,13 @@
}
private void mockDefaultPackages() throws Exception {
- final String testPackageName = mContext.getPackageName();
- final PackageInfo testPackageInfo = mContext.getPackageManager().getPackageInfo(
- testPackageName, PackageManager.GET_PERMISSIONS);
+ final String myPackageName = mContext.getPackageName();
+ final PackageInfo myPackageInfo = mContext.getPackageManager().getPackageInfo(
+ myPackageName, PackageManager.GET_PERMISSIONS);
when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn(
- new String[] {testPackageName});
- when(mPackageManager.getPackageInfoAsUser(eq(testPackageName), anyInt(),
- eq(UserHandle.getCallingUserId()))).thenReturn(testPackageInfo);
+ new String[] {myPackageName});
+ when(mPackageManager.getPackageInfoAsUser(eq(myPackageName), anyInt(),
+ eq(UserHandle.getCallingUserId()))).thenReturn(myPackageInfo);
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
@@ -1390,6 +1445,25 @@
buildPackageInfo(/* SYSTEM */ false, APP2_UID),
buildPackageInfo(/* SYSTEM */ false, VPN_UID)
}));
+
+ // Create a fake always-on VPN package.
+ final int userId = UserHandle.getCallingUserId();
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; // Always-on supported in N+.
+ when(mPackageManager.getApplicationInfoAsUser(eq(ALWAYS_ON_PACKAGE), anyInt(),
+ eq(userId))).thenReturn(applicationInfo);
+
+ // Minimal mocking to keep Vpn#isAlwaysOnPackageSupported happy.
+ ResolveInfo rInfo = new ResolveInfo();
+ rInfo.serviceInfo = new ServiceInfo();
+ rInfo.serviceInfo.metaData = new Bundle();
+ final List<ResolveInfo> services = Arrays.asList(new ResolveInfo[]{rInfo});
+ when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
+ eq(userId))).thenReturn(services);
+ when(mPackageManager.getPackageUidAsUser(TEST_PACKAGE_NAME, userId))
+ .thenReturn(Process.myUid());
+ when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, userId))
+ .thenReturn(VPN_UID);
}
private void verifyActiveNetwork(int transport) {
@@ -2252,10 +2326,10 @@
}
private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- final String testPackageName = mContext.getPackageName();
- when(mPackageManager.getPackageInfo(eq(testPackageName), eq(GET_PERMISSIONS)))
+ final String myPackageName = mContext.getPackageName();
+ when(mPackageManager.getPackageInfo(eq(myPackageName), eq(GET_PERMISSIONS)))
.thenReturn(buildPackageInfo(true, uid));
- mService.mPermissionMonitor.onPackageAdded(testPackageName, uid);
+ mService.mPermissionMonitor.onPackageAdded(myPackageName, uid);
}
@Test
@@ -4668,11 +4742,9 @@
@Test
public void testNetworkCallbackMaximum() {
- // We can only have 99 callbacks, because MultipathPolicyTracker is
- // already one of them.
- final int MAX_REQUESTS = 99;
+ final int MAX_REQUESTS = 100;
final int CALLBACKS = 89;
- final int INTENTS = 10;
+ final int INTENTS = 11;
assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
@@ -5831,10 +5903,21 @@
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
}
+ private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
+ final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
+ userId, "com.android.calling.package");
+ final String defaultCapsString = Arrays.toString(defaultCaps);
+ assertEquals(defaultCapsString, defaultCaps.length, networks.length);
+ final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
+ for (NetworkAgentWrapper network : networks) {
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
+ final String msg = "Did not find " + nc + " in " + Arrays.toString(defaultCaps);
+ assertTrue(msg, defaultCapsSet.contains(nc));
+ }
+ }
+
@Test
public void testVpnSetUnderlyingNetworks() throws Exception {
- final int uid = Process.myUid();
-
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -5857,6 +5940,9 @@
// A VPN without underlying networks is not suspended.
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ final int userId = UserHandle.getUserId(Process.myUid());
+ assertDefaultNetworkCapabilities(userId /* no networks */);
+
// Connect cell and use it as an underlying network.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
@@ -5870,6 +5956,7 @@
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -5884,6 +5971,7 @@
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Don't disconnect, but note the VPN is not using wifi any more.
mService.setUnderlyingNetworksForVpn(
@@ -5894,6 +5982,9 @@
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ // The return value of getDefaultNetworkCapabilitiesForUser always includes the default
+ // network (wifi) as well as the underlying networks (cell).
+ assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Remove NOT_SUSPENDED from the only network and observe VPN is now suspended.
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
@@ -5922,6 +6013,7 @@
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
// Use both again.
mService.setUnderlyingNetworksForVpn(
@@ -5932,6 +6024,7 @@
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Cell is suspended again. As WiFi is not, this should not cause a callback.
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
@@ -5949,6 +6042,7 @@
// a bug in ConnectivityService, but as the SUSPENDED and RESUMED callbacks have never
// been public and are deprecated and slated for removal, there is no sense in spending
// resources fixing this bug now.
+ assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Use both again.
mService.setUnderlyingNetworksForVpn(
@@ -5961,6 +6055,7 @@
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
// As above, the RESUMED callback not being sent here is a bug, but not a bug that's
// worth anybody's time to fix.
+ assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Disconnect cell. Receive update without even removing the dead network from the
// underlying networks – it's dead anyway. Not metered any more.
@@ -5969,6 +6064,7 @@
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
// Disconnect wifi too. No underlying networks means this is now metered.
mWiFiNetworkAgent.disconnect();
@@ -5976,6 +6072,11 @@
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ // When a network disconnects, the callbacks are fired before all state is updated, so for a
+ // short time, synchronous calls will behave as if the network is still connected. Wait for
+ // things to settle.
+ waitForIdle();
+ assertDefaultNetworkCapabilities(userId /* no networks */);
mMockVpn.disconnect();
}
@@ -6276,6 +6377,7 @@
// Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered.
assertTrue(mCm.isActiveNetworkMetered());
+
// VPN explicitly declares WiFi as its underlying network.
mService.setUnderlyingNetworksForVpn(
new Network[] { mWiFiNetworkAgent.getNetwork() });
@@ -6389,6 +6491,189 @@
mCm.unregisterNetworkCallback(defaultCallback);
}
+ private void expectNetworkRejectNonSecureVpn(InOrder inOrder, boolean add,
+ UidRangeParcel... expected) throws Exception {
+ inOrder.verify(mMockNetd).networkRejectNonSecureVpn(eq(add), aryEq(expected));
+ }
+
+ private void checkNetworkInfo(NetworkInfo ni, int type, DetailedState state) {
+ assertNotNull(ni);
+ assertEquals(type, ni.getType());
+ assertEquals(ConnectivityManager.getNetworkTypeName(type), state, ni.getDetailedState());
+ }
+
+ private void assertActiveNetworkInfo(int type, DetailedState state) {
+ checkNetworkInfo(mCm.getActiveNetworkInfo(), type, state);
+ }
+ private void assertNetworkInfo(int type, DetailedState state) {
+ checkNetworkInfo(mCm.getNetworkInfo(type), type, state);
+ }
+
+ @Test
+ public void testNetworkBlockedStatusAlwaysOnVpn() throws Exception {
+ mServiceContext.setPermission(
+ Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
+ mServiceContext.setPermission(
+ Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+ mServiceContext.setPermission(
+ Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .build();
+ mCm.registerNetworkCallback(request, callback);
+
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+
+ final TestNetworkCallback vpnUidCallback = new TestNetworkCallback();
+ final NetworkRequest vpnUidRequest = new NetworkRequest.Builder().build();
+ registerNetworkCallbackAsUid(vpnUidRequest, vpnUidCallback, VPN_UID);
+
+ final int uid = Process.myUid();
+ final int userId = UserHandle.getUserId(uid);
+ final ArrayList<String> allowList = new ArrayList<>();
+ mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+
+ UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
+ UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
+ InOrder inOrder = inOrder(mMockNetd);
+ expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
+
+ // Connect a network when lockdown is active, expect to see it blocked.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false /* validated */);
+ callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+ vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertNull(mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+ // Mobile is BLOCKED even though it's not actually connected.
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+
+ // Disable lockdown, expect to see the network unblocked.
+ // There are no callbacks because they are not implemented yet.
+ mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
+ vpnUidCallback.assertNoCallback();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ // Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
+ allowList.add(TEST_PACKAGE_NAME);
+ mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ callback.assertNoCallback();
+ defaultCallback.assertNoCallback();
+ vpnUidCallback.assertNoCallback();
+
+ // The following requires that the UID of this test package is greater than VPN_UID. This
+ // is always true in practice because a plain AOSP build with no apps installed has almost
+ // 200 packages installed.
+ final UidRangeParcel piece1 = new UidRangeParcel(1, VPN_UID - 1);
+ final UidRangeParcel piece2 = new UidRangeParcel(VPN_UID + 1, uid - 1);
+ final UidRangeParcel piece3 = new UidRangeParcel(uid + 1, 99999);
+ expectNetworkRejectNonSecureVpn(inOrder, true, piece1, piece2, piece3);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ // Connect a new network, expect it to be unblocked.
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(false /* validated */);
+ callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ defaultCallback.assertNoCallback();
+ vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ // Cellular is DISCONNECTED because it's not the default and there are no requests for it.
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
+ // Everything should now be blocked.
+ mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
+ allowList.clear();
+ mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
+ vpnUidCallback.assertNoCallback();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertNull(mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+
+ // Disable lockdown. Everything is unblocked.
+ mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ vpnUidCallback.assertNoCallback();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ // Enable and disable an always-on VPN package without lockdown. Expect no changes.
+ reset(mMockNetd);
+ mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */, allowList);
+ inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
+ callback.assertNoCallback();
+ defaultCallback.assertNoCallback();
+ vpnUidCallback.assertNoCallback();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
+ callback.assertNoCallback();
+ defaultCallback.assertNoCallback();
+ vpnUidCallback.assertNoCallback();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ // Enable lockdown and connect a VPN. The VPN is not blocked.
+ mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ vpnUidCallback.assertNoCallback();
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
+ assertNull(mCm.getActiveNetwork());
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
+
+ mMockVpn.establishForMyUid();
+ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability.
+ assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(null, mCm.getActiveNetworkForUid(VPN_UID)); // BUG?
+ assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
+ assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
+ assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
+
+ mMockVpn.disconnect();
+ defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+ assertNull(mCm.getActiveNetwork());
+
+ mCm.unregisterNetworkCallback(callback);
+ mCm.unregisterNetworkCallback(defaultCallback);
+ mCm.unregisterNetworkCallback(vpnUidCallback);
+ }
+
@Test
public final void testLoseTrusted() throws Exception {
final NetworkRequest trustedRequest = new NetworkRequest.Builder()
@@ -7822,7 +8107,16 @@
@Test
public void testDumpDoesNotCrash() {
- StringWriter stringWriter = new StringWriter();
+ // Filing a couple requests prior to testing the dump.
+ final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder()
+ .clearCapabilities().build();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ final StringWriter stringWriter = new StringWriter();
mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
@@ -7844,11 +8138,11 @@
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
+ final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
assertTrue(nriOutput.length > 1);
for (int i = 0; i < nriOutput.length - 1; i++) {
- boolean isRequestIdInOrder =
+ final boolean isRequestIdInOrder =
nriOutput[i].mRequests.get(0).requestId
< nriOutput[i + 1].mRequests.get(0).requestId;
assertTrue(isRequestIdInOrder);
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index ea763d2..13516d7 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -68,11 +68,12 @@
@SmallTest
public class NetworkManagementServiceTest {
private NetworkManagementService mNMService;
-
@Mock private Context mContext;
@Mock private IBatteryStats.Stub mBatteryStatsService;
@Mock private INetd.Stub mNetdService;
+ private static final int TEST_UID = 111;
+
@NonNull
@Captor
private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
@@ -165,14 +166,14 @@
/**
* Interface class activity.
*/
- unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
+ unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged(1, true, 1234, TEST_UID);
- unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged(9, false, 5678, TEST_UID);
- unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
- expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
+ expectSoon(observer).interfaceClassDataActivityChanged(9, false, 4321, TEST_UID);
/**
* IP address changes.
@@ -222,8 +223,6 @@
assertFalse(mNMService.isFirewallEnabled());
}
- private static final int TEST_UID = 111;
-
@Test
public void testNetworkRestrictedDefault() {
assertFalse(mNMService.isNetworkRestricted(TEST_UID));
@@ -235,23 +234,23 @@
doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
// Restrict usage of mobile data in background
- mNMService.setUidMeteredNetworkDenylist(TEST_UID, true);
+ mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, true);
assertTrue("Should be true since mobile data usage is restricted",
mNMService.isNetworkRestricted(TEST_UID));
mNMService.setDataSaverModeEnabled(true);
verify(mNetdService).bandwidthEnableDataSaver(true);
- mNMService.setUidMeteredNetworkDenylist(TEST_UID, false);
+ mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
assertTrue("Should be true since data saver is on and the uid is not allowlisted",
mNMService.isNetworkRestricted(TEST_UID));
- mNMService.setUidMeteredNetworkAllowlist(TEST_UID, true);
+ mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, true);
assertFalse("Should be false since data saver is on and the uid is allowlisted",
mNMService.isNetworkRestricted(TEST_UID));
// remove uid from allowlist and turn datasaver off again
- mNMService.setUidMeteredNetworkAllowlist(TEST_UID, false);
+ mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
mNMService.setDataSaverModeEnabled(false);
verify(mNetdService).bandwidthEnableDataSaver(false);
assertFalse("Network should not be restricted when data saver is off",
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 6e380be..cc47317 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -228,7 +228,6 @@
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
.thenReturn(true);
- when(mSystemServices.isCallerSystem()).thenReturn(true);
// Used by {@link Notification.Builder}
ApplicationInfo applicationInfo = new ApplicationInfo();
@@ -1102,6 +1101,11 @@
}
@Override
+ public boolean isCallerSystem() {
+ return true;
+ }
+
+ @Override
public void startService(final String serviceName) {
mRunningServices.put(serviceName, true);
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index fb0cfc0..89146f9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -23,11 +23,11 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkUtils.multiplySafeByRational;
import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertArrayEquals;
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index cd9406c..c783629 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -23,6 +23,7 @@
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.INTERFACES_ALL;
@@ -917,7 +918,8 @@
public void testMetered() throws Exception {
// pretend that network comes online
expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)};
+ NetworkState[] states =
+ new NetworkState[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1146,7 +1148,8 @@
public void testStatsProviderUpdateStats() throws Exception {
// Pretend that network comes online.
expectDefaultSettings();
- final NetworkState[] states = new NetworkState[]{buildWifiState(true /* isMetered */)};
+ final NetworkState[] states =
+ new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1206,7 +1209,8 @@
public void testStatsProviderSetAlert() throws Exception {
// Pretend that network comes online.
expectDefaultSettings();
- NetworkState[] states = new NetworkState[]{buildWifiState(true /* isMetered */)};
+ NetworkState[] states =
+ new NetworkState[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
// Register custom provider and retrieve callback.
@@ -1319,6 +1323,47 @@
assertUidTotal(templateAll, UID_RED, 22L + 35L, 26L + 29L, 19L + 7L, 5L + 11L, 1);
}
+ @Test
+ public void testOperationCount_nonDefault_traffic() throws Exception {
+ // Pretend mobile network comes online, but wifi is the default network.
+ expectDefaultSettings();
+ NetworkState[] states = new NetworkState[]{
+ buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]);
+
+ // Create some traffic on mobile network.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4)
+ .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 2L, 1L, 3L, 4L, 0L)
+ .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 1L, 3L, 2L, 1L, 0L)
+ .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 5L, 4L, 1L, 4L, 0L));
+ // Increment operation count, which must have a specific tag.
+ mService.incrementOperationCount(UID_RED, 0xF00D, 2);
+ forcePollAndWaitForIdle();
+
+ // Verify mobile summary is not changed by the operation count.
+ final NetworkTemplate templateMobile =
+ buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
+ final NetworkStats statsMobile = mSession.getSummaryForAllUid(
+ templateMobile, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertValues(statsMobile, IFACE_ALL, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, 3L, 4L, 5L, 5L, 0);
+ assertValues(statsMobile, IFACE_ALL, UID_RED, SET_ALL, 0xF00D, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, 5L, 4L, 1L, 4L, 0);
+
+ // Verify the operation count is blamed onto the default network.
+ // TODO: Blame onto the default network is not very reasonable. Consider blame onto the
+ // network that generates the traffic.
+ final NetworkTemplate templateWifi = buildTemplateWifiWildcard();
+ final NetworkStats statsWifi = mSession.getSummaryForAllUid(
+ templateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertValues(statsWifi, IFACE_ALL, UID_RED, SET_ALL, 0xF00D, METERED_ALL, ROAMING_ALL,
+ DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 2);
+ }
+
private static File getBaseDir(File statsDir) {
File baseDir = new File(statsDir, "netstats");
baseDir.mkdirs();
@@ -1446,14 +1491,14 @@
}
private static NetworkState buildWifiState() {
- return buildWifiState(false);
+ return buildWifiState(false, TEST_IFACE);
}
- private static NetworkState buildWifiState(boolean isMetered) {
+ private static NetworkState buildWifiState(boolean isMetered, @NonNull String iface) {
final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null);
info.setDetailedState(DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TEST_IFACE);
+ prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities();
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);