Merge "[Thread] add more Thread shell commands" into main
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 19bcff9..e84573b 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -126,7 +126,7 @@
// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK).
cc_library {
name: "libcom_android_networkstack_tethering_util_jni",
- sdk_version: "30",
+ sdk_version: "current",
apex_available: [
"com.android.tethering",
],
diff --git a/common/flags.aconfig b/common/flags.aconfig
index 55a96ac..6c3e89d 100644
--- a/common/flags.aconfig
+++ b/common/flags.aconfig
@@ -99,3 +99,11 @@
description: "Flag for oem deny chains blocked reasons API"
bug: "328732146"
}
+
+flag {
+ name: "blocked_reason_network_restricted"
+ is_exported: true
+ namespace: "android_core_networking"
+ description: "Flag for BLOCKED_REASON_NETWORK_RESTRICTED API"
+ bug: "339559837"
+}
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index d233f3e..cd7307f 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -51,6 +51,7 @@
field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20
+ field @FlaggedApi("com.android.net.flags.blocked_reason_network_restricted") public static final int BLOCKED_REASON_NETWORK_RESTRICTED = 256; // 0x100
field public static final int BLOCKED_REASON_NONE = 0; // 0x0
field @FlaggedApi("com.android.net.flags.blocked_reason_oem_deny_chains") public static final int BLOCKED_REASON_OEM_DENY = 128; // 0x80
field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 48ed732..0b37fa5 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -132,6 +132,8 @@
"com.android.net.flags.metered_network_firewall_chains";
static final String BLOCKED_REASON_OEM_DENY_CHAINS =
"com.android.net.flags.blocked_reason_oem_deny_chains";
+ static final String BLOCKED_REASON_NETWORK_RESTRICTED =
+ "com.android.net.flags.blocked_reason_network_restricted";
}
/**
@@ -928,6 +930,17 @@
public static final int BLOCKED_REASON_OEM_DENY = 1 << 7;
/**
+ * Flag to indicate that an app does not have permission to access the specified network,
+ * for example, because it does not have the {@link android.Manifest.permission#INTERNET}
+ * permission.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.BLOCKED_REASON_NETWORK_RESTRICTED)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_NETWORK_RESTRICTED = 1 << 8;
+
+ /**
* Flag to indicate that an app is subject to Data saver restrictions that would
* result in its metered network access being blocked.
*
@@ -968,6 +981,7 @@
BLOCKED_REASON_LOW_POWER_STANDBY,
BLOCKED_REASON_APP_BACKGROUND,
BLOCKED_REASON_OEM_DENY,
+ BLOCKED_REASON_NETWORK_RESTRICTED,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
diff --git a/framework/src/android/net/apf/ApfCapabilities.java b/framework/src/android/net/apf/ApfCapabilities.java
index fae2499..8efb182 100644
--- a/framework/src/android/net/apf/ApfCapabilities.java
+++ b/framework/src/android/net/apf/ApfCapabilities.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
* way to drop unwanted network packets to save power.
@@ -102,6 +104,11 @@
&& apfPacketFormat == other.apfPacketFormat;
}
+ @Override
+ public int hashCode() {
+ return Objects.hash(apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
+ }
+
/**
* Determines whether the APF interpreter advertises support for the data buffer access opcodes
* LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and
diff --git a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
index 02ef8b7..c726dab 100644
--- a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
+++ b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java
@@ -118,7 +118,7 @@
* @hide
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = 35) // TODO: change to VANILLA_ICE_CREAM.
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
public static final long NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION = 333340911L;
private ConnectivityCompatChanges() {
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index ccb6acb..dc67f83 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -306,6 +306,7 @@
if (bad && !isGSI()) {
ALOGE("Unsupported kernel version (%07x).", kernelVersion());
+ sleep(60);
}
}
@@ -432,6 +433,7 @@
ALOGE("Failed to set bpf.progs_loaded property to 1.");
return 125;
}
+ ALOGI("success.");
return 0;
}
diff --git a/netbpfload/loader.cpp b/netbpfload/loader.cpp
index 2b5f5c7..289b4d7 100644
--- a/netbpfload/loader.cpp
+++ b/netbpfload/loader.cpp
@@ -736,15 +736,15 @@
domain selinux_context = getDomainFromSelinuxContext(md[i].selinux_context);
if (specified(selinux_context)) {
ALOGI("map %s selinux_context [%-32s] -> %d -> '%s' (%s)", mapNames[i].c_str(),
- md[i].selinux_context, selinux_context, lookupSelinuxContext(selinux_context),
- lookupPinSubdir(selinux_context));
+ md[i].selinux_context, static_cast<int>(selinux_context),
+ lookupSelinuxContext(selinux_context), lookupPinSubdir(selinux_context));
}
domain pin_subdir = getDomainFromPinSubdir(md[i].pin_subdir);
if (unrecognized(pin_subdir)) return -ENOTDIR;
if (specified(pin_subdir)) {
ALOGI("map %s pin_subdir [%-32s] -> %d -> '%s'", mapNames[i].c_str(), md[i].pin_subdir,
- pin_subdir, lookupPinSubdir(pin_subdir));
+ static_cast<int>(pin_subdir), lookupPinSubdir(pin_subdir));
}
// Format of pin location is /sys/fs/bpf/<pin_subdir|prefix>map_<objName>_<mapName>
@@ -974,13 +974,14 @@
if (specified(selinux_context)) {
ALOGI("prog %s selinux_context [%-32s] -> %d -> '%s' (%s)", name.c_str(),
- cs[i].prog_def->selinux_context, selinux_context,
+ cs[i].prog_def->selinux_context, static_cast<int>(selinux_context),
lookupSelinuxContext(selinux_context), lookupPinSubdir(selinux_context));
}
if (specified(pin_subdir)) {
ALOGI("prog %s pin_subdir [%-32s] -> %d -> '%s'", name.c_str(),
- cs[i].prog_def->pin_subdir, pin_subdir, lookupPinSubdir(pin_subdir));
+ cs[i].prog_def->pin_subdir, static_cast<int>(pin_subdir),
+ lookupPinSubdir(pin_subdir));
}
// strip any potential $foo suffix
diff --git a/netd/Android.bp b/netd/Android.bp
index eedbdae..fe4d999 100644
--- a/netd/Android.bp
+++ b/netd/Android.bp
@@ -72,6 +72,8 @@
"BpfHandlerTest.cpp",
"BpfBaseTest.cpp",
],
+ version_script: ":connectivity_mainline_test_map",
+ stl: "libc++_static",
static_libs: [
"libbase",
"libnetd_updatable",
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index b535ebf..91fec90 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "BpfHandler"
+#define LOG_TAG "NetdUpdatable"
#include "BpfHandler.h"
diff --git a/remoteauth/service/jni/Android.bp b/remoteauth/service/jni/Android.bp
index c0ac779..fc91e0c 100644
--- a/remoteauth/service/jni/Android.bp
+++ b/remoteauth/service/jni/Android.bp
@@ -12,7 +12,7 @@
srcs: ["src/lib.rs"],
rustlibs: [
"libbinder_rs",
- "libjni",
+ "libjni_legacy",
"liblazy_static",
"liblog_rust",
"liblogger",
diff --git a/service-t/native/libs/libnetworkstats/Android.bp b/service-t/native/libs/libnetworkstats/Android.bp
index c620634..b1925bd 100644
--- a/service-t/native/libs/libnetworkstats/Android.bp
+++ b/service-t/native/libs/libnetworkstats/Android.bp
@@ -76,6 +76,8 @@
"-Wno-unused-parameter",
"-Wthread-safety",
],
+ version_script: ":connectivity_mainline_test_map",
+ stl: "libc++_static",
static_libs: [
"libbase",
"libgmock",
diff --git a/service/Android.bp b/service/Android.bp
index 1d74efc..1dd09a9 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -188,7 +188,7 @@
"androidx.annotation_annotation",
"connectivity-net-module-utils-bpf",
"connectivity_native_aidl_interface-lateststable-java",
- "dnsresolver_aidl_interface-V14-java",
+ "dnsresolver_aidl_interface-V15-java",
"modules-utils-shell-command-handler",
"net-utils-device-common",
"net-utils-device-common-ip",
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 23af0f8..1047232 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -55,6 +55,7 @@
import android.os.Build;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.os.UserHandle;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArraySet;
@@ -815,8 +816,11 @@
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public int getNetPermForUid(final int uid) {
+ final int appId = UserHandle.getAppId(uid);
try {
- final U8 permissions = sUidPermissionMap.getValue(new S32(uid));
+ // Key of uid permission map is appId
+ // TODO: Rename map name
+ final U8 permissions = sUidPermissionMap.getValue(new S32(appId));
return permissions != null ? permissions.val : PERMISSION_INTERNET;
} catch (ErrnoException e) {
Log.wtf(TAG, "Failed to get permission for uid: " + uid);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 39ea286..519391f 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -38,6 +38,7 @@
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NETWORK_RESTRICTED;
import static android.net.ConnectivityManager.CALLBACK_IP_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
@@ -120,6 +121,7 @@
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
import static com.android.net.module.util.PermissionUtils.hasAnyPermissionOf;
import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_STATE_SAMPLE;
+import static com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS;
import static com.android.server.connectivity.ConnectivityFlags.REQUEST_RESTRICTED_WIFI;
import static com.android.server.connectivity.ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING;
@@ -485,8 +487,30 @@
private final boolean mBackgroundFirewallChainEnabled;
/**
- * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in
- * internal handler thread, they don't need a lock.
+ * Uids ConnectivityService tracks blocked status of to send blocked status callbacks.
+ * Key is uid based on mAsUid of registered networkRequestInfo
+ * Value is count of registered networkRequestInfo
+ *
+ * This is necessary because when a firewall chain is enabled or disabled, that affects all UIDs
+ * on the system, not just UIDs on that firewall chain. For example, entering doze mode affects
+ * all UIDs that are not on the dozable chain. ConnectivityService doesn't know which UIDs are
+ * running. But it only needs to send onBlockedStatusChanged to UIDs that have at least one
+ * NetworkCallback registered.
+ *
+ * UIDs are added to this list on the binder thread when processing requestNetwork and similar
+ * IPCs. They are removed from this list on the handler thread, when the callback unregistration
+ * is fully processed. They cannot be unregistered when the unregister IPC is processed because
+ * sometimes requests are unregistered on the handler thread.
+ */
+ @GuardedBy("mBlockedStatusTrackingUids")
+ private final SparseIntArray mBlockedStatusTrackingUids = new SparseIntArray();
+
+ /**
+ * Stale copy of UID blocked reasons. This is used to send onBlockedStatusChanged
+ * callbacks. This is only used on the handler thread, so it does not require a lock.
+ * On U-, the blocked reasons come from NPMS.
+ * On V+, the blocked reasons come from the BPF map contents and only maintains blocked reasons
+ * of uids that register network callbacks.
*/
private final SparseIntArray mUidBlockedReasons = new SparseIntArray();
@@ -554,6 +578,8 @@
* default network for each app.
* Order ints passed to netd must be in the 0~999 range. Larger values code for
* a lower priority, see {@link NativeUidRangeConfig}.
+ * Note that only the highest priority preference is applied if the uid is the target of
+ * multiple preferences.
*
* Requests that don't code for a per-app preference use PREFERENCE_ORDER_INVALID.
* The default request uses PREFERENCE_ORDER_DEFAULT.
@@ -788,11 +814,10 @@
private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50;
/**
- * Event to specify that reasons for why an uid is blocked changed.
- * arg1 = uid
- * arg2 = blockedReasons
+ * Event to update blocked reasons for uids.
+ * obj = List of Pair(uid, blockedReasons)
*/
- private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51;
+ private static final int EVENT_BLOCKED_REASONS_CHANGED = 51;
/**
* Event to register a new network offer
@@ -996,14 +1021,18 @@
// Flag to enable the feature of closing frozen app sockets.
private final boolean mDestroyFrozenSockets;
- // Flag to optimize closing frozen app sockets by waiting for the cellular modem to wake up.
- private final boolean mDelayDestroyFrozenSockets;
+ // Flag to optimize closing app sockets by waiting for the cellular modem to wake up.
+ private final boolean mDelayDestroySockets;
// Flag to allow SysUI to receive connectivity reports for wifi picker UI.
private final boolean mAllowSysUiConnectivityReports;
// Uids that ConnectivityService is pending to close sockets of.
- private final Set<Integer> mPendingFrozenUids = new ArraySet<>();
+ // Key is uid and value is reasons of socket destroy
+ private final SparseIntArray mDestroySocketPendingUids = new SparseIntArray();
+
+ private static final int DESTROY_SOCKET_REASON_NONE = 0;
+ private static final int DESTROY_SOCKET_REASON_FROZEN = 1 << 0;
// Flag to drop packets to VPN addresses ingressing via non-VPN interfaces.
private final boolean mIngressToVpnAddressFiltering;
@@ -1821,7 +1850,12 @@
// To ensure uid state is synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
// reading existing policy from disk.
- mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback);
+ // If shouldTrackUidsForBlockedStatusCallbacks() is true (On V+), ConnectivityService
+ // updates blocked reasons when firewall chain and data saver status is updated based on
+ // bpf map contents instead of receiving callbacks from NPMS
+ if (!shouldTrackUidsForBlockedStatusCallbacks()) {
+ mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback);
+ }
final PowerManager powerManager = (PowerManager) context.getSystemService(
Context.POWER_SERVICE);
@@ -1952,8 +1986,7 @@
mDestroyFrozenSockets = mDeps.isAtLeastV() || (mDeps.isAtLeastU()
&& mDeps.isFeatureEnabled(context, KEY_DESTROY_FROZEN_SOCKETS_VERSION));
- mDelayDestroyFrozenSockets = mDeps.isAtLeastU()
- && mDeps.isFeatureEnabled(context, DELAY_DESTROY_FROZEN_SOCKETS_VERSION);
+ mDelayDestroySockets = mDeps.isFeatureNotChickenedOut(context, DELAY_DESTROY_SOCKETS);
mAllowSysUiConnectivityReports = mDeps.isFeatureNotChickenedOut(
mContext, ALLOW_SYSUI_CONNECTIVITY_REPORTS);
if (mDestroyFrozenSockets) {
@@ -3309,14 +3342,38 @@
private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
@Override
public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
- uid, blockedReasons));
+ if (shouldTrackUidsForBlockedStatusCallbacks()) {
+ Log.wtf(TAG, "Received unexpected NetworkPolicy callback");
+ return;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_BLOCKED_REASONS_CHANGED,
+ List.of(new Pair<>(uid, blockedReasons))));
}
};
- private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
- maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
- setUidBlockedReasons(uid, blockedReasons);
+ private boolean shouldTrackUidsForBlockedStatusCallbacks() {
+ return mDeps.isAtLeastV();
+ }
+
+ @VisibleForTesting
+ void handleBlockedReasonsChanged(List<Pair<Integer, Integer>> reasonsList) {
+ for (Pair<Integer, Integer> reasons: reasonsList) {
+ final int uid = reasons.first;
+ final int blockedReasons = reasons.second;
+ if (shouldTrackUidsForBlockedStatusCallbacks()) {
+ synchronized (mBlockedStatusTrackingUids) {
+ if (mBlockedStatusTrackingUids.get(uid) == 0) {
+ // This uid is not tracked anymore.
+ // This can happen if the network request is unregistered while
+ // EVENT_BLOCKED_REASONS_CHANGED is posted but not processed yet.
+ continue;
+ }
+ }
+ }
+ maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
+ setUidBlockedReasons(uid, blockedReasons);
+ }
}
static final class UidFrozenStateChangedArgs {
@@ -3347,44 +3404,51 @@
return !mNetworkActivityTracker.isDefaultNetworkActive();
}
- private void handleFrozenUids(int[] uids, int[] frozenStates) {
- final ArraySet<Integer> ownerUids = new ArraySet<>();
-
- for (int i = 0; i < uids.length; i++) {
- if (frozenStates[i] == UID_FROZEN_STATE_FROZEN) {
- ownerUids.add(uids[i]);
- } else {
- mPendingFrozenUids.remove(uids[i]);
- }
- }
-
- if (ownerUids.isEmpty()) {
- return;
- }
-
- if (mDelayDestroyFrozenSockets && isCellNetworkIdle()) {
- // Delay closing sockets to avoid waking the cell modem up.
- // Wi-Fi network state is not considered since waking Wi-Fi modem up is much cheaper
- // than waking cell modem up.
- mPendingFrozenUids.addAll(ownerUids);
+ private void updateDestroySocketReasons(final int uid, final int reason,
+ final boolean addReason) {
+ final int destroyReasons = mDestroySocketPendingUids.get(uid, DESTROY_SOCKET_REASON_NONE);
+ if (addReason) {
+ mDestroySocketPendingUids.put(uid, destroyReasons | reason);
} else {
- try {
- mDeps.destroyLiveTcpSocketsByOwnerUids(ownerUids);
- } catch (SocketException | InterruptedIOException | ErrnoException e) {
- loge("Exception in socket destroy: " + e);
+ final int newDestroyReasons = destroyReasons & ~reason;
+ if (newDestroyReasons == DESTROY_SOCKET_REASON_NONE) {
+ mDestroySocketPendingUids.delete(uid);
+ } else {
+ mDestroySocketPendingUids.put(uid, newDestroyReasons);
}
}
}
- private void closePendingFrozenSockets() {
+ private void handleFrozenUids(int[] uids, int[] frozenStates) {
ensureRunningOnConnectivityServiceThread();
+ for (int i = 0; i < uids.length; i++) {
+ final int uid = uids[i];
+ final boolean addReason = frozenStates[i] == UID_FROZEN_STATE_FROZEN;
+ updateDestroySocketReasons(uid, DESTROY_SOCKET_REASON_FROZEN, addReason);
+ }
+
+ if (!mDelayDestroySockets || !isCellNetworkIdle()) {
+ destroyPendingSockets();
+ }
+ }
+
+ private void destroyPendingSockets() {
+ ensureRunningOnConnectivityServiceThread();
+ if (mDestroySocketPendingUids.size() == 0) {
+ return;
+ }
+
+ Set<Integer> uids = new ArraySet<>();
+ for (int i = 0; i < mDestroySocketPendingUids.size(); i++) {
+ uids.add(mDestroySocketPendingUids.keyAt(i));
+ }
try {
- mDeps.destroyLiveTcpSocketsByOwnerUids(mPendingFrozenUids);
+ mDeps.destroyLiveTcpSocketsByOwnerUids(uids);
} catch (SocketException | InterruptedIOException | ErrnoException e) {
- loge("Failed to close pending frozen app sockets: " + e);
+ loge("Failed to destroy sockets: " + e);
}
- mPendingFrozenUids.clear();
+ mDestroySocketPendingUids.clear();
}
private void handleReportNetworkActivity(final NetworkActivityParams params) {
@@ -3401,40 +3465,42 @@
isCellNetworkActivity = params.label == TRANSPORT_CELLULAR;
}
- if (mDelayDestroyFrozenSockets
- && params.isActive
- && isCellNetworkActivity
- && !mPendingFrozenUids.isEmpty()) {
- closePendingFrozenSockets();
+ if (mDelayDestroySockets && params.isActive && isCellNetworkActivity) {
+ destroyPendingSockets();
}
}
/**
- * If the cellular network is no longer the default network, close pending frozen sockets.
+ * If the cellular network is no longer the default network, destroy pending sockets.
*
* @param newNetwork new default network
* @param oldNetwork old default network
*/
- private void maybeClosePendingFrozenSockets(NetworkAgentInfo newNetwork,
+ private void maybeDestroyPendingSockets(NetworkAgentInfo newNetwork,
NetworkAgentInfo oldNetwork) {
final boolean isOldNetworkCellular = oldNetwork != null
&& oldNetwork.networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
final boolean isNewNetworkCellular = newNetwork != null
&& newNetwork.networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
- if (isOldNetworkCellular
- && !isNewNetworkCellular
- && !mPendingFrozenUids.isEmpty()) {
- closePendingFrozenSockets();
+ if (isOldNetworkCellular && !isNewNetworkCellular) {
+ destroyPendingSockets();
}
}
- private void dumpCloseFrozenAppSockets(IndentingPrintWriter pw) {
- pw.println("CloseFrozenAppSockets:");
+ private void dumpDestroySockets(IndentingPrintWriter pw) {
+ pw.println("DestroySockets:");
pw.increaseIndent();
pw.print("mDestroyFrozenSockets="); pw.println(mDestroyFrozenSockets);
- pw.print("mDelayDestroyFrozenSockets="); pw.println(mDelayDestroyFrozenSockets);
- pw.print("mPendingFrozenUids="); pw.println(mPendingFrozenUids);
+ pw.print("mDelayDestroySockets="); pw.println(mDelayDestroySockets);
+ pw.print("mDestroySocketPendingUids:");
+ pw.increaseIndent();
+ for (int i = 0; i < mDestroySocketPendingUids.size(); i++) {
+ final int uid = mDestroySocketPendingUids.keyAt(i);
+ final int reasons = mDestroySocketPendingUids.valueAt(i);
+ pw.print(uid + ": reasons=" + reasons);
+ }
+ pw.decreaseIndent();
pw.decreaseIndent();
}
@@ -3460,9 +3526,6 @@
@VisibleForTesting
static final String KEY_DESTROY_FROZEN_SOCKETS_VERSION = "destroy_frozen_sockets_version";
- @VisibleForTesting
- static final String DELAY_DESTROY_FROZEN_SOCKETS_VERSION =
- "delay_destroy_frozen_sockets_version";
@VisibleForTesting
public static final String ALLOW_SYSUI_CONNECTIVITY_REPORTS =
@@ -4096,7 +4159,7 @@
dumpAvoidBadWifiSettings(pw);
pw.println();
- dumpCloseFrozenAppSockets(pw);
+ dumpDestroySockets(pw);
pw.println();
dumpBpfProgramStatus(pw);
@@ -5209,7 +5272,7 @@
if (mDefaultRequest == nri) {
mNetworkActivityTracker.updateDefaultNetwork(null /* newNetwork */, nai);
- maybeClosePendingFrozenSockets(null /* newNetwork */, nai);
+ maybeDestroyPendingSockets(null /* newNetwork */, nai);
ensureNetworkTransitionWakelock(nai.toShortString());
}
}
@@ -5486,6 +5549,12 @@
// If there is an active request, then for sure there is a satisfier.
nri.getSatisfier().addRequest(activeRequest);
}
+
+ if (shouldTrackUidsForBlockedStatusCallbacks()
+ && isAppRequest(nri)
+ && !nri.mUidTrackedForBlockedStatus) {
+ Log.wtf(TAG, "Registered nri is not tracked for sending blocked status: " + nri);
+ }
}
if (mFlags.noRematchAllRequestsOnRegister()) {
@@ -5685,6 +5754,11 @@
}
private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) {
+ handleRemoveNetworkRequest(nri, true /* untrackUids */);
+ }
+
+ private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri,
+ final boolean untrackUids) {
ensureRunningOnConnectivityServiceThread();
for (final NetworkRequest req : nri.mRequests) {
if (null == mNetworkRequests.remove(req)) {
@@ -5719,7 +5793,9 @@
}
}
- nri.mPerUidCounter.decrementCount(nri.mUid);
+ if (untrackUids) {
+ maybeUntrackUidAndClearBlockedReasons(nri);
+ }
mNetworkRequestInfoLogs.log("RELEASE " + nri);
checkNrisConsistency(nri);
@@ -5741,12 +5817,17 @@
}
private void handleRemoveNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
+ handleRemoveNetworkRequests(nris, true /* untrackUids */);
+ }
+
+ private void handleRemoveNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris,
+ final boolean untrackUids) {
for (final NetworkRequestInfo nri : nris) {
if (mDefaultRequest == nri) {
// Make sure we never remove the default request.
continue;
}
- handleRemoveNetworkRequest(nri);
+ handleRemoveNetworkRequest(nri, untrackUids);
}
}
@@ -6486,8 +6567,8 @@
handlePrivateDnsValidationUpdate(
(PrivateDnsValidationUpdate) msg.obj);
break;
- case EVENT_UID_BLOCKED_REASON_CHANGED:
- handleUidBlockedReasonChanged(msg.arg1, msg.arg2);
+ case EVENT_BLOCKED_REASONS_CHANGED:
+ handleBlockedReasonsChanged((List) msg.obj);
break;
case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
@@ -7352,6 +7433,11 @@
// maximum limit of registered callbacks per UID.
final int mAsUid;
+ // Flag to indicate that uid of this nri is tracked for sending blocked status callbacks.
+ // It is always true on V+ if mMessenger != null. As such, it's not strictly necessary.
+ // it's used only as a safeguard to avoid double counting or leaking.
+ boolean mUidTrackedForBlockedStatus;
+
// Preference order of this request.
final int mPreferenceOrder;
@@ -7401,7 +7487,6 @@
mUid = mDeps.getCallingUid();
mAsUid = asUid;
mPerUidCounter = getRequestCounter(this);
- mPerUidCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
* {@link NetworkCallback}.
@@ -7435,7 +7520,6 @@
mAsUid = asUid;
mPendingIntent = null;
mPerUidCounter = getRequestCounter(this);
- mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
mPreferenceOrder = PREFERENCE_ORDER_INVALID;
@@ -7475,9 +7559,9 @@
mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
mPerUidCounter = nri.mPerUidCounter;
- mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
+ mUidTrackedForBlockedStatus = nri.mUidTrackedForBlockedStatus;
mPreferenceOrder = PREFERENCE_ORDER_INVALID;
linkDeathRecipient();
}
@@ -7565,7 +7649,8 @@
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
+ " callback flags: " + mCallbackFlags
- + " order: " + mPreferenceOrder;
+ + " order: " + mPreferenceOrder
+ + " isUidTracked: " + mUidTrackedForBlockedStatus;
}
}
@@ -7780,13 +7865,6 @@
throw new IllegalArgumentException("Bad timeout specified");
}
- final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
- nextNetworkRequestId(), reqType);
- final NetworkRequestInfo nri = getNriToRegister(
- asUid, networkRequest, messenger, binder, callbackFlags,
- callingAttributionTag);
- if (DBG) log("requestNetwork for " + nri);
-
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
// copied from the default request above. (This is necessary to ensure, for example, that
// the callback does not leak sensitive information to unprivileged apps.) Check that the
@@ -7798,7 +7876,13 @@
+ networkCapabilities + " vs. " + defaultNc);
}
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
+ final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
+ nextNetworkRequestId(), reqType);
+ final NetworkRequestInfo nri = getNriToRegister(
+ asUid, networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
+ if (DBG) log("requestNetwork for " + nri);
+ trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_REQUEST, nri);
if (timeoutMs > 0) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
nri), timeoutMs);
@@ -8007,8 +8091,7 @@
NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
- nri));
+ trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT, nri);
return networkRequest;
}
@@ -8047,6 +8130,77 @@
return true;
}
+ private boolean isAppRequest(NetworkRequestInfo nri) {
+ return nri.mMessenger != null || nri.mPendingIntent != null;
+ }
+
+ private void trackUidAndMaybePostCurrentBlockedReason(final NetworkRequestInfo nri) {
+ if (!isAppRequest(nri)) {
+ Log.wtf(TAG, "trackUidAndMaybePostCurrentBlockedReason is called for non app"
+ + "request: " + nri);
+ return;
+ }
+ nri.mPerUidCounter.incrementCountOrThrow(nri.mUid);
+
+ // If nri.mMessenger is null, this nri does not have NetworkCallback so ConnectivityService
+ // does not need to send onBlockedStatusChanged callback for this uid and does not need to
+ // track the uid in mBlockedStatusTrackingUids
+ if (!shouldTrackUidsForBlockedStatusCallbacks() || nri.mMessenger == null) {
+ return;
+ }
+ if (nri.mUidTrackedForBlockedStatus) {
+ Log.wtf(TAG, "Nri is already tracked for sending blocked status: " + nri);
+ return;
+ }
+ nri.mUidTrackedForBlockedStatus = true;
+ synchronized (mBlockedStatusTrackingUids) {
+ final int uid = nri.mAsUid;
+ final int count = mBlockedStatusTrackingUids.get(uid, 0);
+ if (count == 0) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_BLOCKED_REASONS_CHANGED,
+ List.of(new Pair<>(uid, mBpfNetMaps.getUidNetworkingBlockedReasons(uid)))));
+ }
+ mBlockedStatusTrackingUids.put(uid, count + 1);
+ }
+ }
+
+ private void trackUidAndRegisterNetworkRequest(final int event, NetworkRequestInfo nri) {
+ // Post the update of the UID's blocked reasons before posting the message that registers
+ // the callback. This is necessary because if the callback immediately matches a request,
+ // the onBlockedStatusChanged must be called with the correct blocked reasons.
+ // Also, once trackUidAndMaybePostCurrentBlockedReason is called, the register network
+ // request event must be posted, because otherwise the counter for uid will never be
+ // decremented.
+ trackUidAndMaybePostCurrentBlockedReason(nri);
+ mHandler.sendMessage(mHandler.obtainMessage(event, nri));
+ }
+
+ private void maybeUntrackUidAndClearBlockedReasons(final NetworkRequestInfo nri) {
+ if (!isAppRequest(nri)) {
+ // Not an app request.
+ return;
+ }
+ nri.mPerUidCounter.decrementCount(nri.mUid);
+
+ if (!shouldTrackUidsForBlockedStatusCallbacks() || nri.mMessenger == null) {
+ return;
+ }
+ if (!nri.mUidTrackedForBlockedStatus) {
+ Log.wtf(TAG, "Nri is not tracked for sending blocked status: " + nri);
+ return;
+ }
+ nri.mUidTrackedForBlockedStatus = false;
+ synchronized (mBlockedStatusTrackingUids) {
+ final int count = mBlockedStatusTrackingUids.get(nri.mAsUid);
+ if (count > 1) {
+ mBlockedStatusTrackingUids.put(nri.mAsUid, count - 1);
+ } else {
+ mBlockedStatusTrackingUids.delete(nri.mAsUid);
+ mUidBlockedReasons.delete(nri.mAsUid);
+ }
+ }
+ }
+
@Override
public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, IBinder binder,
@@ -8076,7 +8230,7 @@
callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
+ trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_LISTENER, nri);
return networkRequest;
}
@@ -8101,8 +8255,7 @@
callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT, nri));
+ trackUidAndRegisterNetworkRequest(EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT, nri);
}
/** Returns the next Network provider ID. */
@@ -10085,7 +10238,7 @@
mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
}
mNetworkActivityTracker.updateDefaultNetwork(newDefaultNetwork, oldDefaultNetwork);
- maybeClosePendingFrozenSockets(newDefaultNetwork, oldDefaultNetwork);
+ maybeDestroyPendingSockets(newDefaultNetwork, oldDefaultNetwork);
mProxyTracker.setDefaultProxy(null != newDefaultNetwork
? newDefaultNetwork.linkProperties.getHttpProxy() : null);
resetHttpProxyForNonDefaultNetwork(oldDefaultNetwork);
@@ -11057,7 +11210,7 @@
final boolean metered = nai.networkCapabilities.isMetered();
final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
- getBlockedState(blockedReasons, metered, vpnBlocked));
+ getBlockedState(nri.mAsUid, blockedReasons, metered, vpnBlocked));
}
// Notify the requests on this NAI that the network is now lingered.
@@ -11066,7 +11219,21 @@
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
}
- private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
+ private int getPermissionBlockedState(final int uid, final int reasons) {
+ // Before V, the blocked reasons come from NPMS, and that code already behaves as if the
+ // change was disabled: apps without the internet permission will never be told they are
+ // blocked.
+ if (!mDeps.isAtLeastV()) return reasons;
+
+ if (hasInternetPermission(uid)) return reasons;
+
+ return mDeps.isChangeEnabled(NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION, uid)
+ ? reasons | BLOCKED_REASON_NETWORK_RESTRICTED
+ : BLOCKED_REASON_NONE;
+ }
+
+ private int getBlockedState(int uid, int reasons, boolean metered, boolean vpnBlocked) {
+ reasons = getPermissionBlockedState(uid, reasons);
if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
return vpnBlocked
? reasons | BLOCKED_REASON_LOCKDOWN_VPN
@@ -11107,8 +11274,10 @@
? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
: oldVpnBlocked;
- final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
- final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
+ final int oldBlockedState = getBlockedState(
+ nri.mAsUid, blockedReasons, oldMetered, oldVpnBlocked);
+ final int newBlockedState = getBlockedState(
+ nri.mAsUid, blockedReasons, newMetered, newVpnBlocked);
if (oldBlockedState != newBlockedState) {
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
newBlockedState);
@@ -11127,8 +11296,9 @@
final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
final int oldBlockedState = getBlockedState(
- mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
- final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
+ uid, mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
+ final int newBlockedState =
+ getBlockedState(uid, blockedReasons, metered, vpnBlocked);
if (oldBlockedState == newBlockedState) {
continue;
}
@@ -12164,6 +12334,7 @@
// handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
// callback's binder death.
final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId);
+ nri.mPerUidCounter.incrementCountOrThrow(nri.mUid);
final ConnectivityDiagnosticsCallbackInfo cbInfo =
new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName);
@@ -13258,7 +13429,20 @@
final ArraySet<NetworkRequestInfo> perAppCallbackRequestsToUpdate =
getPerAppCallbackRequestsToUpdate();
final ArraySet<NetworkRequestInfo> nrisToRegister = new ArraySet<>(nris);
- handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
+ // This method does not need to modify perUidCounter and mBlockedStatusTrackingUids because:
+ // - |nris| only contains per-app network requests created by ConnectivityService which
+ // are internal requests and have no messenger and are not associated with any callbacks,
+ // and so do not need to be tracked in perUidCounter and mBlockedStatusTrackingUids.
+ // - The requests in perAppCallbackRequestsToUpdate are removed, modified, and re-added,
+ // but the same number of requests is removed and re-added, and none of the requests
+ // changes mUid and mAsUid, so the perUidCounter and mBlockedStatusTrackingUids before
+ // and after this method remains the same. Re-adding the requests does not modify
+ // perUidCounter and mBlockedStatusTrackingUids (that is done when the app registers the
+ // request), so removing them must not modify perUidCounter and mBlockedStatusTrackingUids
+ // either.
+ // TODO(b/341228979): Modify nris in place instead of removing them and re-adding them
+ handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate,
+ false /* untrackUids */);
nrisToRegister.addAll(
createPerAppCallbackRequestsToRegister(perAppCallbackRequestsToUpdate));
handleRegisterNetworkRequests(nrisToRegister);
@@ -13493,10 +13677,17 @@
throw new IllegalStateException(e);
}
- try {
- mBpfNetMaps.setDataSaverEnabled(enable);
- } catch (ServiceSpecificException | UnsupportedOperationException e) {
- Log.e(TAG, "Failed to set data saver " + enable + " : " + e);
+ synchronized (mBlockedStatusTrackingUids) {
+ try {
+ mBpfNetMaps.setDataSaverEnabled(enable);
+ } catch (ServiceSpecificException | UnsupportedOperationException e) {
+ Log.e(TAG, "Failed to set data saver " + enable + " : " + e);
+ return;
+ }
+
+ if (shouldTrackUidsForBlockedStatusCallbacks()) {
+ updateTrackingUidsBlockedReasons();
+ }
}
}
@@ -13532,10 +13723,17 @@
throw new IllegalArgumentException("setUidFirewallRule with invalid rule: " + rule);
}
- try {
- mBpfNetMaps.setUidRule(chain, uid, firewallRule);
- } catch (ServiceSpecificException e) {
- throw new IllegalStateException(e);
+ synchronized (mBlockedStatusTrackingUids) {
+ try {
+ mBpfNetMaps.setUidRule(chain, uid, firewallRule);
+ } catch (ServiceSpecificException e) {
+ throw new IllegalStateException(e);
+ }
+ if (shouldTrackUidsForBlockedStatusCallbacks()
+ && mBlockedStatusTrackingUids.get(uid, 0) != 0) {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_BLOCKED_REASONS_CHANGED,
+ List.of(new Pair<>(uid, mBpfNetMaps.getUidNetworkingBlockedReasons(uid)))));
+ }
}
}
@@ -13613,10 +13811,15 @@
"Chain (" + chain + ") can not be controlled by setFirewallChainEnabled");
}
- try {
- mBpfNetMaps.setChildChain(chain, enable);
- } catch (ServiceSpecificException e) {
- throw new IllegalStateException(e);
+ synchronized (mBlockedStatusTrackingUids) {
+ try {
+ mBpfNetMaps.setChildChain(chain, enable);
+ } catch (ServiceSpecificException e) {
+ throw new IllegalStateException(e);
+ }
+ if (shouldTrackUidsForBlockedStatusCallbacks()) {
+ updateTrackingUidsBlockedReasons();
+ }
}
if (mDeps.isAtLeastU() && enable) {
@@ -13628,6 +13831,22 @@
}
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ @GuardedBy("mBlockedStatusTrackingUids")
+ private void updateTrackingUidsBlockedReasons() {
+ if (mBlockedStatusTrackingUids.size() == 0) {
+ return;
+ }
+ final ArrayList<Pair<Integer, Integer>> uidBlockedReasonsList = new ArrayList<>();
+ for (int i = 0; i < mBlockedStatusTrackingUids.size(); i++) {
+ final int uid = mBlockedStatusTrackingUids.keyAt(i);
+ uidBlockedReasonsList.add(
+ new Pair<>(uid, mBpfNetMaps.getUidNetworkingBlockedReasons(uid)));
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_BLOCKED_REASONS_CHANGED,
+ uidBlockedReasonsList));
+ }
+
@Override
public boolean getFirewallChainEnabled(final int chain) {
enforceNetworkStackOrSettingsPermission();
@@ -13652,7 +13871,13 @@
return;
}
- mBpfNetMaps.replaceUidChain(chain, uids);
+ synchronized (mBlockedStatusTrackingUids) {
+ mBpfNetMaps.replaceUidChain(chain, uids);
+
+ if (shouldTrackUidsForBlockedStatusCallbacks()) {
+ updateTrackingUidsBlockedReasons();
+ }
+ }
}
@Override
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index aec4f24..634a8fa 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -524,31 +524,6 @@
}
}
- private void maybeCleanUp(ParcelFileDescriptor tunFd, ParcelFileDescriptor readSock6,
- ParcelFileDescriptor writeSock6) {
- if (tunFd != null) {
- try {
- tunFd.close();
- } catch (IOException e) {
- Log.e(TAG, "Fail to close tun file descriptor " + e);
- }
- }
- if (readSock6 != null) {
- try {
- readSock6.close();
- } catch (IOException e) {
- Log.e(TAG, "Fail to close read socket " + e);
- }
- }
- if (writeSock6 != null) {
- try {
- writeSock6.close();
- } catch (IOException e) {
- Log.e(TAG, "Fail to close write socket " + e);
- }
- }
- }
-
private void tagSocketAsClat(long cookie) throws IOException {
if (mCookieTagMap == null) {
throw new IOException("Cookie tag map is not initialized");
@@ -604,42 +579,6 @@
throw new IOException("Prefix must be 96 bits long: " + nat64Prefix);
}
- // [1] Pick an IPv4 address from 192.0.0.4, 192.0.0.5, 192.0.0.6 ..
- final String v4Str;
- try {
- v4Str = mDeps.selectIpv4Address(INIT_V4ADDR_STRING, INIT_V4ADDR_PREFIX_LEN);
- } catch (IOException e) {
- throw new IOException("no IPv4 addresses were available for clat: " + e);
- }
-
- final Inet4Address v4;
- try {
- v4 = (Inet4Address) InetAddresses.parseNumericAddress(v4Str);
- } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- throw new IOException("Invalid IPv4 address " + v4Str);
- }
-
- // [2] Generate a checksum-neutral IID.
- final Integer fwmark = getFwmark(netId);
- final String pfx96Str = nat64Prefix.getAddress().getHostAddress();
- final String v6Str;
- try {
- v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str, fwmark);
- } catch (IOException e) {
- throw new IOException("no IPv6 addresses were available for clat: " + e);
- }
-
- final Inet6Address pfx96 = (Inet6Address) nat64Prefix.getAddress();
- final Inet6Address v6;
- try {
- v6 = (Inet6Address) InetAddresses.parseNumericAddress(v6Str);
- } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- throw new IOException("Invalid IPv6 address " + v6Str);
- }
-
- // [3] Open, configure and bring up the tun interface.
- // Create the v4-... tun interface.
-
// Initialize all required file descriptors with null pointer. This makes the following
// error handling easier. Simply always call #maybeCleanUp for closing file descriptors,
// if any valid ones, in error handling.
@@ -647,145 +586,112 @@
ParcelFileDescriptor readSock6 = null;
ParcelFileDescriptor writeSock6 = null;
- final String tunIface = CLAT_PREFIX + iface;
- try {
- tunFd = mDeps.adoptFd(mDeps.createTunInterface(tunIface));
- } catch (IOException e) {
- throw new IOException("Create tun interface " + tunIface + " failed: " + e);
- }
+ long cookie = 0;
+ boolean isSocketTagged = false;
- final int tunIfIndex = mDeps.getInterfaceIndex(tunIface);
- if (tunIfIndex == INVALID_IFINDEX) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Fail to get interface index for interface " + tunIface);
- }
+ try {
+ // [1] Pick an IPv4 address from 192.0.0.4, 192.0.0.5, 192.0.0.6 ..
+ final String v4Str = mDeps.selectIpv4Address(INIT_V4ADDR_STRING,
+ INIT_V4ADDR_PREFIX_LEN);
+ final Inet4Address v4 = (Inet4Address) InetAddresses.parseNumericAddress(v4Str);
- // disable IPv6 on it - failing to do so is not a critical error
- try {
- mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Disable IPv6 on " + tunIface + " failed: " + e);
- }
+ // [2] Generate a checksum-neutral IID.
+ final Integer fwmark = getFwmark(netId);
+ final String pfx96Str = nat64Prefix.getAddress().getHostAddress();
+ final String v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str, fwmark);
+ final Inet6Address pfx96 = (Inet6Address) nat64Prefix.getAddress();
+ final Inet6Address v6 = (Inet6Address) InetAddresses.parseNumericAddress(v6Str);
- // Detect ipv4 mtu.
- final int detectedMtu;
- try {
- detectedMtu = mDeps.detectMtu(pfx96Str,
- ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark);
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Detect MTU on " + tunIface + " failed: " + e);
- }
- final int mtu = adjustMtu(detectedMtu);
- Log.i(TAG, "detected ipv4 mtu of " + detectedMtu + " adjusted to " + mtu);
+ // [3] Open and configure local 464xlat read/write sockets.
+ // Opens a packet socket to receive IPv6 packets in clatd.
- // Config tun interface mtu, address and bring up.
- try {
- mNetd.interfaceSetMtu(tunIface, mtu);
- } catch (RemoteException | ServiceSpecificException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Set MTU " + mtu + " on " + tunIface + " failed: " + e);
- }
- final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
- ifConfig.ifName = tunIface;
- ifConfig.ipv4Addr = v4Str;
- ifConfig.prefixLength = 32;
- ifConfig.hwAddr = "";
- ifConfig.flags = new String[] {IF_STATE_UP};
- try {
- mNetd.interfaceSetCfg(ifConfig);
- } catch (RemoteException | ServiceSpecificException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Setting IPv4 address to " + ifConfig.ipv4Addr + "/"
- + ifConfig.prefixLength + " failed on " + ifConfig.ifName + ": " + e);
- }
-
- // [4] Open and configure local 464xlat read/write sockets.
- // Opens a packet socket to receive IPv6 packets in clatd.
- try {
// Use a JNI call to get native file descriptor instead of Os.socket() because we would
// like to use ParcelFileDescriptor to manage file descriptor. But ctor
// ParcelFileDescriptor(FileDescriptor fd) is a @hide function. Need to use native file
// descriptor to initialize ParcelFileDescriptor object instead.
readSock6 = mDeps.adoptFd(mDeps.openPacketSocket());
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Open packet socket failed: " + e);
- }
- // Opens a raw socket with a given fwmark to send IPv6 packets in clatd.
- try {
+ // Opens a raw socket with a given fwmark to send IPv6 packets in clatd.
// Use a JNI call to get native file descriptor instead of Os.socket(). See above
// reason why we use jniOpenPacketSocket6().
writeSock6 = mDeps.adoptFd(mDeps.openRawSocket6(fwmark));
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Open raw socket failed: " + e);
- }
- final int ifIndex = mDeps.getInterfaceIndex(iface);
- if (ifIndex == INVALID_IFINDEX) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("Fail to get interface index for interface " + iface);
- }
+ final int ifIndex = mDeps.getInterfaceIndex(iface);
+ if (ifIndex == INVALID_IFINDEX) {
+ throw new IOException("Fail to get interface index for interface " + iface);
+ }
- // Start translating packets to the new prefix.
- try {
+ // Start translating packets to the new prefix.
mDeps.addAnycastSetsockopt(writeSock6.getFileDescriptor(), v6Str, ifIndex);
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("add anycast sockopt failed: " + e);
- }
-
- // Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
- final long cookie;
- try {
+ // Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
cookie = mDeps.getSocketCookie(writeSock6.getFileDescriptor());
tagSocketAsClat(cookie);
- } catch (IOException e) {
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("tag raw socket failed: " + e);
- }
-
- // Update our packet socket filter to reflect the new 464xlat IP address.
- try {
+ isSocketTagged = true;
+ // Update our packet socket filter to reflect the new 464xlat IP address.
mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6Str, ifIndex);
- } catch (IOException e) {
- try {
- untagSocket(cookie);
- } catch (IOException e2) {
- Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+
+ // [4] Open, configure and bring up the tun interface.
+ // Create the v4-... tun interface.
+ final String tunIface = CLAT_PREFIX + iface;
+ tunFd = mDeps.adoptFd(mDeps.createTunInterface(tunIface));
+ final int tunIfIndex = mDeps.getInterfaceIndex(tunIface);
+ if (tunIfIndex == INVALID_IFINDEX) {
+ throw new IOException("Fail to get interface index for interface " + tunIface);
}
- maybeCleanUp(tunFd, readSock6, writeSock6);
- throw new IOException("configure packet socket failed: " + e);
- }
+ // disable IPv6 on it - failing to do so is not a critical error
+ mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
+ // Detect ipv4 mtu.
+ final int detectedMtu = mDeps.detectMtu(pfx96Str,
+ ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark);
+ final int mtu = adjustMtu(detectedMtu);
+ Log.i(TAG, "detected ipv4 mtu of " + detectedMtu + " adjusted to " + mtu);
+ // Config tun interface mtu, address and bring up.
+ mNetd.interfaceSetMtu(tunIface, mtu);
+ final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
+ ifConfig.ifName = tunIface;
+ ifConfig.ipv4Addr = v4Str;
+ ifConfig.prefixLength = 32;
+ ifConfig.hwAddr = "";
+ ifConfig.flags = new String[] {IF_STATE_UP};
+ mNetd.interfaceSetCfg(ifConfig);
- // [5] Start clatd.
- final int pid;
- try {
- pid = mDeps.startClatd(tunFd.getFileDescriptor(), readSock6.getFileDescriptor(),
- writeSock6.getFileDescriptor(), iface, pfx96Str, v4Str, v6Str);
- } catch (IOException e) {
- try {
- untagSocket(cookie);
- } catch (IOException e2) {
- Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+ // [5] Start clatd.
+ final int pid = mDeps.startClatd(tunFd.getFileDescriptor(),
+ readSock6.getFileDescriptor(), writeSock6.getFileDescriptor(), iface, pfx96Str,
+ v4Str, v6Str);
+
+ // [6] Initialize and store clatd tracker object.
+ mClatdTracker = new ClatdTracker(iface, ifIndex, tunIface, tunIfIndex, v4, v6, pfx96,
+ pid, cookie);
+
+ // [7] Start BPF
+ maybeStartBpf(mClatdTracker);
+
+ return v6Str;
+ } catch (IOException | RemoteException | ServiceSpecificException | ClassCastException
+ | IllegalArgumentException | NullPointerException e) {
+ if (isSocketTagged) {
+ try {
+ untagSocket(cookie);
+ } catch (IOException e2) {
+ Log.e(TAG, "untagSocket cookie " + cookie + " failed: " + e2);
+ }
}
- throw new IOException("Error start clatd on " + iface + ": " + e);
- } finally {
- // The file descriptors have been duplicated (dup2) to clatd in native_startClatd().
- // Close these file descriptor stubs which are unused anymore.
- maybeCleanUp(tunFd, readSock6, writeSock6);
+ try {
+ if (tunFd != null) {
+ tunFd.close();
+ }
+ if (readSock6 != null) {
+ readSock6.close();
+ }
+ if (writeSock6 != null) {
+ writeSock6.close();
+ }
+ } catch (IOException e2) {
+ Log.e(TAG, "Fail to cleanup fd ", e);
+ }
+ throw new IOException("Failed to start clat ", e);
}
-
- // [6] Initialize and store clatd tracker object.
- mClatdTracker = new ClatdTracker(iface, ifIndex, tunIface, tunIfIndex, v4, v6, pfx96,
- pid, cookie);
-
- // [7] Start BPF
- maybeStartBpf(mClatdTracker);
-
- return v6Str;
}
private void maybeStopBpf(final ClatdTracker tracker) {
diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java
index 176307d..7ea7f95 100644
--- a/service/src/com/android/server/connectivity/ConnectivityFlags.java
+++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java
@@ -44,6 +44,8 @@
public static final String BACKGROUND_FIREWALL_CHAIN = "background_firewall_chain";
+ public static final String DELAY_DESTROY_SOCKETS = "delay_destroy_sockets";
+
private boolean mNoRematchAllRequestsOnRegister;
/**
diff --git a/service/src/com/android/server/connectivity/DnsManager.java b/service/src/com/android/server/connectivity/DnsManager.java
index 8e6854a..ac02229 100644
--- a/service/src/com/android/server/connectivity/DnsManager.java
+++ b/service/src/com/android/server/connectivity/DnsManager.java
@@ -390,6 +390,7 @@
: new String[0]; // Off
paramsParcel.transportTypes = nc.getTransportTypes();
paramsParcel.meteredNetwork = nc.isMetered();
+ paramsParcel.interfaceNames = lp.getAllInterfaceNames().toArray(new String[0]);
// Prepare to track the validation status of the DNS servers in the
// resolver config when private DNS is in opportunistic or strict mode.
if (useTls) {
@@ -403,13 +404,14 @@
}
Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
- + "%d, %d, %s, %s, %s, %b)", paramsParcel.netId,
+ + "%d, %d, %s, %s, %s, %b, %s)", paramsParcel.netId,
Arrays.toString(paramsParcel.servers), Arrays.toString(paramsParcel.domains),
paramsParcel.sampleValiditySeconds, paramsParcel.successThreshold,
paramsParcel.minSamples, paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec,
paramsParcel.retryCount, paramsParcel.tlsName,
Arrays.toString(paramsParcel.tlsServers),
- Arrays.toString(paramsParcel.transportTypes), paramsParcel.meteredNetwork));
+ Arrays.toString(paramsParcel.transportTypes), paramsParcel.meteredNetwork,
+ Arrays.toString(paramsParcel.interfaceNames)));
try {
mDnsResolver.setResolverConfiguration(paramsParcel);
diff --git a/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java b/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java
index ac479b8..af4aee5 100644
--- a/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java
+++ b/service/src/com/android/server/connectivity/MulticastRoutingCoordinatorService.java
@@ -168,14 +168,18 @@
public void applyMulticastRoutingConfig(
final String iifName, final String oifName, final MulticastRoutingConfig newConfig) {
checkOnHandlerThread();
+ Objects.requireNonNull(iifName, "IifName can't be null");
+ Objects.requireNonNull(oifName, "OifName can't be null");
if (newConfig.getForwardingMode() != FORWARD_NONE) {
// Make sure iif and oif are added as multicast forwarding interfaces
- try {
- maybeAddAndTrackInterface(iifName);
- maybeAddAndTrackInterface(oifName);
- } catch (IllegalStateException e) {
- Log.e(TAG, "Failed to apply multicast routing config, ", e);
+ if (!maybeAddAndTrackInterface(iifName) || !maybeAddAndTrackInterface(oifName)) {
+ Log.e(
+ TAG,
+ "Failed to apply multicast routing config from "
+ + iifName
+ + " to "
+ + oifName);
return;
}
}
@@ -258,9 +262,14 @@
}
}
+ /**
+ * Returns the next available virtual index for multicast routing, or -1 if the number of
+ * virtual interfaces has reached max value.
+ */
private int getNextAvailableVirtualIndex() {
if (mVirtualInterfaces.size() >= MAX_NUM_OF_MULTICAST_VIRTUAL_INTERFACES) {
- throw new IllegalStateException("Can't allocate new multicast virtual interface");
+ Log.e(TAG, "Can't allocate new multicast virtual interface");
+ return -1;
}
for (int i = 0; i < mVirtualInterfaces.size(); i++) {
if (!mVirtualInterfaces.contains(i)) {
@@ -291,12 +300,23 @@
return mVirtualInterfaces.get(virtualIndex);
}
- private void maybeAddAndTrackInterface(String ifName) {
+ /**
+ * Returns {@code true} if the interfaces is added and tracked, or {@code false} when failed
+ * to add the interface.
+ */
+ private boolean maybeAddAndTrackInterface(String ifName) {
checkOnHandlerThread();
- if (getIndexForValue(mVirtualInterfaces, ifName) >= 0) return;
+ if (getIndexForValue(mVirtualInterfaces, ifName) >= 0) return true;
int nextVirtualIndex = getNextAvailableVirtualIndex();
+ if (nextVirtualIndex < 0) {
+ return false;
+ }
int ifIndex = mDependencies.getInterfaceIndex(ifName);
+ if (ifIndex == 0) {
+ Log.e(TAG, "Can't get interface index for " + ifName);
+ return false;
+ }
final StructMif6ctl mif6ctl =
new StructMif6ctl(
nextVirtualIndex,
@@ -309,10 +329,11 @@
Log.d(TAG, "Added mifi " + nextVirtualIndex + " to MIF");
} catch (ErrnoException e) {
Log.e(TAG, "failed to add multicast virtual interface", e);
- return;
+ return false;
}
mVirtualInterfaces.put(nextVirtualIndex, ifName);
mInterfaces.put(ifIndex, ifName);
+ return true;
}
@VisibleForTesting
@@ -798,13 +819,12 @@
NetworkUtils.setsockoptBytes(fd, IPPROTO_IPV6, MRT6_DEL_MFC, bytes);
}
- public Integer getInterfaceIndex(String ifName) {
- try {
- NetworkInterface ni = NetworkInterface.getByName(ifName);
- return ni.getIndex();
- } catch (NullPointerException | SocketException e) {
- return null;
- }
+ /**
+ * Returns the interface index for an interface name, or 0 if the interface index could
+ * not be found.
+ */
+ public int getInterfaceIndex(String ifName) {
+ return Os.if_nametoindex(ifName);
}
public NetworkInterface getNetworkInterface(int physicalIndex) {
diff --git a/service/src/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
index 065922d..489dab5 100644
--- a/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ b/service/src/com/android/server/connectivity/Nat464Xlat.java
@@ -202,13 +202,13 @@
try {
addrStr = mClatCoordinator.clatStart(baseIface, getNetId(), mNat64PrefixInUse);
} catch (IOException e) {
- Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+ Log.e(TAG, "Error starting clatd on " + baseIface, e);
}
} else {
try {
addrStr = mNetd.clatdStart(baseIface, mNat64PrefixInUse.toString());
} catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+ Log.e(TAG, "Error starting clatd on " + baseIface, e);
}
}
mIface = CLAT_PREFIX + baseIface;
@@ -217,7 +217,7 @@
try {
mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
} catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- Log.e(TAG, "Invalid IPv6 address " + addrStr);
+ Log.e(TAG, "Invalid IPv6 address " + addrStr , e);
}
if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
stopPrefixDiscovery();
diff --git a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
index 92ec0c4..df7010e 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java
@@ -41,6 +41,10 @@
public static final short IFLA_ADDRESS = 1;
public static final short IFLA_IFNAME = 3;
public static final short IFLA_MTU = 4;
+ public static final short IFLA_INET6_ADDR_GEN_MODE = 8;
+ public static final short IFLA_AF_SPEC = 26;
+
+ public static final short IN6_ADDR_GEN_MODE_NONE = 1;
private int mMtu;
@NonNull
diff --git a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
index 02d1574..28eeaea 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/StructIfinfoMsg.java
@@ -49,7 +49,7 @@
@Field(order = 4, type = Type.U32)
public final long change;
- StructIfinfoMsg(short family, int type, int index, long flags, long change) {
+ public StructIfinfoMsg(short family, int type, int index, long flags, long change) {
this.family = family;
this.type = type;
this.index = index;
diff --git a/staticlibs/native/bpfmapjni/Android.bp b/staticlibs/native/bpfmapjni/Android.bp
index 7e6b4ec..969ebd4 100644
--- a/staticlibs/native/bpfmapjni/Android.bp
+++ b/staticlibs/native/bpfmapjni/Android.bp
@@ -39,7 +39,7 @@
"-Werror",
"-Wno-unused-parameter",
],
- sdk_version: "30",
+ sdk_version: "current",
min_sdk_version: "30",
apex_available: [
"com.android.tethering",
diff --git a/staticlibs/native/tcutils/Android.bp b/staticlibs/native/tcutils/Android.bp
index 926590d..e4742ce 100644
--- a/staticlibs/native/tcutils/Android.bp
+++ b/staticlibs/native/tcutils/Android.bp
@@ -21,7 +21,10 @@
name: "libtcutils",
srcs: ["tcutils.cpp"],
export_include_dirs: ["include"],
- header_libs: ["bpf_headers"],
+ header_libs: [
+ "bpf_headers",
+ "libbase_headers",
+ ],
shared_libs: [
"liblog",
],
@@ -31,7 +34,7 @@
"-Werror",
"-Wno-unused-parameter",
],
- sdk_version: "30",
+ sdk_version: "current",
min_sdk_version: "30",
apex_available: [
"com.android.tethering",
diff --git a/staticlibs/native/tcutils/scopeguard.h b/staticlibs/native/tcutils/scopeguard.h
deleted file mode 100644
index 76bbb93..0000000
--- a/staticlibs/native/tcutils/scopeguard.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-// -----------------------------------------------------------------------------
-// TODO: figure out a way to use libbase_ndk. This is currently not working
-// because of missing apex availability. For now, we can use a copy of
-// ScopeGuard which is very lean compared to unique_fd. This code has been
-// copied verbatim from:
-// https://cs.android.com/android/platform/superproject/+/master:system/libbase/include/android-base/scopeguard.h
-
-#pragma once
-
-#include <utility> // for std::move, std::forward
-
-namespace android {
-namespace base {
-
-// ScopeGuard ensures that the specified functor is executed no matter how the
-// current scope exits.
-template <typename F> class ScopeGuard {
-public:
- ScopeGuard(F &&f) : f_(std::forward<F>(f)), active_(true) {}
-
- ScopeGuard(ScopeGuard &&that) noexcept
- : f_(std::move(that.f_)), active_(that.active_) {
- that.active_ = false;
- }
-
- template <typename Functor>
- ScopeGuard(ScopeGuard<Functor> &&that)
- : f_(std::move(that.f_)), active_(that.active_) {
- that.active_ = false;
- }
-
- ~ScopeGuard() {
- if (active_)
- f_();
- }
-
- ScopeGuard() = delete;
- ScopeGuard(const ScopeGuard &) = delete;
- void operator=(const ScopeGuard &) = delete;
- void operator=(ScopeGuard &&that) = delete;
-
- void Disable() { active_ = false; }
-
- bool active() const { return active_; }
-
-private:
- template <typename Functor> friend class ScopeGuard;
-
- F f_;
- bool active_;
-};
-
-template <typename F> ScopeGuard<F> make_scope_guard(F &&f) {
- return ScopeGuard<F>(std::forward<F>(f));
-}
-
-} // namespace base
-} // namespace android
diff --git a/staticlibs/native/tcutils/tcutils.cpp b/staticlibs/native/tcutils/tcutils.cpp
index c82390f..21e781c 100644
--- a/staticlibs/native/tcutils/tcutils.cpp
+++ b/staticlibs/native/tcutils/tcutils.cpp
@@ -20,8 +20,10 @@
#include "logging.h"
#include "bpf/KernelUtils.h"
-#include "scopeguard.h"
+#include <BpfSyscallWrappers.h>
+#include <android-base/scopeguard.h>
+#include <android-base/unique_fd.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
@@ -39,10 +41,6 @@
#include <unistd.h>
#include <utility>
-#define BPF_FD_JUST_USE_INT
-#include <BpfSyscallWrappers.h>
-#undef BPF_FD_JUST_USE_INT
-
// The maximum length of TCA_BPF_NAME. Sync from net/sched/cls_bpf.c.
#define CLS_BPF_NAME_LEN 256
@@ -52,6 +50,9 @@
namespace android {
namespace {
+using base::make_scope_guard;
+using base::unique_fd;
+
/**
* IngressPoliceFilterBuilder builds a nlmsg request equivalent to the following
* tc command:
@@ -130,7 +131,7 @@
// class members
const unsigned mBurstInBytes;
const char *mBpfProgPath;
- int mBpfFd;
+ unique_fd mBpfFd;
Request mRequest;
static double getTickInUsec() {
@@ -139,7 +140,7 @@
ALOGE("fopen(\"/proc/net/psched\"): %s", strerror(errno));
return 0.0;
}
- auto scopeGuard = base::make_scope_guard([fp] { fclose(fp); });
+ auto scopeGuard = make_scope_guard([fp] { fclose(fp); });
uint32_t t2us;
uint32_t us2t;
@@ -166,7 +167,6 @@
unsigned burstInBytes, const char* bpfProgPath)
: mBurstInBytes(burstInBytes),
mBpfProgPath(bpfProgPath),
- mBpfFd(-1),
mRequest{
.n = {
.nlmsg_len = sizeof(mRequest),
@@ -298,13 +298,6 @@
}
// clang-format on
- ~IngressPoliceFilterBuilder() {
- // TODO: use unique_fd
- if (mBpfFd != -1) {
- close(mBpfFd);
- }
- }
-
constexpr unsigned getRequestSize() const { return sizeof(Request); }
private:
@@ -332,14 +325,14 @@
}
int initBpfFd() {
- mBpfFd = bpf::retrieveProgram(mBpfProgPath);
- if (mBpfFd == -1) {
+ mBpfFd.reset(bpf::retrieveProgram(mBpfProgPath));
+ if (!mBpfFd.ok()) {
int error = errno;
ALOGE("retrieveProgram failed: %d", error);
return -error;
}
- mRequest.opt.acts.act2.opt.fd.u32 = static_cast<uint32_t>(mBpfFd);
+ mRequest.opt.acts.act2.opt.fd.u32 = static_cast<uint32_t>(mBpfFd.get());
snprintf(mRequest.opt.acts.act2.opt.name.str,
sizeof(mRequest.opt.acts.act2.opt.name.str), "%s:[*fsobj]",
basename(mBpfProgPath));
@@ -370,14 +363,13 @@
int sendAndProcessNetlinkResponse(const void *req, int len) {
// TODO: use unique_fd instead of ScopeGuard
- int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
- if (fd == -1) {
+ unique_fd fd(socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE));
+ if (!fd.ok()) {
int error = errno;
ALOGE("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE): %d",
error);
return -error;
}
- auto scopeGuard = base::make_scope_guard([fd] { close(fd); });
static constexpr int on = 1;
if (setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on))) {
@@ -460,10 +452,9 @@
}
int hardwareAddressType(const char *interface) {
- int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (fd < 0)
+ unique_fd fd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+ if (!fd.ok())
return -errno;
- auto scopeGuard = base::make_scope_guard([fd] { close(fd); });
struct ifreq ifr = {};
// We use strncpy() instead of strlcpy() since kernel has to be able
@@ -576,12 +567,11 @@
// /sys/fs/bpf/... direct-action
int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
const char *bpfProgPath) {
- const int bpfFd = bpf::retrieveProgram(bpfProgPath);
- if (bpfFd == -1) {
+ unique_fd bpfFd(bpf::retrieveProgram(bpfProgPath));
+ if (!bpfFd.ok()) {
ALOGE("retrieveProgram failed: %d", errno);
return -errno;
}
- auto scopeGuard = base::make_scope_guard([bpfFd] { close(bpfFd); });
struct {
nlmsghdr n;
diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp
index 59ef20d..44abba2 100644
--- a/staticlibs/netd/Android.bp
+++ b/staticlibs/netd/Android.bp
@@ -22,7 +22,7 @@
sdk_version: "system_current",
min_sdk_version: "30",
static_libs: [
- "netd_aidl_interface-V14-java",
+ "netd_aidl_interface-V15-java",
],
apex_available: [
"//apex_available:platform", // used from services.net
@@ -45,7 +45,7 @@
cc_library_static {
name: "netd_aidl_interface-lateststable-ndk",
whole_static_libs: [
- "netd_aidl_interface-V14-ndk",
+ "netd_aidl_interface-V15-ndk",
],
apex_available: [
"com.android.resolv",
@@ -56,12 +56,12 @@
cc_defaults {
name: "netd_aidl_interface_lateststable_cpp_static",
- static_libs: ["netd_aidl_interface-V14-cpp"],
+ static_libs: ["netd_aidl_interface-V15-cpp"],
}
cc_defaults {
name: "netd_aidl_interface_lateststable_cpp_shared",
- shared_libs: ["netd_aidl_interface-V14-cpp"],
+ shared_libs: ["netd_aidl_interface-V15-cpp"],
}
aidl_interface {
@@ -167,6 +167,10 @@
version: "14",
imports: [],
},
+ {
+ version: "15",
+ imports: [],
+ },
],
frozen: true,
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/15/.hash
new file mode 100644
index 0000000..afdadcc
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/.hash
@@ -0,0 +1 @@
+2be6ff6fb01645cdddb3bb60f6de5727e5733267
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/INetd.aidl
new file mode 100644
index 0000000..80b3b62
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/INetd.aidl
@@ -0,0 +1,260 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetd {
+ boolean isAlive();
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
+ boolean bandwidthEnableDataSaver(boolean enable);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
+ void networkCreatePhysical(int netId, int permission);
+ /**
+ * @deprecated use networkCreate() instead.
+ */
+ void networkCreateVpn(int netId, boolean secure);
+ void networkDestroy(int netId);
+ void networkAddInterface(int netId, in @utf8InCpp String iface);
+ void networkRemoveInterface(int netId, in @utf8InCpp String iface);
+ void networkAddUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRemoveUidRanges(int netId, in android.net.UidRangeParcel[] uidRanges);
+ void networkRejectNonSecureVpn(boolean add, in android.net.UidRangeParcel[] uidRanges);
+ void socketDestroy(in android.net.UidRangeParcel[] uidRanges, in int[] exemptUids);
+ boolean tetherApplyDnsInterfaces();
+ android.net.TetherStatsParcel[] tetherGetStats();
+ void interfaceAddAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString, int prefixLength);
+ @utf8InCpp String getProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter);
+ void setProcSysNet(int ipversion, int which, in @utf8InCpp String ifname, in @utf8InCpp String parameter, in @utf8InCpp String value);
+ void ipSecSetEncapSocketOwner(in ParcelFileDescriptor socket, int newUid);
+ int ipSecAllocateSpi(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecAddSecurityAssociation(int transformId, int mode, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int underlyingNetId, int spi, int markValue, int markMask, in @utf8InCpp String authAlgo, in byte[] authKey, in int authTruncBits, in @utf8InCpp String cryptAlgo, in byte[] cryptKey, in int cryptTruncBits, in @utf8InCpp String aeadAlgo, in byte[] aeadKey, in int aeadIcvBits, int encapType, int encapLocalPort, int encapRemotePort, int interfaceId);
+ void ipSecDeleteSecurityAssociation(int transformId, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecApplyTransportModeTransform(in ParcelFileDescriptor socket, int transformId, int direction, in @utf8InCpp String sourceAddress, in @utf8InCpp String destinationAddress, int spi);
+ void ipSecRemoveTransportModeTransform(in ParcelFileDescriptor socket);
+ void ipSecAddSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecUpdateSecurityPolicy(int transformId, int selAddrFamily, int direction, in @utf8InCpp String tmplSrcAddress, in @utf8InCpp String tmplDstAddress, int spi, int markValue, int markMask, int interfaceId);
+ void ipSecDeleteSecurityPolicy(int transformId, int selAddrFamily, int direction, int markValue, int markMask, int interfaceId);
+ void ipSecAddTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecUpdateTunnelInterface(in @utf8InCpp String deviceName, in @utf8InCpp String localAddress, in @utf8InCpp String remoteAddress, int iKey, int oKey, int interfaceId);
+ void ipSecRemoveTunnelInterface(in @utf8InCpp String deviceName);
+ void wakeupAddInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void wakeupDelInterface(in @utf8InCpp String ifName, in @utf8InCpp String prefix, int mark, int mask);
+ void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
+ void idletimerAddInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void idletimerRemoveInterface(in @utf8InCpp String ifName, int timeout, in @utf8InCpp String classLabel);
+ void strictUidCleartextPenalty(int uid, int policyPenalty);
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator.
+ */
+ @utf8InCpp String clatdStart(in @utf8InCpp String ifName, in @utf8InCpp String nat64Prefix);
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The clatd control plane moved to the mainline module starting in T. See ClatCoordinator.
+ */
+ void clatdStop(in @utf8InCpp String ifName);
+ boolean ipfwdEnabled();
+ @utf8InCpp String[] ipfwdGetRequesterList();
+ void ipfwdEnableForwarding(in @utf8InCpp String requester);
+ void ipfwdDisableForwarding(in @utf8InCpp String requester);
+ void ipfwdAddInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void ipfwdRemoveInterfaceForward(in @utf8InCpp String fromIface, in @utf8InCpp String toIface);
+ void bandwidthSetInterfaceQuota(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceQuota(in @utf8InCpp String ifName);
+ void bandwidthSetInterfaceAlert(in @utf8InCpp String ifName, long bytes);
+ void bandwidthRemoveInterfaceAlert(in @utf8InCpp String ifName);
+ void bandwidthSetGlobalAlert(long bytes);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void bandwidthAddNaughtyApp(int uid);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void bandwidthRemoveNaughtyApp(int uid);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void bandwidthAddNiceApp(int uid);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void bandwidthRemoveNiceApp(int uid);
+ void tetherStart(in @utf8InCpp String[] dhcpRanges);
+ void tetherStop();
+ boolean tetherIsEnabled();
+ void tetherInterfaceAdd(in @utf8InCpp String ifName);
+ void tetherInterfaceRemove(in @utf8InCpp String ifName);
+ @utf8InCpp String[] tetherInterfaceList();
+ void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs);
+ @utf8InCpp String[] tetherDnsList();
+ void networkAddRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkRemoveRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop);
+ void networkAddLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ void networkRemoveLegacyRoute(int netId, in @utf8InCpp String ifName, in @utf8InCpp String destination, in @utf8InCpp String nextHop, int uid);
+ int networkGetDefault();
+ void networkSetDefault(int netId);
+ void networkClearDefault();
+ void networkSetPermissionForNetwork(int netId, int permission);
+ void networkSetPermissionForUser(int permission, in int[] uids);
+ void networkClearPermissionForUser(in int[] uids);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void trafficSetNetPermForUids(int permission, in int[] uids);
+ void networkSetProtectAllow(int uid);
+ void networkSetProtectDeny(int uid);
+ boolean networkCanProtect(int uid);
+ void firewallSetFirewallType(int firewalltype);
+ void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void firewallSetUidRule(int childChain, int uid, int firewallRule);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void firewallEnableChildChain(int childChain, boolean enable);
+ @utf8InCpp String[] interfaceGetList();
+ android.net.InterfaceConfigurationParcel interfaceGetCfg(in @utf8InCpp String ifName);
+ void interfaceSetCfg(in android.net.InterfaceConfigurationParcel cfg);
+ void interfaceSetIPv6PrivacyExtensions(in @utf8InCpp String ifName, boolean enable);
+ void interfaceClearAddrs(in @utf8InCpp String ifName);
+ void interfaceSetEnableIPv6(in @utf8InCpp String ifName, boolean enable);
+ void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+ void tetherAddForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void tetherRemoveForward(in @utf8InCpp String intIface, in @utf8InCpp String extIface);
+ void setTcpRWmemorySize(in @utf8InCpp String rmemValues, in @utf8InCpp String wmemValues);
+ void registerUnsolicitedEventListener(android.net.INetdUnsolicitedEventListener listener);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void firewallRemoveUidInterfaceRules(in int[] uids);
+ /**
+ * @deprecated unimplemented on T+.
+ */
+ void trafficSwapActiveStatsMap();
+ IBinder getOemNetd();
+ void tetherStartWithConfiguration(in android.net.TetherConfigParcel config);
+ android.net.MarkMaskParcel getFwmarkForNetwork(int netId);
+ void networkAddRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkUpdateRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator.
+ */
+ void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator.
+ */
+ void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator.
+ */
+ android.net.TetherStatsParcel[] tetherOffloadGetStats();
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator.
+ */
+ void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
+ /**
+ * @deprecated This method has no effect and throws UnsupportedOperationException. The mainline module accesses the BPF map directly starting in S. See BpfCoordinator.
+ */
+ android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
+ void networkCreate(in android.net.NativeNetworkConfig config);
+ void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
+ void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
+ void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo);
+ void setNetworkAllowlist(in android.net.netd.aidl.NativeUidRangeConfig[] allowedNetworks);
+ void networkAllowBypassVpnOnNetwork(boolean allow, int uid, int netId);
+ const int IPV4 = 4;
+ const int IPV6 = 6;
+ const int CONF = 1;
+ const int NEIGH = 2;
+ const String IPSEC_INTERFACE_PREFIX = "ipsec";
+ const int IPV6_ADDR_GEN_MODE_EUI64 = 0;
+ const int IPV6_ADDR_GEN_MODE_NONE = 1;
+ const int IPV6_ADDR_GEN_MODE_STABLE_PRIVACY = 2;
+ const int IPV6_ADDR_GEN_MODE_RANDOM = 3;
+ const int IPV6_ADDR_GEN_MODE_DEFAULT = 0;
+ const int PENALTY_POLICY_ACCEPT = 1;
+ const int PENALTY_POLICY_LOG = 2;
+ const int PENALTY_POLICY_REJECT = 3;
+ const int CLAT_MARK = 0xdeadc1a7;
+ const int LOCAL_NET_ID = 99;
+ const int DUMMY_NET_ID = 51;
+ const int UNREACHABLE_NET_ID = 52;
+ const String NEXTHOP_NONE = "";
+ const String NEXTHOP_UNREACHABLE = "unreachable";
+ const String NEXTHOP_THROW = "throw";
+ const int PERMISSION_NONE = 0;
+ const int PERMISSION_NETWORK = 1;
+ const int PERMISSION_SYSTEM = 2;
+ const int NO_PERMISSIONS = 0;
+ const int PERMISSION_INTERNET = 4;
+ const int PERMISSION_UPDATE_DEVICE_STATS = 8;
+ const int PERMISSION_UNINSTALLED = (-1) /* -1 */;
+ /**
+ * @deprecated use FIREWALL_ALLOWLIST.
+ */
+ const int FIREWALL_WHITELIST = 0;
+ const int FIREWALL_ALLOWLIST = 0;
+ /**
+ * @deprecated use FIREWALL_DENYLIST.
+ */
+ const int FIREWALL_BLACKLIST = 1;
+ const int FIREWALL_DENYLIST = 1;
+ const int FIREWALL_RULE_ALLOW = 1;
+ const int FIREWALL_RULE_DENY = 2;
+ const int FIREWALL_CHAIN_NONE = 0;
+ const int FIREWALL_CHAIN_DOZABLE = 1;
+ const int FIREWALL_CHAIN_STANDBY = 2;
+ const int FIREWALL_CHAIN_POWERSAVE = 3;
+ const int FIREWALL_CHAIN_RESTRICTED = 4;
+ const String IF_STATE_UP = "up";
+ const String IF_STATE_DOWN = "down";
+ const String IF_FLAG_BROADCAST = "broadcast";
+ const String IF_FLAG_LOOPBACK = "loopback";
+ const String IF_FLAG_POINTOPOINT = "point-to-point";
+ const String IF_FLAG_RUNNING = "running";
+ const String IF_FLAG_MULTICAST = "multicast";
+ const int IPSEC_DIRECTION_IN = 0;
+ const int IPSEC_DIRECTION_OUT = 1;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..31775df
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/INetdUnsolicitedEventListener.aidl
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2018, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface INetdUnsolicitedEventListener {
+ oneway void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs, int uid);
+ oneway void onQuotaLimitReached(@utf8InCpp String alertName, @utf8InCpp String ifName);
+ oneway void onInterfaceDnsServerInfo(@utf8InCpp String ifName, long lifetimeS, in @utf8InCpp String[] servers);
+ oneway void onInterfaceAddressUpdated(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAddressRemoved(@utf8InCpp String addr, @utf8InCpp String ifName, int flags, int scope);
+ oneway void onInterfaceAdded(@utf8InCpp String ifName);
+ oneway void onInterfaceRemoved(@utf8InCpp String ifName);
+ oneway void onInterfaceChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onInterfaceLinkStateChanged(@utf8InCpp String ifName, boolean up);
+ oneway void onRouteChanged(boolean updated, @utf8InCpp String route, @utf8InCpp String gateway, @utf8InCpp String ifName);
+ oneway void onStrictCleartextDetected(int uid, @utf8InCpp String hex);
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..1869d8d
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/InterfaceConfigurationParcel.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable InterfaceConfigurationParcel {
+ @utf8InCpp String ifName;
+ @utf8InCpp String hwAddr;
+ @utf8InCpp String ipv4Addr;
+ int prefixLength;
+ @utf8InCpp String[] flags;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/IpSecMigrateInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/IpSecMigrateInfoParcel.aidl
new file mode 100644
index 0000000..975a261
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/IpSecMigrateInfoParcel.aidl
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2022, 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@JavaOnlyImmutable
+parcelable IpSecMigrateInfoParcel {
+ int requestId;
+ int selAddrFamily;
+ int direction;
+ @utf8InCpp String oldSourceAddress;
+ @utf8InCpp String oldDestinationAddress;
+ @utf8InCpp String newSourceAddress;
+ @utf8InCpp String newDestinationAddress;
+ int interfaceId;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/MarkMaskParcel.aidl
new file mode 100644
index 0000000..8ea20d1
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/MarkMaskParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable MarkMaskParcel {
+ int mark;
+ int mask;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeNetworkConfig.aidl
new file mode 100644
index 0000000..77d814b
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeNetworkConfig.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeNetworkConfig {
+ int netId;
+ android.net.NativeNetworkType networkType = android.net.NativeNetworkType.PHYSICAL;
+ int permission;
+ boolean secure;
+ android.net.NativeVpnType vpnType = android.net.NativeVpnType.PLATFORM;
+ boolean excludeLocalRoutes = false;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeNetworkType.aidl
new file mode 100644
index 0000000..e77a143
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeNetworkType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@Backing(type="int")
+enum NativeNetworkType {
+ PHYSICAL = 0,
+ VIRTUAL = 1,
+ PHYSICAL_LOCAL = 2,
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeVpnType.aidl
new file mode 100644
index 0000000..8a8be83
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/NativeVpnType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+@Backing(type="int")
+enum NativeVpnType {
+ SERVICE = 1,
+ PLATFORM = 2,
+ LEGACY = 3,
+ OEM = 4,
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/RouteInfoParcel.aidl
new file mode 100644
index 0000000..5ef95e6
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/RouteInfoParcel.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+parcelable RouteInfoParcel {
+ @utf8InCpp String destination;
+ @utf8InCpp String ifName;
+ @utf8InCpp String nextHop;
+ int mtu;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherConfigParcel.aidl
new file mode 100644
index 0000000..7b39c22
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherConfigParcel.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherConfigParcel {
+ boolean usingLegacyDnsProxy;
+ @utf8InCpp String[] dhcpRanges;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 0000000..983e986
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherOffloadRuleParcel.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherOffloadRuleParcel {
+ int inputInterfaceIndex;
+ int outputInterfaceIndex;
+ byte[] destination;
+ int prefixLength;
+ byte[] srcL2Address;
+ byte[] dstL2Address;
+ int pmtu = 1500;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..5f1b722
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/TetherStatsParcel.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable TetherStatsParcel {
+ @utf8InCpp String iface;
+ long rxBytes;
+ long rxPackets;
+ long txBytes;
+ long txPackets;
+ int ifIndex = 0;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..72e987a
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/UidRangeParcel.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable UidRangeParcel {
+ int start;
+ int stop;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 0000000..9bb679f
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/15/android/net/netd/aidl/NativeUidRangeConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.netd.aidl;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeUidRangeConfig {
+ int netId;
+ android.net.UidRangeParcel[] uidRanges;
+ int subPriority;
+}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
index 8ccefb2..80b3b62 100644
--- a/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
@@ -203,6 +203,7 @@
void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
void ipSecMigrate(in android.net.IpSecMigrateInfoParcel migrateInfo);
void setNetworkAllowlist(in android.net.netd.aidl.NativeUidRangeConfig[] allowedNetworks);
+ void networkAllowBypassVpnOnNetwork(boolean allow, int uid, int netId);
const int IPV4 = 4;
const int IPV6 = 6;
const int CONF = 1;
diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl
index ee27e84..e4c63b9 100644
--- a/staticlibs/netd/binder/android/net/INetd.aidl
+++ b/staticlibs/netd/binder/android/net/INetd.aidl
@@ -1446,4 +1446,27 @@
* - subPriority: unused
*/
void setNetworkAllowlist(in NativeUidRangeConfig[] allowedNetworks);
+
+ /**
+ * Allow the UID to explicitly select the given network even if it is subject to a VPN.
+ *
+ * Throws ServiceSpecificException with error code EEXISTS when trying to add a bypass rule that
+ * already exists, and ENOENT when trying to remove a bypass rule that does not exist.
+ *
+ * netId specific bypass rules can be combined and are allowed to overlap with global VPN
+ * exclusions (by calling networkSetProtectAllow / networkSetProtectDeny, or by setting netId to
+ * 0). Adding or removing global VPN bypass rules does not affect the netId specific rules and
+ * vice versa.
+ *
+ * Note that if netId is set to 0 (NETID_UNSET) this API is equivalent to
+ * networkSetProtectAllow} / #networkSetProtectDeny.
+ *
+ * @param allow whether to allow or disallow the operation.
+ * @param uid the UID
+ * @param netId the netId that the UID is allowed to select.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ void networkAllowBypassVpnOnNetwork(boolean allow, int uid, int netId);
}
diff --git a/staticlibs/netd/libnetdutils/InternetAddresses.cpp b/staticlibs/netd/libnetdutils/InternetAddresses.cpp
index 322f1b1..6d98608 100644
--- a/staticlibs/netd/libnetdutils/InternetAddresses.cpp
+++ b/staticlibs/netd/libnetdutils/InternetAddresses.cpp
@@ -16,6 +16,7 @@
#include "netdutils/InternetAddresses.h"
+#include <stdlib.h>
#include <string>
#include <android-base/stringprintf.h>
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
index 4185b05..d5e91c2 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/SetFeatureFlagsRule.kt
@@ -24,6 +24,7 @@
* A JUnit Rule that sets feature flags based on `@FeatureFlag` annotations.
*
* This rule enables dynamic control of feature flag states during testing.
+ * And restores the original values after performing tests.
*
* **Usage:**
* ```kotlin
@@ -31,6 +32,8 @@
* @get:Rule
* val setFeatureFlagsRule = SetFeatureFlagsRule(setFlagsMethod = (name, enabled) -> {
* // Custom handling code.
+ * }, (name) -> {
+ * // Custom getter code to retrieve the original values.
* })
*
* // ... test methods with @FeatureFlag annotations
@@ -41,7 +44,10 @@
* }
* ```
*/
-class SetFeatureFlagsRule(val setFlagsMethod: (name: String, enabled: Boolean) -> Unit) : TestRule {
+class SetFeatureFlagsRule(
+ val setFlagsMethod: (name: String, enabled: Boolean?) -> Unit,
+ val getFlagsMethod: (name: String) -> Boolean?
+) : TestRule {
/**
* This annotation marks a test method as requiring a specific feature flag to be configured.
*
@@ -69,13 +75,20 @@
FeatureFlag::class.java
)
+ val valuesToBeRestored = mutableMapOf<String, Boolean?>()
for (featureFlagAnnotation in featureFlagAnnotations) {
+ valuesToBeRestored[featureFlagAnnotation.name] =
+ getFlagsMethod(featureFlagAnnotation.name)
setFlagsMethod(featureFlagAnnotation.name, featureFlagAnnotation.enabled)
}
// Execute the test method, which includes methods annotated with
// @Before, @Test and @After.
base.evaluate()
+
+ valuesToBeRestored.forEach {
+ setFlagsMethod(it.key, it.value)
+ }
}
}
}
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index 6e9d614..e95a81a 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -201,3 +201,8 @@
name: "connectivity-mainline-presubmit-java-defaults",
test_mainline_modules: mainline_presubmit_modules,
}
+
+filegroup {
+ name: "connectivity_mainline_test_map",
+ srcs: ["connectivity_mainline_test.map"],
+}
diff --git a/tests/common/connectivity_mainline_test.map b/tests/common/connectivity_mainline_test.map
new file mode 100644
index 0000000..043312e
--- /dev/null
+++ b/tests/common/connectivity_mainline_test.map
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2024 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.
+#
+
+# Some connectivity tests run on older OS versions, and for those tests, many
+# library dependencies (such as libbase and libc++) need to be linked
+# statically. The tests also need to be linked with a version script to ensure
+# that the statically-linked library isn't exported from the executable, where
+# it would override the shared libraries that the OS itself uses. See
+# b/333438055 for an example of what goes wrong when libc++ is partially
+# exported from an executable.
+{
+ local:
+ *;
+};
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 5ed4696..bf40462 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -36,11 +36,22 @@
import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_BACKGROUND;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_OEM_DENY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.ConnectivityManager.EXTRA_NETWORK;
import static android.net.ConnectivityManager.EXTRA_NETWORK_REQUEST;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_ADMIN;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
@@ -196,6 +207,7 @@
import com.android.testutils.CompatUtil;
import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DeviceConfigRule;
import com.android.testutils.DeviceInfoUtils;
@@ -2472,8 +2484,11 @@
}
}
+ // On V+, ConnectivityService generates blockedReasons based on bpf map contents even if the
+ // otherUid does not exist on device. So if allowlist chain (e.g. background chain) is enabled,
+ // blockedReasons for otherUid will not be BLOCKED_REASON_NONE.
@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
- @Test
+ @Test @IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public void testBlockedStatusCallback() throws Exception {
// Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
// shims, and @IgnoreUpTo does not check that.
@@ -3713,6 +3728,260 @@
Process.myUid() + 1, EXPECT_OPEN);
}
+ private int getBlockedReason(final int chain) {
+ switch(chain) {
+ case FIREWALL_CHAIN_DOZABLE:
+ return BLOCKED_REASON_DOZE;
+ case FIREWALL_CHAIN_POWERSAVE:
+ return BLOCKED_REASON_BATTERY_SAVER;
+ case FIREWALL_CHAIN_RESTRICTED:
+ return BLOCKED_REASON_RESTRICTED_MODE;
+ case FIREWALL_CHAIN_LOW_POWER_STANDBY:
+ return BLOCKED_REASON_LOW_POWER_STANDBY;
+ case FIREWALL_CHAIN_BACKGROUND:
+ return BLOCKED_REASON_APP_BACKGROUND;
+ case FIREWALL_CHAIN_STANDBY:
+ return BLOCKED_REASON_APP_STANDBY;
+ case FIREWALL_CHAIN_METERED_DENY_USER:
+ return BLOCKED_METERED_REASON_USER_RESTRICTED;
+ case FIREWALL_CHAIN_METERED_DENY_ADMIN:
+ return BLOCKED_METERED_REASON_ADMIN_DISABLED;
+ case FIREWALL_CHAIN_OEM_DENY_1:
+ case FIREWALL_CHAIN_OEM_DENY_2:
+ case FIREWALL_CHAIN_OEM_DENY_3:
+ return BLOCKED_REASON_OEM_DENY;
+ default:
+ throw new IllegalArgumentException(
+ "Failed to find blockedReasons for chain: " + chain);
+ }
+ }
+
+ private void doTestBlockedReasons_setUidFirewallRule(final int chain, final boolean metered)
+ throws Exception {
+ assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI));
+
+ // Store current Wi-Fi metered value and update metered value
+ final Network currentWifiNetwork = mCtsNetUtils.ensureWifiConnected();
+ final NetworkCapabilities wifiNetworkCapabilities = callWithShellPermissionIdentity(
+ () -> mCm.getNetworkCapabilities(currentWifiNetwork));
+ final String ssid = unquoteSSID(wifiNetworkCapabilities.getSsid());
+ final boolean oldMeteredValue = wifiNetworkCapabilities.isMetered();
+ final Network wifiNetwork =
+ setWifiMeteredStatusAndWait(ssid, metered, true /* waitForValidation */);
+
+ // Store current firewall chains status. This test operates on the chain that is passed in,
+ // but also always operates on FIREWALL_CHAIN_METERED_DENY_USER to ensure that metered
+ // chains are tested as well.
+ final int myUid = Process.myUid();
+ final boolean wasChainEnabled = runWithShellPermissionIdentity(
+ () -> mCm.getFirewallChainEnabled(chain), NETWORK_SETTINGS);
+ final int previousFirewallRule = runWithShellPermissionIdentity(
+ () -> mCm.getUidFirewallRule(chain, myUid));
+ final int previousMeteredDenyFirewallRule = runWithShellPermissionIdentity(
+ () -> mCm.getUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, myUid));
+
+ final DetailedBlockedStatusCallback cb = new DetailedBlockedStatusCallback();
+ networkCallbackRule.requestNetwork(makeWifiNetworkRequest(), cb);
+ testAndCleanup(() -> {
+ int blockedReasonsWithoutChain = BLOCKED_REASON_NONE;
+ int blockedReasonsWithChain = getBlockedReason(chain);
+ int blockedReasonsWithChainAndLockDown =
+ getBlockedReason(chain) | BLOCKED_REASON_LOCKDOWN_VPN;
+ if (metered) {
+ blockedReasonsWithoutChain |= BLOCKED_METERED_REASON_USER_RESTRICTED;
+ blockedReasonsWithChain |= BLOCKED_METERED_REASON_USER_RESTRICTED;
+ blockedReasonsWithChainAndLockDown |= BLOCKED_METERED_REASON_USER_RESTRICTED;
+ }
+
+ // Set RULE_DENY on target chain and metered deny chain
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, true /* enable */);
+ mCm.setUidFirewallRule(chain, myUid, FIREWALL_RULE_DENY);
+ mCm.setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, myUid,
+ FIREWALL_RULE_DENY);
+ }, NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(wifiNetwork, blockedReasonsWithChain);
+
+ // Set VPN lockdown
+ final Range<Integer> myUidRange = new Range<>(myUid, myUid);
+ runWithShellPermissionIdentity(() -> setRequireVpnForUids(
+ true /* requireVpn */, List.of(myUidRange)), NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(wifiNetwork,
+ blockedReasonsWithChainAndLockDown);
+
+ // Unset VPN lockdown
+ runWithShellPermissionIdentity(() -> setRequireVpnForUids(
+ false /* requireVpn */, List.of(myUidRange)), NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(wifiNetwork, blockedReasonsWithChain);
+
+ // Set RULE_ALLOW on target chain
+ runWithShellPermissionIdentity(
+ () -> mCm.setUidFirewallRule(chain, myUid, FIREWALL_RULE_ALLOW),
+ NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(wifiNetwork, blockedReasonsWithoutChain);
+
+ // Set RULE_ALLOW on metered deny chain
+ runWithShellPermissionIdentity(() -> mCm.setUidFirewallRule(
+ FIREWALL_CHAIN_METERED_DENY_USER, myUid, FIREWALL_RULE_ALLOW),
+ NETWORK_SETTINGS);
+ if (metered) {
+ cb.eventuallyExpectBlockedStatusCallback(wifiNetwork, BLOCKED_REASON_NONE);
+ }
+ }, /* cleanup */ () -> {
+ setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */);
+ }, /* cleanup */ () -> {
+ mCm.unregisterNetworkCallback(cb);
+ }, /* cleanup */ () -> {
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, wasChainEnabled);
+ try {
+ mCm.setUidFirewallRule(chain, myUid, previousFirewallRule);
+ } catch (IllegalStateException ignored) {
+ // Removing match causes an exception when the rule entry for the uid does
+ // not exist. But this is fine and can be ignored.
+ }
+ try {
+ mCm.setUidFirewallRule(FIREWALL_CHAIN_METERED_DENY_USER, myUid,
+ previousMeteredDenyFirewallRule);
+ } catch (IllegalStateException ignored) {
+ // Removing match causes an exception when the rule entry for the uid does
+ // not exist. But this is fine and can be ignored.
+ }
+ }, NETWORK_SETTINGS);
+ });
+ }
+
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+ @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @ConnectivityModuleTest
+ public void testBlockedReasons_setUidFirewallRule() throws Exception {
+ doTestBlockedReasons_setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, true /* metered */);
+ doTestBlockedReasons_setUidFirewallRule(FIREWALL_CHAIN_STANDBY, false /* metered */);
+ }
+
+ private void doTestBlockedReasons_setFirewallChainEnabled(final int chain) {
+ // Store current firewall chains status.
+ final int myUid = Process.myUid();
+ // TODO(b/342508466): Use runAsShell
+ final boolean wasChainEnabled = runWithShellPermissionIdentity(
+ () -> mCm.getFirewallChainEnabled(chain), NETWORK_SETTINGS);
+ final int previousFirewallRule = runWithShellPermissionIdentity(
+ () -> mCm.getUidFirewallRule(chain, myUid), NETWORK_SETTINGS);
+
+ final DetailedBlockedStatusCallback cb = new DetailedBlockedStatusCallback();
+ networkCallbackRule.registerDefaultNetworkCallback(cb);
+ final Network network = cb.expect(CallbackEntry.AVAILABLE).getNetwork();
+ testAndCleanup(() -> {
+ // Disable chain and set RULE_DENY on target chain
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, false /* enable */);
+ mCm.setUidFirewallRule(chain, myUid, FIREWALL_RULE_DENY);
+ }, NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(network, BLOCKED_REASON_NONE);
+
+ // Enable chain
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, true /* enable */);
+ }, NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(network, getBlockedReason(chain));
+
+ // Disable chain
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, false /* enable */);
+ }, NETWORK_SETTINGS);
+ cb.eventuallyExpectBlockedStatusCallback(network, BLOCKED_REASON_NONE);
+ }, /* cleanup */ () -> {
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, wasChainEnabled);
+ try {
+ mCm.setUidFirewallRule(chain, myUid, previousFirewallRule);
+ } catch (IllegalStateException ignored) {
+ // Removing match causes an exception when the rule entry for the uid does
+ // not exist. But this is fine and can be ignored.
+ }
+ }, NETWORK_SETTINGS);
+ });
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @ConnectivityModuleTest
+ public void testBlockedReasons_setFirewallChainEnabled() {
+ doTestBlockedReasons_setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE);
+ doTestBlockedReasons_setFirewallChainEnabled(FIREWALL_CHAIN_OEM_DENY_1);
+ }
+
+ private void doTestBlockedReasons_replaceFirewallChain(
+ final int chain, final boolean isAllowList) {
+ // Store current firewall chains status.
+ final int myUid = Process.myUid();
+ final boolean wasChainEnabled = runWithShellPermissionIdentity(
+ () -> mCm.getFirewallChainEnabled(chain), NETWORK_SETTINGS);
+ final int previousFirewallRule = runWithShellPermissionIdentity(
+ () -> mCm.getUidFirewallRule(chain, myUid), NETWORK_SETTINGS);
+
+ final DetailedBlockedStatusCallback cb = new DetailedBlockedStatusCallback();
+ networkCallbackRule.registerDefaultNetworkCallback(cb);
+ final Network network = cb.expect(CallbackEntry.AVAILABLE).getNetwork();
+ testAndCleanup(() -> {
+ cb.eventuallyExpectBlockedStatusCallback(network, BLOCKED_REASON_NONE);
+
+ // Remove uid from the target chain and enable chain
+ runWithShellPermissionIdentity(() -> {
+ // Note that this removes *all* UIDs from the chain, not just the UID that is
+ // being tested. This is probably OK since FIREWALL_CHAIN_OEM_DENY_2 is unused
+ // in AOSP and FIREWALL_CHAIN_BACKGROUND is probably empty when running this
+ // test (since nothing is in the foreground).
+ //
+ // TODO(b/342508466): add a getFirewallUidChainContents or similar method to fetch
+ // chain contents, and update this test to use it.
+ mCm.replaceFirewallChain(chain, new int[0]);
+ mCm.setFirewallChainEnabled(chain, true /* enable */);
+ }, NETWORK_SETTINGS);
+
+ if (isAllowList) {
+ cb.eventuallyExpectBlockedStatusCallback(network, getBlockedReason(chain));
+ } else {
+ cb.assertNoBlockedStatusCallback();
+ }
+
+ // Put uid on the target chain
+ runWithShellPermissionIdentity(
+ () -> mCm.replaceFirewallChain(chain, new int[]{myUid}), NETWORK_SETTINGS);
+
+ if (isAllowList) {
+ cb.eventuallyExpectBlockedStatusCallback(network, BLOCKED_REASON_NONE);
+ } else {
+ cb.eventuallyExpectBlockedStatusCallback(network, getBlockedReason(chain));
+ }
+
+ // Remove uid from the target chain
+ runWithShellPermissionIdentity(
+ () -> mCm.replaceFirewallChain(chain, new int[0]), NETWORK_SETTINGS);
+
+ if (isAllowList) {
+ cb.eventuallyExpectBlockedStatusCallback(network, getBlockedReason(chain));
+ } else {
+ cb.eventuallyExpectBlockedStatusCallback(network, BLOCKED_REASON_NONE);
+ }
+ }, /* cleanup */ () -> {
+ runWithShellPermissionIdentity(() -> {
+ mCm.setFirewallChainEnabled(chain, wasChainEnabled);
+ try {
+ mCm.setUidFirewallRule(chain, myUid, previousFirewallRule);
+ } catch (IllegalStateException ignored) {
+ // Removing match causes an exception when the rule entry for the uid does
+ // not exist. But this is fine and can be ignored.
+ }
+ }, NETWORK_SETTINGS);
+ });
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @ConnectivityModuleTest
+ public void testBlockedReasons_replaceFirewallChain() {
+ doTestBlockedReasons_replaceFirewallChain(
+ FIREWALL_CHAIN_BACKGROUND, true /* isAllowChain */);
+ doTestBlockedReasons_replaceFirewallChain(
+ FIREWALL_CHAIN_OEM_DENY_2, false /* isAllowChain */);
+ }
+
private void assumeTestSApis() {
// Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
// shims, and @IgnoreUpTo does not check that.
diff --git a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index d2e46af..06bdca6 100644
--- a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -27,6 +27,7 @@
import android.net.ConnectivityManager
import android.net.IDnsResolver
import android.net.INetd
+import android.net.INetd.PERMISSION_INTERNET
import android.net.LinkProperties
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
@@ -225,6 +226,9 @@
override fun getSystemProperties() = mock(MockableSystemProperties::class.java)
override fun makeNetIdManager() = TestNetIdManager()
override fun getBpfNetMaps(context: Context?, netd: INetd?) = mock(BpfNetMaps::class.java)
+ .also {
+ doReturn(PERMISSION_INTERNET).`when`(it).getNetPermForUid(anyInt())
+ }
override fun isChangeEnabled(changeId: Long, uid: Int) = true
override fun makeMultinetworkPolicyTracker(
diff --git a/tests/mts/Android.bp b/tests/mts/Android.bp
index 336be2e..c118d0a 100644
--- a/tests/mts/Android.bp
+++ b/tests/mts/Android.bp
@@ -31,6 +31,8 @@
header_libs: [
"bpf_headers",
],
+ version_script: ":connectivity_mainline_test_map",
+ stl: "libc++_static",
static_libs: [
"libbase",
"libmodules-utils-build",
diff --git a/tests/native/connectivity_native_test/Android.bp b/tests/native/connectivity_native_test/Android.bp
index 2f66d17..c5088c6 100644
--- a/tests/native/connectivity_native_test/Android.bp
+++ b/tests/native/connectivity_native_test/Android.bp
@@ -17,8 +17,9 @@
"connectivity_native_test.cpp",
],
header_libs: ["bpf_connectivity_headers"],
+ version_script: ":connectivity_mainline_test_map",
+ stl: "libc++_static",
shared_libs: [
- "libbase",
"libbinder_ndk",
"liblog",
"libnetutils",
@@ -26,6 +27,7 @@
],
static_libs: [
"connectivity_native_aidl_interface-lateststable-ndk",
+ "libbase",
"libcutils",
"libmodules-utils-build",
"libutils",
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index b6cb09b..44a8222 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -53,6 +53,7 @@
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_DEVICE_TYPE;
@@ -163,7 +164,6 @@
import static android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
import static com.android.server.ConnectivityService.ALLOW_SATALLITE_NETWORK_FALLBACK;
-import static com.android.server.ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION;
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
import static com.android.server.ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS;
import static com.android.server.ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION;
@@ -178,6 +178,7 @@
import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackRegister;
import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister;
import static com.android.server.connectivity.ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN;
+import static com.android.server.connectivity.ConnectivityFlags.DELAY_DESTROY_SOCKETS;
import static com.android.server.connectivity.ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING;
import static com.android.testutils.Cleanup.testAndCleanup;
import static com.android.testutils.ConcurrentUtils.await;
@@ -1746,7 +1747,15 @@
private void setBlockedReasonChanged(int blockedReasons) {
mBlockedReasons = blockedReasons;
- mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
+ if (mDeps.isAtLeastV()) {
+ visibleOnHandlerThread(mCsHandlerThread.getThreadHandler(),
+ () -> mService.handleBlockedReasonsChanged(
+ List.of(new Pair<>(Process.myUid(), blockedReasons))
+
+ ));
+ } else {
+ mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
+ }
}
private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
@@ -1927,11 +1936,16 @@
mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
- final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
- ArgumentCaptor.forClass(NetworkPolicyCallback.class);
- verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
- policyCallbackCaptor.capture());
- mPolicyCallback = policyCallbackCaptor.getValue();
+ if (mDeps.isAtLeastV()) {
+ verify(mNetworkPolicyManager, never()).registerNetworkPolicyCallback(any(), any());
+ mPolicyCallback = null;
+ } else {
+ final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkPolicyCallback.class);
+ verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
+ policyCallbackCaptor.capture());
+ mPolicyCallback = policyCallbackCaptor.getValue();
+ }
// Create local CM before sending system ready so that we can answer
// getSystemService() correctly.
@@ -2169,8 +2183,6 @@
return true;
case KEY_DESTROY_FROZEN_SOCKETS_VERSION:
return true;
- case DELAY_DESTROY_FROZEN_SOCKETS_VERSION:
- return true;
default:
return super.isFeatureEnabled(context, name);
}
@@ -2187,6 +2199,8 @@
return true;
case BACKGROUND_FIREWALL_CHAIN:
return true;
+ case DELAY_DESTROY_SOCKETS:
+ return true;
default:
return super.isFeatureNotChickenedOut(context, name);
}
@@ -7527,13 +7541,13 @@
@Test
public void testNetworkCallbackMaximum() throws Exception {
final int MAX_REQUESTS = 100;
- final int CALLBACKS = 87;
+ final int CALLBACKS = 88;
final int DIFF_INTENTS = 10;
final int SAME_INTENTS = 10;
final int SYSTEM_ONLY_MAX_REQUESTS = 250;
- // Assert 1 (Default request filed before testing) + CALLBACKS + DIFF_INTENTS +
- // 1 (same intent) = MAX_REQUESTS - 1, since the capacity is MAX_REQUEST - 1.
- assertEquals(MAX_REQUESTS - 1, 1 + CALLBACKS + DIFF_INTENTS + 1);
+ // CALLBACKS + DIFF_INTENTS + 1 (same intent)
+ // = MAX_REQUESTS - 1, since the capacity is MAX_REQUEST - 1.
+ assertEquals(MAX_REQUESTS - 1, CALLBACKS + DIFF_INTENTS + 1);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
ArrayList<Object> registered = new ArrayList<>();
@@ -9867,6 +9881,28 @@
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertExtraInfoFromCmPresent(mCellAgent);
+ // Remove PERMISSION_INTERNET and disable NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION
+ doReturn(INetd.PERMISSION_NONE).when(mBpfNetMaps).getNetPermForUid(Process.myUid());
+ mDeps.setChangeIdEnabled(false,
+ NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION, Process.myUid());
+
+ setBlockedReasonChanged(BLOCKED_REASON_DOZE);
+ if (mDeps.isAtLeastV()) {
+ // On V+, network access from app that does not have INTERNET permission is considered
+ // not blocked if NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION is disabled.
+ // So blocked status does not change from BLOCKED_REASON_NONE
+ cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
+ } else {
+ // On U-, onBlockedStatusChanged callback is called with blocked reasons CS receives
+ // from NPMS callback regardless of permission app has.
+ // Note that this cannot actually happen because on U-, NPMS will never notify any
+ // blocked reasons for apps that don't have the INTERNET permission.
+ cellNetworkCallback.expect(BLOCKED_STATUS, mCellAgent, cb -> cb.getBlocked());
+ detailedCallback.expect(BLOCKED_STATUS_INT, mCellAgent,
+ cb -> cb.getReason() == BLOCKED_REASON_DOZE);
+ }
+
mCm.unregisterNetworkCallback(cellNetworkCallback);
}
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index da7fda3..72dde7f 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -38,6 +38,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -418,21 +419,6 @@
inOrder.verify(mDeps).generateIpv6Address(eq(BASE_IFACE),
eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(NAT64_PREFIX_STRING), eq(MARK));
- // Open, configure and bring up the tun interface.
- inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE));
- inOrder.verify(mDeps).adoptFd(eq(TUN_FD));
- inOrder.verify(mDeps).getInterfaceIndex(eq(STACKED_IFACE));
- inOrder.verify(mNetd).interfaceSetEnableIPv6(eq(STACKED_IFACE), eq(false /* enable */));
- inOrder.verify(mDeps).detectMtu(eq(NAT64_PREFIX_STRING), eq(GOOGLE_DNS_4), eq(MARK));
- inOrder.verify(mNetd).interfaceSetMtu(eq(STACKED_IFACE),
- eq(1472 /* ETHER_MTU(1500) - MTU_DELTA(28) */));
- inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
- STACKED_IFACE.equals(cfg.ifName)
- && XLAT_LOCAL_IPV4ADDR_STRING.equals(cfg.ipv4Addr)
- && (32 == cfg.prefixLength)
- && "".equals(cfg.hwAddr)
- && assertContainsFlag(cfg.flags, IF_STATE_UP)));
-
// Open and configure 464xlat read/write sockets.
inOrder.verify(mDeps).openPacketSocket();
inOrder.verify(mDeps).adoptFd(eq(PACKET_SOCK_FD));
@@ -449,6 +435,21 @@
argThat(fd -> Objects.equals(PACKET_SOCK_PFD.getFileDescriptor(), fd)),
eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(BASE_IFINDEX));
+ // Open, configure and bring up the tun interface.
+ inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE));
+ inOrder.verify(mDeps).adoptFd(eq(TUN_FD));
+ inOrder.verify(mDeps).getInterfaceIndex(eq(STACKED_IFACE));
+ inOrder.verify(mNetd).interfaceSetEnableIPv6(eq(STACKED_IFACE), eq(false /* enable */));
+ inOrder.verify(mDeps).detectMtu(eq(NAT64_PREFIX_STRING), eq(GOOGLE_DNS_4), eq(MARK));
+ inOrder.verify(mNetd).interfaceSetMtu(eq(STACKED_IFACE),
+ eq(1472 /* ETHER_MTU(1500) - MTU_DELTA(28) */));
+ inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
+ STACKED_IFACE.equals(cfg.ifName)
+ && XLAT_LOCAL_IPV4ADDR_STRING.equals(cfg.ipv4Addr)
+ && (32 == cfg.prefixLength)
+ && "".equals(cfg.hwAddr)
+ && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+
// Start clatd.
inOrder.verify(mDeps).startClatd(
argThat(fd -> Objects.equals(TUN_PFD.getFileDescriptor(), fd)),
@@ -630,9 +631,13 @@
public int createTunInterface(@NonNull String tuniface) throws IOException {
throw new IOException();
}
+ @Override
+ public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+ return mock(IBpfMap.class);
+ }
}
checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
- false /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
+ true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@Test
@@ -643,9 +648,14 @@
throws IOException {
throw new IOException();
}
+
+ @Override
+ public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
+ return mock(IBpfMap.class);
+ }
}
checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
- false /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
+ true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@Test
@@ -656,7 +666,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
false /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
}
@@ -668,7 +678,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, false /* needToCloseRawSockFd */);
}
@@ -681,7 +691,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@@ -694,7 +704,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@@ -721,7 +731,7 @@
throw new IOException();
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
@@ -733,7 +743,7 @@
return null;
}
}
- checkNotStartClat(new FailureDependencies(), true /* needToCloseTunFd */,
+ checkNotStartClat(new FailureDependencies(), false /* needToCloseTunFd */,
true /* needToClosePacketSockFd */, true /* needToCloseRawSockFd */);
}
}
diff --git a/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
index 44512bb..ea3d2dd 100644
--- a/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
@@ -29,8 +29,6 @@
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static com.android.testutils.MiscAsserts.assertContainsExactly;
-import static com.android.testutils.MiscAsserts.assertContainsStringsExactly;
import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
import static org.junit.Assert.assertEquals;
@@ -38,12 +36,12 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivitySettingsManager;
@@ -74,7 +72,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -122,29 +119,6 @@
assertFieldCountEquals(3, ResolverOptionsParcel.class);
}
- private void assertResolverParamsEquals(@NonNull ResolverParamsParcel actual,
- @NonNull ResolverParamsParcel expected) {
- assertEquals(actual.netId, expected.netId);
- assertEquals(actual.sampleValiditySeconds, expected.sampleValiditySeconds);
- assertEquals(actual.successThreshold, expected.successThreshold);
- assertEquals(actual.minSamples, expected.minSamples);
- assertEquals(actual.maxSamples, expected.maxSamples);
- assertEquals(actual.baseTimeoutMsec, expected.baseTimeoutMsec);
- assertEquals(actual.retryCount, expected.retryCount);
- assertContainsStringsExactly(actual.servers, expected.servers);
- assertContainsStringsExactly(actual.domains, expected.domains);
- assertEquals(actual.tlsName, expected.tlsName);
- assertContainsStringsExactly(actual.tlsServers, expected.tlsServers);
- assertContainsStringsExactly(actual.tlsFingerprints, expected.tlsFingerprints);
- assertEquals(actual.caCertificate, expected.caCertificate);
- assertEquals(actual.tlsConnectTimeoutMs, expected.tlsConnectTimeoutMs);
- assertResolverOptionsEquals(actual.resolverOptions, expected.resolverOptions);
- assertContainsExactly(actual.transportTypes, expected.transportTypes);
- assertEquals(actual.meteredNetwork, expected.meteredNetwork);
- assertEquals(actual.dohParams, expected.dohParams);
- assertFieldCountEquals(18, ResolverParamsParcel.class);
- }
-
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -365,11 +339,6 @@
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
mDnsManager.flushVmDnsCache();
- final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- resolverParamsParcelCaptor.capture());
- final ResolverParamsParcel actualParams = resolverParamsParcelCaptor.getValue();
final ResolverParamsParcel expectedParams = new ResolverParamsParcel();
expectedParams.netId = TEST_NETID;
expectedParams.sampleValiditySeconds = TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS;
@@ -384,7 +353,8 @@
expectedParams.resolverOptions = null;
expectedParams.meteredNetwork = true;
expectedParams.dohParams = null;
- assertResolverParamsEquals(actualParams, expectedParams);
+ expectedParams.interfaceNames = new String[]{TEST_IFACENAME};
+ verify(mMockDnsResolver, times(1)).setResolverConfiguration(eq(expectedParams));
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSBlockedReasonsTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSBlockedReasonsTest.kt
new file mode 100644
index 0000000..0590fbb
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivityservice/CSBlockedReasonsTest.kt
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server
+
+import android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER
+import android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED
+import android.net.ConnectivityManager.BLOCKED_REASON_APP_BACKGROUND
+import android.net.ConnectivityManager.BLOCKED_REASON_DOZE
+import android.net.ConnectivityManager.BLOCKED_REASON_NETWORK_RESTRICTED
+import android.net.ConnectivityManager.BLOCKED_REASON_NONE
+import android.net.ConnectivityManager.FIREWALL_CHAIN_BACKGROUND
+import android.net.ConnectivityManager.FIREWALL_CHAIN_DOZABLE
+import android.net.ConnectivityManager.FIREWALL_CHAIN_METERED_DENY_USER
+import android.net.ConnectivityManager.FIREWALL_RULE_ALLOW
+import android.net.ConnectivityManager.FIREWALL_RULE_DENY
+import android.net.ConnectivitySettingsManager
+import android.net.INetd.PERMISSION_NONE
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkRequest
+import android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION
+import android.os.Build
+import android.os.Process
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatusInt
+import com.android.testutils.TestableNetworkCallback
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.Mockito.doReturn
+
+private fun cellNc() = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build()
+private fun cellRequest() = NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .build()
+private fun wifiNc() = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .build()
+private fun wifiRequest() = NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .build()
+
+@RunWith(DevSdkIgnoreRunner::class)
+@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class CSBlockedReasonsTest : CSTest() {
+
+ inner class DetailedBlockedStatusCallback : TestableNetworkCallback() {
+ override fun onBlockedStatusChanged(network: Network, blockedReasons: Int) {
+ history.add(BlockedStatusInt(network, blockedReasons))
+ }
+
+ fun expectBlockedStatusChanged(network: Network, blockedReasons: Int) {
+ expect<BlockedStatusInt>(network) { it.reason == blockedReasons }
+ }
+ }
+
+ @Test
+ fun testBlockedReasons_onAvailable() {
+ doReturn(BLOCKED_REASON_DOZE or BLOCKED_METERED_REASON_DATA_SAVER)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+
+ val cellAgent = Agent(nc = cellNc())
+ cellAgent.connect()
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+
+ val cellCb = DetailedBlockedStatusCallback()
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(cellRequest(), cellCb)
+ cm.requestNetwork(wifiRequest(), wifiCb)
+
+ cellCb.expectAvailableCallbacks(
+ cellAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_DOZE or BLOCKED_METERED_REASON_DATA_SAVER
+ )
+ wifiCb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_DOZE
+ )
+
+ cellAgent.disconnect()
+ wifiAgent.disconnect()
+ cm.unregisterNetworkCallback(cellCb)
+ cm.unregisterNetworkCallback(wifiCb)
+ }
+
+ @Test
+ fun testBlockedReasons_dataSaverChanged() {
+ doReturn(BLOCKED_REASON_APP_BACKGROUND or BLOCKED_METERED_REASON_DATA_SAVER)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ doReturn(true).`when`(netd).bandwidthEnableDataSaver(anyBoolean())
+
+ val cellCb = DetailedBlockedStatusCallback()
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(cellRequest(), cellCb)
+ cm.requestNetwork(wifiRequest(), wifiCb)
+
+ val cellAgent = Agent(nc = cellNc())
+ cellAgent.connect()
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+ cellCb.expectAvailableCallbacks(
+ cellAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_APP_BACKGROUND or BLOCKED_METERED_REASON_DATA_SAVER
+ )
+ wifiCb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_APP_BACKGROUND
+ )
+
+ // Disable data saver
+ doReturn(BLOCKED_REASON_APP_BACKGROUND)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setDataSaverEnabled(false)
+ cellCb.expectBlockedStatusChanged(cellAgent.network, BLOCKED_REASON_APP_BACKGROUND)
+
+ // waitForIdle since stubbing bpfNetMaps while CS handler thread calls
+ // bpfNetMaps.getNetPermForUid throws exception.
+ // The expectBlockedStatusChanged just above guarantees that the onBlockedStatusChanged
+ // method on this callback was called, but it does not guarantee that ConnectivityService
+ // has finished processing all onBlockedStatusChanged callbacks for all requests.
+ waitForIdle()
+ // Enable data saver
+ doReturn(BLOCKED_REASON_APP_BACKGROUND or BLOCKED_METERED_REASON_DATA_SAVER)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setDataSaverEnabled(true)
+ cellCb.expectBlockedStatusChanged(
+ cellAgent.network,
+ BLOCKED_REASON_APP_BACKGROUND or BLOCKED_METERED_REASON_DATA_SAVER
+ )
+ // BlockedStatus does not change for the non-metered network
+ wifiCb.assertNoCallback()
+
+ cellAgent.disconnect()
+ wifiAgent.disconnect()
+ cm.unregisterNetworkCallback(cellCb)
+ cm.unregisterNetworkCallback(wifiCb)
+ }
+
+ @Test
+ fun testBlockedReasons_setUidFirewallRule() {
+ doReturn(BLOCKED_REASON_DOZE or BLOCKED_METERED_REASON_USER_RESTRICTED)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+
+ val cellCb = DetailedBlockedStatusCallback()
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(cellRequest(), cellCb)
+ cm.requestNetwork(wifiRequest(), wifiCb)
+
+ val cellAgent = Agent(nc = cellNc())
+ cellAgent.connect()
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+ cellCb.expectAvailableCallbacks(
+ cellAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_DOZE or BLOCKED_METERED_REASON_USER_RESTRICTED
+ )
+ wifiCb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_DOZE
+ )
+
+ // waitForIdle since stubbing bpfNetMaps while CS handler thread calls
+ // bpfNetMaps.getNetPermForUid throws exception.
+ // The expectBlockedStatusChanged just above guarantees that the onBlockedStatusChanged
+ // method on this callback was called, but it does not guarantee that ConnectivityService
+ // has finished processing all onBlockedStatusChanged callbacks for all requests.
+ waitForIdle()
+ // Set RULE_ALLOW on metered deny chain
+ doReturn(BLOCKED_REASON_DOZE)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setUidFirewallRule(
+ FIREWALL_CHAIN_METERED_DENY_USER,
+ Process.myUid(),
+ FIREWALL_RULE_ALLOW
+ )
+ cellCb.expectBlockedStatusChanged(
+ cellAgent.network,
+ BLOCKED_REASON_DOZE
+ )
+ // BlockedStatus does not change for the non-metered network
+ wifiCb.assertNoCallback()
+
+ // Set RULE_DENY on metered deny chain
+ doReturn(BLOCKED_REASON_DOZE or BLOCKED_METERED_REASON_USER_RESTRICTED)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setUidFirewallRule(
+ FIREWALL_CHAIN_METERED_DENY_USER,
+ Process.myUid(),
+ FIREWALL_RULE_DENY
+ )
+ cellCb.expectBlockedStatusChanged(
+ cellAgent.network,
+ BLOCKED_REASON_DOZE or BLOCKED_METERED_REASON_USER_RESTRICTED
+ )
+ // BlockedStatus does not change for the non-metered network
+ wifiCb.assertNoCallback()
+
+ cellAgent.disconnect()
+ wifiAgent.disconnect()
+ cm.unregisterNetworkCallback(cellCb)
+ cm.unregisterNetworkCallback(wifiCb)
+ }
+
+ @Test
+ fun testBlockedReasons_setFirewallChainEnabled() {
+ doReturn(BLOCKED_REASON_NONE)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(wifiRequest(), wifiCb)
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+ wifiCb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_NONE
+ )
+
+ // Enable dozable firewall chain
+ doReturn(BLOCKED_REASON_DOZE)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true)
+ wifiCb.expectBlockedStatusChanged(
+ wifiAgent.network,
+ BLOCKED_REASON_DOZE
+ )
+
+ // Disable dozable firewall chain
+ doReturn(BLOCKED_REASON_NONE)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, false)
+ wifiCb.expectBlockedStatusChanged(
+ wifiAgent.network,
+ BLOCKED_REASON_NONE
+ )
+
+ wifiAgent.disconnect()
+ cm.unregisterNetworkCallback(wifiCb)
+ }
+
+ @Test
+ fun testBlockedReasons_replaceFirewallChain() {
+ doReturn(BLOCKED_REASON_APP_BACKGROUND)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(wifiRequest(), wifiCb)
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+ wifiCb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_APP_BACKGROUND
+ )
+
+ // Put uid on background firewall chain
+ doReturn(BLOCKED_REASON_NONE)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, intArrayOf(Process.myUid()))
+ wifiCb.expectBlockedStatusChanged(
+ wifiAgent.network,
+ BLOCKED_REASON_NONE
+ )
+
+ // Remove uid from background firewall chain
+ doReturn(BLOCKED_REASON_APP_BACKGROUND)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.replaceFirewallChain(FIREWALL_CHAIN_BACKGROUND, intArrayOf())
+ wifiCb.expectBlockedStatusChanged(
+ wifiAgent.network,
+ BLOCKED_REASON_APP_BACKGROUND
+ )
+
+ wifiAgent.disconnect()
+ cm.unregisterNetworkCallback(wifiCb)
+ }
+
+ @Test
+ fun testBlockedReasons_perAppDefaultNetwork() {
+ doReturn(BLOCKED_METERED_REASON_USER_RESTRICTED)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+
+ val cellCb = DetailedBlockedStatusCallback()
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(cellRequest(), cellCb)
+ cm.requestNetwork(wifiRequest(), wifiCb)
+
+ val cellAgent = Agent(nc = cellNc())
+ cellAgent.connect()
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+
+ val cb = DetailedBlockedStatusCallback()
+ cm.registerDefaultNetworkCallback(cb)
+ cb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_NONE
+ )
+
+ // CS must send correct blocked reasons after per app default network change
+ ConnectivitySettingsManager.setMobileDataPreferredUids(context, setOf(Process.myUid()))
+ service.updateMobileDataPreferredUids()
+ cb.expectAvailableCallbacks(
+ cellAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_METERED_REASON_USER_RESTRICTED
+ )
+
+ // Remove per app default network request
+ ConnectivitySettingsManager.setMobileDataPreferredUids(context, setOf())
+ service.updateMobileDataPreferredUids()
+ cb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = BLOCKED_REASON_NONE
+ )
+
+ cellAgent.disconnect()
+ wifiAgent.disconnect()
+ cm.unregisterNetworkCallback(cellCb)
+ cm.unregisterNetworkCallback(wifiCb)
+ cm.unregisterNetworkCallback(cb)
+ }
+
+ private fun doTestBlockedReasonsNoInternetPermission(blockedByNoInternetPermission: Boolean) {
+ doReturn(PERMISSION_NONE).`when`(bpfNetMaps).getNetPermForUid(Process.myUid())
+
+ val wifiCb = DetailedBlockedStatusCallback()
+ cm.requestNetwork(wifiRequest(), wifiCb)
+ val wifiAgent = Agent(nc = wifiNc())
+ wifiAgent.connect()
+ val expectedBlockedReason = if (blockedByNoInternetPermission) {
+ BLOCKED_REASON_NETWORK_RESTRICTED
+ } else {
+ BLOCKED_REASON_NONE
+ }
+ wifiCb.expectAvailableCallbacks(
+ wifiAgent.network,
+ validated = false,
+ blockedReason = expectedBlockedReason
+ )
+
+ // Enable background firewall chain
+ doReturn(BLOCKED_REASON_APP_BACKGROUND)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, true)
+ if (blockedByNoInternetPermission) {
+ wifiCb.expectBlockedStatusChanged(
+ wifiAgent.network,
+ BLOCKED_REASON_NETWORK_RESTRICTED or BLOCKED_REASON_APP_BACKGROUND
+ )
+ }
+
+ // Disable background firewall chain
+ doReturn(BLOCKED_REASON_NONE)
+ .`when`(bpfNetMaps).getUidNetworkingBlockedReasons(Process.myUid())
+ cm.setFirewallChainEnabled(FIREWALL_CHAIN_BACKGROUND, false)
+ if (blockedByNoInternetPermission) {
+ wifiCb.expectBlockedStatusChanged(
+ wifiAgent.network,
+ BLOCKED_REASON_NETWORK_RESTRICTED
+ )
+ } else {
+ // No callback is expected since blocked reasons does not change from
+ // BLOCKED_REASON_NONE.
+ wifiCb.assertNoCallback()
+ }
+ }
+
+ @Test
+ fun testBlockedReasonsNoInternetPermission_changeDisabled() {
+ deps.setChangeIdEnabled(false, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION)
+ doTestBlockedReasonsNoInternetPermission(blockedByNoInternetPermission = false)
+ }
+
+ @Test
+ fun testBlockedReasonsNoInternetPermission_changeEnabled() {
+ deps.setChangeIdEnabled(true, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION)
+ doTestBlockedReasonsNoInternetPermission(blockedByNoInternetPermission = true)
+ }
+}
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSIngressDiscardRuleTests.kt b/tests/unit/java/com/android/server/connectivityservice/CSIngressDiscardRuleTests.kt
index bb7fb51..93f6e81 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSIngressDiscardRuleTests.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSIngressDiscardRuleTests.kt
@@ -37,6 +37,7 @@
import com.android.testutils.TestableNetworkCallback
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.InOrder
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.timeout
@@ -96,6 +97,11 @@
private val LOCAL_IPV6_ADDRRESS = InetAddresses.parseNumericAddress("fe80::1234")
private val LOCAL_IPV6_LINK_ADDRRESS = LinkAddress(LOCAL_IPV6_ADDRRESS, 64)
+ fun verifyNoMoreIngressDiscardRuleChange(inorder: InOrder) {
+ inorder.verify(bpfNetMaps, never()).setIngressDiscardRule(any(), any())
+ inorder.verify(bpfNetMaps, never()).removeIngressDiscardRule(any())
+ }
+
@Test
fun testVpnIngressDiscardRule_UpdateVpnAddress() {
// non-VPN network whose address will be not duplicated with VPN address
@@ -148,7 +154,7 @@
// IngressDiscardRule is added to the VPN address
inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
- inorder.verifyNoMoreInteractions()
+ verifyNoMoreIngressDiscardRuleChange(inorder)
// The VPN interface name is changed
val newlp = lp(VPN_IFNAME2, IPV6_LINK_ADDRESS, LOCAL_IPV6_LINK_ADDRRESS)
@@ -157,7 +163,7 @@
// IngressDiscardRule is updated with the new interface name
inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME2)
- inorder.verifyNoMoreInteractions()
+ verifyNoMoreIngressDiscardRuleChange(inorder)
agent.disconnect()
inorder.verify(bpfNetMaps, timeout(TIMEOUT_MS)).removeIngressDiscardRule(IPV6_ADDRESS)
@@ -206,10 +212,10 @@
// IngressDiscardRule for IPV6_ADDRESS2 is removed but IngressDiscardRule for
// IPV6_LINK_ADDRESS is not added since Wi-Fi also uses IPV6_LINK_ADDRESS
inorder.verify(bpfNetMaps).removeIngressDiscardRule(IPV6_ADDRESS2)
- inorder.verifyNoMoreInteractions()
+ verifyNoMoreIngressDiscardRuleChange(inorder)
vpnAgent.disconnect()
- inorder.verifyNoMoreInteractions()
+ verifyNoMoreIngressDiscardRuleChange(inorder)
cm.unregisterNetworkCallback(cb)
}
@@ -225,7 +231,7 @@
// IngressDiscardRule is added to the VPN address
inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
- inorder.verifyNoMoreInteractions()
+ verifyNoMoreIngressDiscardRuleChange(inorder)
val nr = nr(TRANSPORT_WIFI)
val cb = TestableNetworkCallback()
@@ -247,7 +253,7 @@
// IngressDiscardRule is added to the VPN address since the VPN address is not duplicated
// with the Wi-Fi address
inorder.verify(bpfNetMaps).setIngressDiscardRule(IPV6_ADDRESS, VPN_IFNAME)
- inorder.verifyNoMoreInteractions()
+ verifyNoMoreIngressDiscardRuleChange(inorder)
// The Wi-Fi address is changed back to the same address as the VPN interface
wifiAgent.sendLinkProperties(wifiLp)
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
index 3b06ad0..99a8a3d 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
@@ -27,6 +27,7 @@
import android.content.res.Resources
import android.net.ConnectivityManager
import android.net.INetd
+import android.net.INetd.PERMISSION_INTERNET
import android.net.InetAddresses
import android.net.LinkProperties
import android.net.LocalNetworkConfig
@@ -89,6 +90,7 @@
import org.junit.Rule
import org.junit.rules.TestName
import org.mockito.AdditionalAnswers.delegatesTo
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
@@ -157,11 +159,11 @@
it[ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER] = true
it[ConnectivityFlags.REQUEST_RESTRICTED_WIFI] = true
it[ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION] = true
- it[ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION] = true
it[ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS] = true
it[ConnectivityService.ALLOW_SATALLITE_NETWORK_FALLBACK] = true
it[ConnectivityFlags.INGRESS_TO_VPN_ADDRESS_FILTERING] = true
it[ConnectivityFlags.BACKGROUND_FIREWALL_CHAIN] = true
+ it[ConnectivityFlags.DELAY_DESTROY_SOCKETS] = true
}
fun setFeatureEnabled(flag: String, enabled: Boolean) = enabledFeatures.set(flag, enabled)
@@ -171,7 +173,11 @@
val contentResolver = makeMockContentResolver(context)
val PRIMARY_USER = 0
- val PRIMARY_USER_INFO = UserInfo(PRIMARY_USER, "" /* name */, UserInfo.FLAG_PRIMARY)
+ val PRIMARY_USER_INFO = UserInfo(
+ PRIMARY_USER,
+ "", // name
+ UserInfo.FLAG_PRIMARY
+ )
val PRIMARY_USER_HANDLE = UserHandle(PRIMARY_USER)
val userManager = makeMockUserManager(PRIMARY_USER_INFO, PRIMARY_USER_HANDLE)
val activityManager = makeActivityManager()
@@ -183,10 +189,16 @@
val connResources = makeMockConnResources(sysResources, packageManager)
val netd = mock<INetd>()
- val bpfNetMaps = mock<BpfNetMaps>()
+ val bpfNetMaps = mock<BpfNetMaps>().also {
+ doReturn(PERMISSION_INTERNET).`when`(it).getNetPermForUid(anyInt())
+ }
val clatCoordinator = mock<ClatCoordinator>()
val networkRequestStateStatsMetrics = mock<NetworkRequestStateStatsMetrics>()
- val proxyTracker = ProxyTracker(context, mock<Handler>(), 16 /* EVENT_PROXY_HAS_CHANGED */)
+ val proxyTracker = ProxyTracker(
+ context,
+ mock<Handler>(),
+ 16 // EVENT_PROXY_HAS_CHANGED
+ )
val systemConfigManager = makeMockSystemConfigManager()
val batteryStats = mock<IBatteryStats>()
val batteryManager = BatteryStatsManager(batteryStats)
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 6425daa..9026481 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -314,7 +314,7 @@
new SetFeatureFlagsRule((name, enabled) -> {
mFeatureFlags.put(name, enabled);
return null;
- });
+ }, (name) -> mFeatureFlags.getOrDefault(name, false));
private class MockContext extends BroadcastInterceptingContext {
private final Context mBaseContext;
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
index 3d743ab..b418ef6 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
@@ -465,6 +465,7 @@
private void setEnabledInternal(
boolean isEnabled, boolean persist, @NonNull OperationReceiverWrapper receiver) {
+ checkOnHandlerThread();
if (isEnabled && isThreadUserRestricted()) {
receiver.onError(
ERROR_FAILED_PRECONDITION,
@@ -960,7 +961,11 @@
private void checkOnHandlerThread() {
if (Looper.myLooper() != mHandler.getLooper()) {
- Log.wtf(TAG, "Must be on the handler thread!");
+ throw new IllegalStateException(
+ "Not running on ThreadNetworkControllerService thread ("
+ + mHandler.getLooper()
+ + ") : "
+ + Looper.myLooper());
}
}
diff --git a/thread/service/java/com/android/server/thread/TunInterfaceController.java b/thread/service/java/com/android/server/thread/TunInterfaceController.java
index c3f6ace..976f93d 100644
--- a/thread/service/java/com/android/server/thread/TunInterfaceController.java
+++ b/thread/service/java/com/android/server/thread/TunInterfaceController.java
@@ -16,30 +16,40 @@
package com.android.server.thread;
+import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.EADDRINUSE;
+import static android.system.OsConstants.IFF_MULTICAST;
+import static android.system.OsConstants.IFF_NOARP;
+import static android.system.OsConstants.NETLINK_ROUTE;
+
+import static com.android.net.module.util.netlink.NetlinkConstants.RTM_NEWLINK;
+import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_AF_SPEC;
+import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IFLA_INET6_ADDR_GEN_MODE;
+import static com.android.net.module.util.netlink.RtNetlinkLinkMessage.IN6_ADDR_GEN_MODE_NONE;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
-import android.net.util.SocketUtils;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.OsConstants;
import android.util.Log;
+import com.android.net.module.util.HexDump;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.net.module.util.netlink.NetlinkUtils;
-import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
+import com.android.net.module.util.netlink.StructIfinfoMsg;
+import com.android.net.module.util.netlink.StructNlAttr;
+import com.android.net.module.util.netlink.StructNlMsgHdr;
import com.android.server.thread.openthread.Ipv6AddressInfo;
import com.android.server.thread.openthread.OnMeshPrefixConfig;
-import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InterruptedIOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -47,12 +57,15 @@
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
/** Controller for virtual/tunnel network interfaces. */
public class TunInterfaceController {
private static final String TAG = "TunIfController";
+ private static final boolean DBG = false;
private static final long INFINITE_LIFETIME = 0xffffffffL;
static final int MTU = 1280;
@@ -62,14 +75,13 @@
private final String mIfName;
private final LinkProperties mLinkProperties = new LinkProperties();
- private ParcelFileDescriptor mParcelTunFd;
- private FileDescriptor mNetlinkSocket;
- private static int sNetlinkSeqNo = 0;
private final MulticastSocket mMulticastSocket; // For join group and leave group
- private NetworkInterface mNetworkInterface;
private final List<InetAddress> mMulticastAddresses = new ArrayList<>();
private final List<RouteInfo> mNetDataPrefixes = new ArrayList<>();
+ private ParcelFileDescriptor mParcelTunFd;
+ private NetworkInterface mNetworkInterface;
+
/** Creates a new {@link TunInterfaceController} instance for given interface. */
public TunInterfaceController(String interfaceName) {
mIfName = interfaceName;
@@ -91,26 +103,21 @@
public void createTunInterface() throws IOException {
mParcelTunFd = ParcelFileDescriptor.adoptFd(nativeCreateTunInterface(mIfName, MTU));
try {
- mNetlinkSocket = NetlinkUtils.netlinkSocketForProto(OsConstants.NETLINK_ROUTE);
- } catch (ErrnoException e) {
- throw new IOException("Failed to create netlink socket", e);
- }
- try {
mNetworkInterface = NetworkInterface.getByName(mIfName);
} catch (SocketException e) {
throw new IOException("Failed to get NetworkInterface", e);
}
+
+ setAddrGenModeToNone();
}
public void destroyTunInterface() {
try {
mParcelTunFd.close();
- SocketUtils.closeSocket(mNetlinkSocket);
} catch (IOException e) {
// Should never fail
}
mParcelTunFd = null;
- mNetlinkSocket = null;
mNetworkInterface = null;
}
@@ -128,6 +135,10 @@
for (LinkAddress address : mLinkProperties.getAllLinkAddresses()) {
removeAddress(address);
}
+ for (RouteInfo route : mLinkProperties.getAllRoutes()) {
+ mLinkProperties.removeRoute(route);
+ }
+ mNetDataPrefixes.clear();
}
nativeSetInterfaceUp(mIfName, isUp);
}
@@ -138,14 +149,14 @@
public void addAddress(LinkAddress address) {
Log.d(TAG, "Adding address " + address + " with flags: " + address.getFlags());
- long validLifetimeSeconds;
long preferredLifetimeSeconds;
+ long validLifetimeSeconds;
if (address.getDeprecationTime() == LinkAddress.LIFETIME_PERMANENT
|| address.getDeprecationTime() == LinkAddress.LIFETIME_UNKNOWN) {
- validLifetimeSeconds = INFINITE_LIFETIME;
+ preferredLifetimeSeconds = INFINITE_LIFETIME;
} else {
- validLifetimeSeconds =
+ preferredLifetimeSeconds =
Math.max(
(address.getDeprecationTime() - SystemClock.elapsedRealtime()) / 1000L,
0L);
@@ -153,28 +164,23 @@
if (address.getExpirationTime() == LinkAddress.LIFETIME_PERMANENT
|| address.getExpirationTime() == LinkAddress.LIFETIME_UNKNOWN) {
- preferredLifetimeSeconds = INFINITE_LIFETIME;
+ validLifetimeSeconds = INFINITE_LIFETIME;
} else {
- preferredLifetimeSeconds =
+ validLifetimeSeconds =
Math.max(
(address.getExpirationTime() - SystemClock.elapsedRealtime()) / 1000L,
0L);
}
- byte[] message =
- RtNetlinkAddressMessage.newRtmNewAddressMessage(
- sNetlinkSeqNo++,
- address.getAddress(),
- (short) address.getPrefixLength(),
- address.getFlags(),
- (byte) address.getScope(),
- Os.if_nametoindex(mIfName),
- validLifetimeSeconds,
- preferredLifetimeSeconds);
- try {
- Os.write(mNetlinkSocket, message, 0, message.length);
- } catch (ErrnoException | InterruptedIOException e) {
- Log.e(TAG, "Failed to add address " + address, e);
+ if (!NetlinkUtils.sendRtmNewAddressRequest(
+ Os.if_nametoindex(mIfName),
+ address.getAddress(),
+ (short) address.getPrefixLength(),
+ address.getFlags(),
+ (byte) address.getScope(),
+ preferredLifetimeSeconds,
+ validLifetimeSeconds)) {
+ Log.w(TAG, "Failed to add address " + address.getAddress().getHostAddress());
return;
}
mLinkProperties.addLinkAddress(address);
@@ -184,22 +190,17 @@
/** Removes an address from the interface. */
public void removeAddress(LinkAddress address) {
Log.d(TAG, "Removing address " + address);
- byte[] message =
- RtNetlinkAddressMessage.newRtmDelAddressMessage(
- sNetlinkSeqNo++,
- address.getAddress(),
- (short) address.getPrefixLength(),
- Os.if_nametoindex(mIfName));
// Intentionally update the mLinkProperties before send netlink message because the
// address is already removed from ot-daemon and apps can't reach to the address even
// when the netlink request below fails
mLinkProperties.removeLinkAddress(address);
mLinkProperties.removeRoute(getRouteForAddress(address));
- try {
- Os.write(mNetlinkSocket, message, 0, message.length);
- } catch (ErrnoException | InterruptedIOException e) {
- Log.e(TAG, "Failed to remove address " + address, e);
+ if (!NetlinkUtils.sendRtmDelAddressRequest(
+ Os.if_nametoindex(mIfName),
+ (Inet6Address) address.getAddress(),
+ (short) address.getPrefixLength())) {
+ Log.w(TAG, "Failed to remove address " + address.getAddress().getHostAddress());
}
}
@@ -362,4 +363,66 @@
Log.e(TAG, "failed to leave group " + address.getHostAddress(), e);
}
}
+
+ /**
+ * Sets the address generation mode to {@code IN6_ADDR_GEN_MODE_NONE}.
+ *
+ * <p>So that the "thread-wpan" interface has only one IPv6 link local address which is
+ * generated by OpenThread.
+ */
+ private void setAddrGenModeToNone() {
+ StructNlMsgHdr header = new StructNlMsgHdr();
+ header.nlmsg_type = RTM_NEWLINK;
+ header.nlmsg_pid = 0;
+ header.nlmsg_seq = 0;
+ header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ StructIfinfoMsg ifInfo =
+ new StructIfinfoMsg(
+ (short) 0 /* family */,
+ 0 /* type */,
+ Os.if_nametoindex(mIfName),
+ (IFF_MULTICAST | IFF_NOARP) /* flags */,
+ 0xffffffff /* change */);
+
+ // Nested attributes
+ // IFLA_AF_SPEC
+ // AF_INET6
+ // IFLA_INET6_ADDR_GEN_MODE
+ StructNlAttr addrGenMode =
+ new StructNlAttr(IFLA_INET6_ADDR_GEN_MODE, (byte) IN6_ADDR_GEN_MODE_NONE);
+ StructNlAttr afInet6 = new StructNlAttr((short) AF_INET6, addrGenMode);
+ StructNlAttr afSpec = new StructNlAttr(IFLA_AF_SPEC, afInet6);
+
+ final int msgLength =
+ StructNlMsgHdr.STRUCT_SIZE
+ + StructIfinfoMsg.STRUCT_SIZE
+ + afSpec.getAlignedLength();
+ byte[] msg = new byte[msgLength];
+ ByteBuffer buf = ByteBuffer.wrap(msg);
+ buf.order(ByteOrder.nativeOrder());
+
+ header.nlmsg_len = msgLength;
+ header.pack(buf);
+ ifInfo.pack(buf);
+ afSpec.pack(buf);
+
+ if (buf.position() != msgLength) {
+ throw new AssertionError(
+ String.format(
+ "Unexpected netlink message size (actual = %d, expected = %d)",
+ buf.position(), msgLength));
+ }
+
+ if (DBG) {
+ Log.d(TAG, "ADDR_GEN_MODE message is:");
+ Log.d(TAG, HexDump.dumpHexString(msg));
+ }
+
+ try {
+ NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed to set ADDR_GEN_MODE to NONE", e);
+ }
+ }
}
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index 4028014..61b6eac 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -176,7 +176,7 @@
// TODO (b/323300829): add test for removing an OT address
@Test
- public void tunInterface_joinedNetwork_otAddressesAddedToTunInterface() throws Exception {
+ public void tunInterface_joinedNetwork_otAndTunAddressesMatch() throws Exception {
mController.joinAndWait(DEFAULT_DATASET);
List<Inet6Address> otAddresses = mOtCtl.getAddresses();
@@ -185,9 +185,12 @@
// that we can write assertThat() in the Predicate
waitFor(
() -> {
- String ifconfig = runShellCommand("ifconfig thread-wpan");
- return otAddresses.stream()
- .allMatch(addr -> ifconfig.contains(addr.getHostAddress()));
+ List<Inet6Address> tunAddresses =
+ getIpv6LinkAddresses("thread-wpan").stream()
+ .map(linkAddr -> (Inet6Address) linkAddr.getAddress())
+ .toList();
+ return otAddresses.containsAll(tunAddresses)
+ && tunAddresses.containsAll(otAddresses);
},
TUN_ADDR_UPDATE_TIMEOUT);
}
@@ -307,6 +310,23 @@
.isFalse();
}
+ @Test
+ public void toggleThreadNetwork_routeFromPreviousNetDataIsRemoved() throws Exception {
+ ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ mController.joinAndWait(DEFAULT_DATASET);
+ mOtCtl.executeCommand("prefix add " + TEST_NO_SLAAC_PREFIX + " pros med");
+ mOtCtl.executeCommand("netdata register");
+
+ mController.leaveAndWait();
+ mOtCtl.factoryReset();
+ mController.joinAndWait(DEFAULT_DATASET);
+
+ LinkProperties lp = cm.getLinkProperties(getThreadNetwork(CALLBACK_TIMEOUT));
+ assertThat(lp).isNotNull();
+ assertThat(lp.getRoutes().stream().anyMatch(r -> r.matches(TEST_NO_SLAAC_PREFIX_ADDRESS)))
+ .isFalse();
+ }
+
// TODO (b/323300829): add more tests for integration with linux platform and
// ConnectivityService
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
index 78f5770..ada46c8 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
@@ -301,7 +301,7 @@
return false;
}
- public static List<LinkAddress> getIpv6LinkAddresses(String interfaceName) throws IOException {
+ public static List<LinkAddress> getIpv6LinkAddresses(String interfaceName) {
List<LinkAddress> addresses = new ArrayList<>();
final String cmd = " ip -6 addr show dev " + interfaceName;
final String output = runShellCommandOrThrow(cmd);
diff --git a/thread/tests/multidevices/AndroidTest.xml b/thread/tests/multidevices/AndroidTest.xml
index a2ea9aa..8b2bed3 100644
--- a/thread/tests/multidevices/AndroidTest.xml
+++ b/thread/tests/multidevices/AndroidTest.xml
@@ -44,7 +44,7 @@
<test class="com.android.tradefed.testtype.mobly.MoblyBinaryHostTest">
<!-- The mobly-par-file-name should match the module name -->
- <option name="mobly-par-file-name" value="ThreadMultiDeviceTestCases" />
+ <option name="mobly-par-file-name" value="ThreadNetworkMultiDeviceTests" />
<!-- Timeout limit in milliseconds for all test cases of the python binary -->
<option name="mobly-test-timeout" value="180000" />
</test>
diff --git a/thread/tests/unit/Android.bp b/thread/tests/unit/Android.bp
index 3365cd0..9404d1b 100644
--- a/thread/tests/unit/Android.bp
+++ b/thread/tests/unit/Android.bp
@@ -33,6 +33,7 @@
"mts-tethering",
],
static_libs: [
+ "androidx.test.rules",
"frameworks-base-testutils",
"framework-connectivity-pre-jarjar",
"framework-connectivity-t-pre-jarjar",
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
index 52a9dd9..cf6eb44 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
@@ -69,6 +69,7 @@
import android.provider.Settings;
import android.util.AtomicFile;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -97,6 +98,12 @@
/** Unit tests for {@link ThreadNetworkControllerService}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
+// This test doesn't really need to run on the UI thread, but @Before and @Test annotated methods
+// need to run in the same thread because there are code in {@code ThreadNetworkControllerService}
+// checking that all its methods are running in the thread of the handler it's using. This is due
+// to a bug in TestLooper that it executes all tasks on the current thread rather than the thread
+// associated to the backed Looper object.
+@UiThreadTest
public final class ThreadNetworkControllerServiceTest {
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset new":
// Active Timestamp: 1
diff --git a/tools/aospify_device.sh b/tools/aospify_device.sh
index f25ac9d..0176093 100755
--- a/tools/aospify_device.sh
+++ b/tools/aospify_device.sh
@@ -3,10 +3,14 @@
# Script to swap core networking modules in a GMS userdebug device to AOSP modules, by remounting
# the system partition and replacing module prebuilts. This is only to be used for local testing,
# and should only be used on userdebug devices that support "adb root" and remounting the system
-# partition using overlayfs.
+# partition using overlayfs. The setup wizard should be cleared before running the script.
#
# Usage: aospify_device.sh [device_serial]
-# Reset by wiping data (adb reboot bootloader && fastboot erase userdata && fastboot reboot).
+#
+# Reset with "adb enable-verity", then wiping data (from Settings, or:
+# "adb reboot bootloader && fastboot erase userdata && fastboot reboot").
+# Some devices output errors like "Overlayfs teardown failed" on "enable-verity" but it still works
+# (/mnt/scratch should be deleted).
#
# This applies to NetworkStack, CaptivePortalLogin, dnsresolver, tethering, cellbroadcast modules,
# which generally need to be preloaded together (core networking modules + cellbroadcast which
@@ -37,6 +41,10 @@
else
rm -f /tmp/decompressed_$aosp_apex_name.apex
$ANDROID_HOST_OUT/bin/deapexer decompress --input $ANDROID_PRODUCT_OUT/system/apex/$aosp_apex_name.capex --output /tmp/decompressed_$aosp_apex_name.apex
+ if ! $ADB_CMD shell ls /system/apex/$original_apex_name.apex 1>/dev/null 2>/dev/null; then
+ # Filename observed on some phones, even though it is not actually compressed
+ original_apex_name=${original_apex_name}_compressed
+ fi
$ADB_CMD shell rm /system/apex/$original_apex_name.apex
$ADB_CMD push /tmp/decompressed_$aosp_apex_name.apex /system/apex/$aosp_apex_name.apex
rm /tmp/decompressed_$aosp_apex_name.apex
@@ -47,7 +55,7 @@
local app_type=$1
local original_apk_name=$2
local aosp_apk_name=$3
- $ADB_CMD shell rm /system/$app_type/$original_apk_name/$original_apk_name.apk
+ $ADB_CMD shell rm /system/$app_type/$original_apk_name/$original_apk_name*.apk
$ADB_CMD push $ANDROID_PRODUCT_OUT/system/$app_type/$aosp_apk_name/$aosp_apk_name.apk /system/$app_type/$original_apk_name/
}
@@ -97,7 +105,7 @@
exit 1
fi
-if ! $ADB_CMD wait-for-device shell pm path com.google.android.networkstack; then
+if ! $ADB_CMD wait-for-device shell pm path com.google.android.networkstack 1>/dev/null 2>/dev/null; then
echo "This device is already not using GMS modules"
exit 1
fi
@@ -122,8 +130,7 @@
$ADB_CMD reboot
echo "Waiting for boot..."
-$ADB_CMD wait-for-device;
-until [[ $($ADB_CMD shell getprop sys.boot_completed) == 1 ]]; do
+until [[ $($ADB_CMD wait-for-device shell getprop sys.boot_completed) == 1 ]]; do
sleep 1;
done
@@ -146,7 +153,12 @@
# Update the networkstack privapp-permissions allowlist
rm -f /tmp/pulled_privapp-permissions.xml
-$ADB_CMD pull /system/etc/permissions/privapp-permissions-google.xml /tmp/pulled_privapp-permissions.xml
+networkstack_permissions=/system/etc/permissions/GoogleNetworkStack_permissions.xml
+if ! $ADB_CMD shell ls $networkstack_permissions 1>/dev/null 2>/dev/null; then
+ networkstack_permissions=/system/etc/permissions/privapp-permissions-google.xml
+fi
+
+$ADB_CMD pull $networkstack_permissions /tmp/pulled_privapp-permissions.xml
# Remove last </permission> line, and the permissions for com.google.android.networkstack
sed -nE '1,/<\/permissions>/p' /tmp/pulled_privapp-permissions.xml \
@@ -156,7 +168,7 @@
>> /tmp/modified_privapp-permissions.xml
echo '</permissions>' >> /tmp/modified_privapp-permissions.xml
-$ADB_CMD push /tmp/modified_privapp-permissions.xml /system/etc/permissions/privapp-permissions-google.xml
+$ADB_CMD push /tmp/modified_privapp-permissions.xml $networkstack_permissions
rm /tmp/pulled_privapp-permissions.xml /tmp/modified_privapp-permissions.xml