Merge "TestNetworkManager: add note on kernel version expectation"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4eeaf51..4774866 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -171,23 +171,6 @@
]
}
],
- "auto-postsubmit": [
- // Test tag for automotive targets. These are only running in postsubmit so as to harden the
- // automotive targets to avoid introducing additional test flake and build time. The plan for
- // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
- // Additionally, this tag is used in targeted test suites to limit resource usage on the test
- // infra during the hardening phase.
- // TODO: this tag to be removed once the above is no longer an issue.
- {
- "name": "FrameworksNetTests"
- },
- {
- "name": "FrameworksNetIntegrationTests"
- },
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
"imports": [
{
"path": "frameworks/base/core/java/android/net"
diff --git a/bpf_progs/bpf_shared.h b/bpf_progs/bpf_shared.h
index fd449a3..85b9f86 100644
--- a/bpf_progs/bpf_shared.h
+++ b/bpf_progs/bpf_shared.h
@@ -148,6 +148,7 @@
#endif // __cplusplus
+// LINT.IfChange(match_type)
enum UidOwnerMatchType {
NO_MATCH = 0,
HAPPY_BOX_MATCH = (1 << 0),
@@ -163,6 +164,7 @@
OEM_DENY_2_MATCH = (1 << 10),
OEM_DENY_3_MATCH = (1 << 11),
};
+// LINT.ThenChange(packages/modules/Connectivity/service/src/com/android/server/BpfNetMaps.java)
enum BpfPermissionMatch {
BPF_PERMISSION_INTERNET = 1 << 2,
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 39cd7f3..02083ff 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -5903,6 +5903,7 @@
*
* @param chain target chain.
* @param enable whether the chain should be enabled.
+ * @throws UnsupportedOperationException if called on pre-T devices.
* @throws IllegalStateException if enabling or disabling the firewall chain failed.
* @hide
*/
@@ -5921,6 +5922,29 @@
}
/**
+ * Get the specified firewall chain status.
+ *
+ * @param chain target chain.
+ * @return {@code true} if chain is enabled, {@code false} if chain is disabled.
+ * @throws UnsupportedOperationException if called on pre-T devices.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public boolean getFirewallChainEnabled(@FirewallChain final int chain) {
+ try {
+ return mService.getFirewallChainEnabled(chain);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Replaces the contents of the specified UID-based firewall chain.
*
* @param chain target chain to replace.
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index bc73769..29fea00 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -244,5 +244,7 @@
void setFirewallChainEnabled(int chain, boolean enable);
+ boolean getFirewallChainEnabled(int chain);
+
void replaceFirewallChain(int chain, in int[] uids);
}
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
index 71d3e4f..f058f94 100644
--- a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
+++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -16,12 +16,14 @@
package com.android.server.ethernet;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.EthernetNetworkSpecifier;
import android.net.EthernetNetworkUpdateRequest;
import android.net.IEthernetManager;
import android.net.IEthernetServiceListener;
@@ -29,6 +31,7 @@
import android.net.ITetheredInterfaceCallback;
import android.net.IpConfiguration;
import android.net.NetworkCapabilities;
+import android.net.NetworkSpecifier;
import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
@@ -216,19 +219,39 @@
"EthernetServiceImpl");
}
- private void maybeValidateTestCapabilities(final String iface,
- @Nullable final NetworkCapabilities nc) {
+ private void validateOrSetNetworkSpecifier(String iface, NetworkCapabilities nc) {
+ final NetworkSpecifier spec = nc.getNetworkSpecifier();
+ if (spec == null) {
+ nc.setNetworkSpecifier(new EthernetNetworkSpecifier(iface));
+ return;
+ }
+ if (!(spec instanceof EthernetNetworkSpecifier)) {
+ throw new IllegalArgumentException("Invalid specifier type for request.");
+ }
+ if (!((EthernetNetworkSpecifier) spec).getInterfaceName().matches(iface)) {
+ throw new IllegalArgumentException("Invalid interface name set on specifier.");
+ }
+ }
+
+ private void maybeValidateTestCapabilities(String iface, NetworkCapabilities nc) {
if (!mTracker.isValidTestInterface(iface)) {
return;
}
- // For test interfaces, only null or capabilities that include TRANSPORT_TEST are
- // allowed.
- if (nc != null && !nc.hasTransport(TRANSPORT_TEST)) {
+ if (!nc.hasTransport(TRANSPORT_TEST)) {
throw new IllegalArgumentException(
"Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST.");
}
}
+ private void maybeValidateEthernetTransport(String iface, NetworkCapabilities nc) {
+ if (mTracker.isValidTestInterface(iface)) {
+ return;
+ }
+ if (!nc.hasSingleTransport(TRANSPORT_ETHERNET)) {
+ throw new IllegalArgumentException("Invalid transport type for request.");
+ }
+ }
+
private void enforceAdminPermission(final String iface, boolean enforceAutomotive,
final String logMessage) {
if (mTracker.isValidTestInterface(iface)) {
@@ -251,12 +274,17 @@
// TODO: validate that iface is listed in overlay config_ethernet_interfaces
// only automotive devices are allowed to set the NetworkCapabilities using this API
- enforceAdminPermission(iface, request.getNetworkCapabilities() != null,
- "updateConfiguration() with non-null capabilities");
- maybeValidateTestCapabilities(iface, request.getNetworkCapabilities());
+ final NetworkCapabilities nc = request.getNetworkCapabilities();
+ enforceAdminPermission(
+ iface, nc != null, "updateConfiguration() with non-null capabilities");
+ if (nc != null) {
+ validateOrSetNetworkSpecifier(iface, nc);
+ maybeValidateTestCapabilities(iface, nc);
+ maybeValidateEthernetTransport(iface, nc);
+ }
mTracker.updateConfiguration(
- iface, request.getIpConfiguration(), request.getNetworkCapabilities(), listener);
+ iface, request.getIpConfiguration(), nc, listener);
}
@Override
diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java
index d99e164..7c801d7 100644
--- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java
+++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java
@@ -78,6 +78,7 @@
private final long mBucketDuration;
private final boolean mOnlyTags;
+ private final boolean mWipeOnError;
private long mPersistThresholdBytes = 2 * MB_IN_BYTES;
private NetworkStats mLastSnapshot;
@@ -102,6 +103,7 @@
// slack to avoid overflow
mBucketDuration = YEAR_IN_MILLIS;
mOnlyTags = false;
+ mWipeOnError = true;
mPending = null;
mSinceBoot = new NetworkStatsCollection(mBucketDuration);
@@ -113,7 +115,8 @@
* Persisted recorder.
*/
public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
- DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
+ DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags,
+ boolean wipeOnError) {
mRotator = Objects.requireNonNull(rotator, "missing FileRotator");
mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver");
mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager");
@@ -121,6 +124,7 @@
mBucketDuration = bucketDuration;
mOnlyTags = onlyTags;
+ mWipeOnError = wipeOnError;
mPending = new NetworkStatsCollection(bucketDuration);
mSinceBoot = new NetworkStatsCollection(bucketDuration);
@@ -552,7 +556,9 @@
}
mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0);
}
-
- mRotator.deleteAll();
+ // Delete all files if this recorder is set wipe on error.
+ if (mWipeOnError) {
+ mRotator.deleteAll();
+ }
}
}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index e41034a..424dcd9 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -800,11 +800,14 @@
mSystemReady = true;
// create data recorders along with historical rotators
- mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false, mStatsDir);
- mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, mStatsDir);
- mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, mStatsDir);
+ mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false, mStatsDir,
+ true /* wipeOnError */);
+ mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, mStatsDir,
+ true /* wipeOnError */);
+ mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, mStatsDir,
+ true /* wipeOnError */);
mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true,
- mStatsDir);
+ mStatsDir, true /* wipeOnError */);
updatePersistThresholdsLocked();
@@ -869,12 +872,13 @@
private NetworkStatsRecorder buildRecorder(
String prefix, NetworkStatsSettings.Config config, boolean includeTags,
- File baseDir) {
+ File baseDir, boolean wipeOnError) {
final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
Context.DROPBOX_SERVICE);
return new NetworkStatsRecorder(new FileRotator(
baseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
- mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags);
+ mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags,
+ wipeOnError);
}
@GuardedBy("mStatsLock")
@@ -971,12 +975,17 @@
final NetworkStatsRecorder[] legacyRecorders;
if (runComparison) {
final File legacyBaseDir = mDeps.getLegacyStatsDir();
+ // Set wipeOnError flag false so the recorder won't damage persistent data if reads
+ // failed and calling deleteAll.
legacyRecorders = new NetworkStatsRecorder[]{
- buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false, legacyBaseDir),
- buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, legacyBaseDir),
- buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, legacyBaseDir),
- buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true, legacyBaseDir)
- };
+ buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false, legacyBaseDir,
+ false /* wipeOnError */),
+ buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false, legacyBaseDir,
+ false /* wipeOnError */),
+ buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false, legacyBaseDir,
+ false /* wipeOnError */),
+ buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true, legacyBaseDir,
+ false /* wipeOnError */)};
} else {
legacyRecorders = null;
}
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index 2780044..49392e0 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -82,13 +82,6 @@
return (jint)status.code();
}
-static jint native_setChildChain(JNIEnv* env, jobject self, jint childChain, jboolean enable) {
- auto chain = static_cast<ChildChain>(childChain);
- int res = mTc.toggleUidOwnerMap(chain, enable);
- if (res) ALOGE("%s failed, error code = %d", __func__, res);
- return (jint)res;
-}
-
static jint native_replaceUidChain(JNIEnv* env, jobject self, jstring name, jboolean isAllowlist,
jintArray jUids) {
const ScopedUtfChars chainNameUtf8(env, name);
@@ -199,8 +192,6 @@
(void*)native_addNiceApp},
{"native_removeNiceApp", "(I)I",
(void*)native_removeNiceApp},
- {"native_setChildChain", "(IZ)I",
- (void*)native_setChildChain},
{"native_replaceUidChain", "(Ljava/lang/String;Z[I)I",
(void*)native_replaceUidChain},
{"native_setUidRule", "(III)I",
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 4dc056d..9331548 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -451,53 +451,6 @@
return 0;
}
-int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
- std::lock_guard guard(mMutex);
- uint32_t key = UID_RULES_CONFIGURATION_KEY;
- auto oldConfigure = mConfigurationMap.readValue(key);
- if (!oldConfigure.ok()) {
- ALOGE("Cannot read the old configuration from map: %s",
- oldConfigure.error().message().c_str());
- return -oldConfigure.error().code();
- }
- uint32_t match;
- switch (chain) {
- case DOZABLE:
- match = DOZABLE_MATCH;
- break;
- case STANDBY:
- match = STANDBY_MATCH;
- break;
- case POWERSAVE:
- match = POWERSAVE_MATCH;
- break;
- case RESTRICTED:
- match = RESTRICTED_MATCH;
- break;
- case LOW_POWER_STANDBY:
- match = LOW_POWER_STANDBY_MATCH;
- break;
- case OEM_DENY_1:
- match = OEM_DENY_1_MATCH;
- break;
- case OEM_DENY_2:
- match = OEM_DENY_2_MATCH;
- break;
- case OEM_DENY_3:
- match = OEM_DENY_3_MATCH;
- break;
- default:
- return -EINVAL;
- }
- BpfConfig newConfiguration =
- enable ? (oldConfigure.value() | match) : (oldConfigure.value() & ~match);
- Status res = mConfigurationMap.writeValue(key, newConfiguration, BPF_EXIST);
- if (!isOk(res)) {
- ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, res.msg().c_str());
- }
- return -res.code();
-}
-
Status TrafficController::swapActiveStatsMap() {
std::lock_guard guard(mMutex);
diff --git a/service/native/include/TrafficController.h b/service/native/include/TrafficController.h
index 8512929..14c5eaf 100644
--- a/service/native/include/TrafficController.h
+++ b/service/native/include/TrafficController.h
@@ -71,8 +71,6 @@
netdutils::Status updateUidOwnerMap(const uint32_t uid,
UidOwnerMatchType matchType, IptOp op) EXCLUDES(mMutex);
- int toggleUidOwnerMap(ChildChain chain, bool enable) EXCLUDES(mMutex);
-
static netdutils::StatusOr<std::unique_ptr<netdutils::NetlinkListenerInterface>>
makeSkDestroyListener();
diff --git a/service/proguard.flags b/service/proguard.flags
index 94397ab..cffa490 100644
--- a/service/proguard.flags
+++ b/service/proguard.flags
@@ -8,11 +8,10 @@
# Prevent proguard from stripping out any nearby-service and fast-pair-lite-protos fields.
-keep class com.android.server.nearby.NearbyService { *; }
--keep class com.android.server.nearby.service.proto { *; }
# The lite proto runtime uses reflection to access fields based on the names in
# the schema, keep all the fields.
# This replicates the base proguard rule used by the build by default
# (proguard_basic_keeps.flags), but needs to be specified here because the
# com.google.protobuf package is jarjared to the below package.
--keepclassmembers class * extends com.android.connectivity.com.google.protobuf.MessageLite { <fields>; }
+-keepclassmembers class * extends android.net.connectivity.com.google.protobuf.MessageLite { <fields>; }
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index 151d0e3..3ee3ea1 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -16,15 +16,30 @@
package com.android.server;
+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_OEM_DENY_1;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
+import static android.system.OsConstants.EINVAL;
+import static android.system.OsConstants.ENOENT;
import static android.system.OsConstants.EOPNOTSUPP;
import android.net.INetd;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
+import android.util.SparseLongArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.BpfMap;
+import com.android.net.module.util.Struct.U32;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -41,6 +56,56 @@
private static final boolean USE_NETD = !SdkLevel.isAtLeastT();
private static boolean sInitialized = false;
+ // Lock for sConfigurationMap entry for UID_RULES_CONFIGURATION_KEY.
+ // This entry is not accessed by others.
+ // BpfNetMaps acquires this lock while sequence of read, modify, and write.
+ private static final Object sUidRulesConfigBpfMapLock = new Object();
+
+ private static final String CONFIGURATION_MAP_PATH =
+ "/sys/fs/bpf/netd_shared/map_netd_configuration_map";
+ private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
+ private static BpfMap<U32, U32> sConfigurationMap = null;
+
+ // LINT.IfChange(match_type)
+ private static final long NO_MATCH = 0;
+ private static final long HAPPY_BOX_MATCH = (1 << 0);
+ private static final long PENALTY_BOX_MATCH = (1 << 1);
+ private static final long DOZABLE_MATCH = (1 << 2);
+ private static final long STANDBY_MATCH = (1 << 3);
+ private static final long POWERSAVE_MATCH = (1 << 4);
+ private static final long RESTRICTED_MATCH = (1 << 5);
+ private static final long LOW_POWER_STANDBY_MATCH = (1 << 6);
+ private static final long IIF_MATCH = (1 << 7);
+ private static final long LOCKDOWN_VPN_MATCH = (1 << 8);
+ private static final long OEM_DENY_1_MATCH = (1 << 9);
+ private static final long OEM_DENY_2_MATCH = (1 << 10);
+ private static final long OEM_DENY_3_MATCH = (1 << 11);
+ // LINT.ThenChange(packages/modules/Connectivity/bpf_progs/bpf_shared.h)
+
+ // TODO: Use Java BpfMap instead of JNI code (TrafficController) for map update.
+ // Currently, BpfNetMaps uses TrafficController for map update and TrafficController
+ // (changeUidOwnerRule and toggleUidOwnerMap) also does conversion from "firewall chain" to
+ // "match". Migrating map update from JNI to Java BpfMap will solve this duplication.
+ private static final SparseLongArray FIREWALL_CHAIN_TO_MATCH = new SparseLongArray();
+ static {
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_DOZABLE, DOZABLE_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_STANDBY, STANDBY_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_POWERSAVE, POWERSAVE_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_RESTRICTED, RESTRICTED_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_LOW_POWER_STANDBY, LOW_POWER_STANDBY_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_OEM_DENY_1, OEM_DENY_1_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_OEM_DENY_2, OEM_DENY_2_MATCH);
+ FIREWALL_CHAIN_TO_MATCH.put(FIREWALL_CHAIN_OEM_DENY_3, OEM_DENY_3_MATCH);
+ }
+
+ /**
+ * Only tests or BpfNetMaps#ensureInitialized can call this function.
+ */
+ @VisibleForTesting
+ public static void initialize(final Dependencies deps) {
+ sConfigurationMap = deps.getConfigurationMap();
+ }
+
/**
* Initializes the class if it is not already initialized. This method will open maps but not
* cause any other effects. This method may be called multiple times on any thread.
@@ -50,10 +115,30 @@
if (!USE_NETD) {
System.loadLibrary("service-connectivity");
native_init();
+ initialize(new Dependencies());
}
sInitialized = true;
}
+ /**
+ * Dependencies of BpfNetMaps, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Get configuration BPF map.
+ */
+ public BpfMap<U32, U32> getConfigurationMap() {
+ try {
+ return new BpfMap<>(
+ CONFIGURATION_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, U32.class);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Cannot open netd configuration map: " + e);
+ return null;
+ }
+ }
+ }
+
/** Constructor used after T that doesn't need to use netd anymore. */
public BpfNetMaps() {
this(null);
@@ -61,17 +146,35 @@
if (USE_NETD) throw new IllegalArgumentException("BpfNetMaps need to use netd before T");
}
- public BpfNetMaps(INetd netd) {
+ public BpfNetMaps(final INetd netd) {
ensureInitialized();
mNetd = netd;
}
+ /**
+ * Get corresponding match from firewall chain.
+ */
+ @VisibleForTesting
+ public long getMatchByFirewallChain(final int chain) {
+ final long match = FIREWALL_CHAIN_TO_MATCH.get(chain, NO_MATCH);
+ if (match == NO_MATCH) {
+ throw new ServiceSpecificException(EINVAL, "Invalid firewall chain: " + chain);
+ }
+ return match;
+ }
+
private void maybeThrow(final int err, final String msg) {
if (err != 0) {
throw new ServiceSpecificException(err, msg + ": " + Os.strerror(err));
}
}
+ private void throwIfUseNetd(final String msg) {
+ if (USE_NETD) {
+ throw new UnsupportedOperationException(msg);
+ }
+ }
+
/**
* Add naughty app bandwidth rule for specific app
*
@@ -125,12 +228,56 @@
*
* @param childChain target chain to enable
* @param enable whether to enable or disable child chain.
+ * @throws UnsupportedOperationException if called on pre-T devices.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
public void setChildChain(final int childChain, final boolean enable) {
- final int err = native_setChildChain(childChain, enable);
- maybeThrow(err, "Unable to set child chain");
+ throwIfUseNetd("setChildChain is not available on pre-T devices");
+
+ final long match = getMatchByFirewallChain(childChain);
+ try {
+ synchronized (sUidRulesConfigBpfMapLock) {
+ final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
+ if (config == null) {
+ throw new ServiceSpecificException(ENOENT,
+ "Unable to get firewall chain status: sConfigurationMap does not have"
+ + " entry for UID_RULES_CONFIGURATION_KEY");
+ }
+ final long newConfig = enable ? (config.val | match) : (config.val & (~match));
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(newConfig));
+ }
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno,
+ "Unable to set child chain: " + Os.strerror(e.errno));
+ }
+ }
+
+ /**
+ * Get the specified firewall chain status.
+ *
+ * @param childChain target chain
+ * @return {@code true} if chain is enabled, {@code false} if chain is not enabled.
+ * @throws UnsupportedOperationException if called on pre-T devices.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ public boolean getChainEnabled(final int childChain) {
+ throwIfUseNetd("getChainEnabled is not available on pre-T devices");
+
+ final long match = getMatchByFirewallChain(childChain);
+ try {
+ final U32 config = sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
+ if (config == null) {
+ throw new ServiceSpecificException(ENOENT,
+ "Unable to get firewall chain status: sConfigurationMap does not have"
+ + " entry for UID_RULES_CONFIGURATION_KEY");
+ }
+ return (config.val & match) != 0;
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno,
+ "Unable to get firewall chain status: " + Os.strerror(e.errno));
+ }
}
/**
@@ -279,7 +426,6 @@
private native int native_removeNaughtyApp(int uid);
private native int native_addNiceApp(int uid);
private native int native_removeNiceApp(int uid);
- private native int native_setChildChain(int childChain, boolean enable);
private native int native_replaceUidChain(String name, boolean isAllowlist, int[] uids);
private native int native_setUidRule(int childChain, int uid, int firewallRule);
private native int native_addUidInterfaceRules(String ifName, int[] uids);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 853a1a2..6568654 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -11384,6 +11384,13 @@
}
@Override
+ public boolean getFirewallChainEnabled(final int chain) {
+ enforceNetworkStackOrSettingsPermission();
+
+ return mBpfNetMaps.getChainEnabled(chain);
+ }
+
+ @Override
public void replaceFirewallChain(final int chain, final int[] uids) {
enforceNetworkStackOrSettingsPermission();
diff --git a/tests/native/connectivity_native_test.cpp b/tests/native/connectivity_native_test.cpp
index 29b14ca..3db5265 100644
--- a/tests/native/connectivity_native_test.cpp
+++ b/tests/native/connectivity_native_test.cpp
@@ -233,29 +233,54 @@
}
TEST_F(ConnectivityNativeBinderTest, BlockNegativePort) {
- ndk::ScopedAStatus status = mService->blockPortForBind(-1);
+ int retry = 0;
+ ndk::ScopedAStatus status;
+ do {
+ status = mService->blockPortForBind(-1);
+ // TODO: find out why transaction failed is being thrown on the first attempt.
+ } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
TEST_F(ConnectivityNativeBinderTest, UnblockNegativePort) {
- ndk::ScopedAStatus status = mService->unblockPortForBind(-1);
+ int retry = 0;
+ ndk::ScopedAStatus status;
+ do {
+ status = mService->unblockPortForBind(-1);
+ // TODO: find out why transaction failed is being thrown on the first attempt.
+ } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
TEST_F(ConnectivityNativeBinderTest, BlockMaxPort) {
- ndk::ScopedAStatus status = mService->blockPortForBind(65536);
+ int retry = 0;
+ ndk::ScopedAStatus status;
+ do {
+ status = mService->blockPortForBind(65536);
+ // TODO: find out why transaction failed is being thrown on the first attempt.
+ } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
TEST_F(ConnectivityNativeBinderTest, UnblockMaxPort) {
- ndk::ScopedAStatus status = mService->unblockPortForBind(65536);
+ int retry = 0;
+ ndk::ScopedAStatus status;
+ do {
+ status = mService->unblockPortForBind(65536);
+ // TODO: find out why transaction failed is being thrown on the first attempt.
+ } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
TEST_F(ConnectivityNativeBinderTest, CheckPermission) {
+ int retry = 0;
int curUid = getuid();
EXPECT_EQ(0, seteuid(FIRST_APPLICATION_UID + 2000)) << "seteuid failed: " << strerror(errno);
- ndk::ScopedAStatus status = mService->blockPortForBind(5555);
+ ndk::ScopedAStatus status;
+ do {
+ status = mService->blockPortForBind(5555);
+ // TODO: find out why transaction failed is being thrown on the first attempt.
+ } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
EXPECT_EQ(EX_SECURITY, status.getExceptionCode());
EXPECT_EQ(0, seteuid(curUid)) << "seteuid failed: " << strerror(errno);
}
diff --git a/tests/unit/java/android/net/NetworkStatsRecorderTest.java b/tests/unit/java/android/net/NetworkStatsRecorderTest.java
new file mode 100644
index 0000000..fad11a3
--- /dev/null
+++ b/tests/unit/java/android/net/NetworkStatsRecorderTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *i
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.net.NetworkStats;
+import android.os.DropBoxManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.FileRotator;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+
+@RunWith(DevSdkIgnoreRunner.class)
+@SmallTest
+@DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
+public final class NetworkStatsRecorderTest {
+ private static final String TAG = NetworkStatsRecorderTest.class.getSimpleName();
+
+ private static final String TEST_PREFIX = "test";
+
+ @Mock private DropBoxManager mDropBox;
+ @Mock private NetworkStats.NonMonotonicObserver mObserver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ private NetworkStatsRecorder buildRecorder(FileRotator rotator, boolean wipeOnError) {
+ return new NetworkStatsRecorder(rotator, mObserver, mDropBox, TEST_PREFIX,
+ HOUR_IN_MILLIS, false /* includeTags */, wipeOnError);
+ }
+
+ @Test
+ public void testWipeOnError() throws Exception {
+ final FileRotator rotator = mock(FileRotator.class);
+ final NetworkStatsRecorder wipeOnErrorRecorder = buildRecorder(rotator, true);
+
+ // Assuming that the rotator gets an exception happened when read data.
+ doThrow(new IOException()).when(rotator).readMatching(any(), anyLong(), anyLong());
+ wipeOnErrorRecorder.getOrLoadPartialLocked(Long.MIN_VALUE, Long.MAX_VALUE);
+ // Verify that the files will be deleted.
+ verify(rotator, times(1)).deleteAll();
+ reset(rotator);
+
+ final NetworkStatsRecorder noWipeOnErrorRecorder = buildRecorder(rotator, false);
+ doThrow(new IOException()).when(rotator).readMatching(any(), anyLong(), anyLong());
+ noWipeOnErrorRecorder.getOrLoadPartialLocked(Long.MIN_VALUE, Long.MAX_VALUE);
+ // Verify that the rotator won't delete files.
+ verify(rotator, never()).deleteAll();
+ }
+}
diff --git a/tests/unit/java/com/android/server/BpfNetMapsTest.java b/tests/unit/java/com/android/server/BpfNetMapsTest.java
index f07a10d..99e7ecc 100644
--- a/tests/unit/java/com/android/server/BpfNetMapsTest.java
+++ b/tests/unit/java/com/android/server/BpfNetMapsTest.java
@@ -16,43 +16,93 @@
package com.android.server;
+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_OEM_DENY_1;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
import static android.net.INetd.PERMISSION_INTERNET;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.mockito.Mockito.verify;
import android.net.INetd;
import android.os.Build;
+import android.os.ServiceSpecificException;
import androidx.test.filters.SmallTest;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.BpfMap;
+import com.android.net.module.util.Struct.U32;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
+import com.android.testutils.TestBpfMap;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public final class BpfNetMapsTest {
private static final String TAG = "BpfNetMapsTest";
+
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
private static final int TEST_UID = 10086;
private static final int[] TEST_UIDS = {10002, 10003};
private static final String IFNAME = "wlan0";
private static final String CHAINNAME = "fw_dozable";
+ private static final U32 UID_RULES_CONFIGURATION_KEY = new U32(0);
+ private static final List<Integer> FIREWALL_CHAINS = List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY,
+ FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_RESTRICTED,
+ FIREWALL_CHAIN_LOW_POWER_STANDBY,
+ FIREWALL_CHAIN_OEM_DENY_1,
+ FIREWALL_CHAIN_OEM_DENY_2,
+ FIREWALL_CHAIN_OEM_DENY_3
+ );
+
private BpfNetMaps mBpfNetMaps;
@Mock INetd mNetd;
+ private static final TestBpfMap<U32, U32> sConfigurationMap =
+ new TestBpfMap<>(U32.class, U32.class);
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mBpfNetMaps = new BpfNetMaps(mNetd);
+ BpfNetMaps.initialize(makeDependencies());
+ sConfigurationMap.clear();
+ }
+
+ private static BpfNetMaps.Dependencies makeDependencies() {
+ return new BpfNetMaps.Dependencies() {
+ @Override
+ public BpfMap<U32, U32> getConfigurationMap() {
+ return sConfigurationMap;
+ }
+ };
}
@Test
@@ -65,4 +115,154 @@
mBpfNetMaps.setNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
verify(mNetd).trafficSetNetPermForUids(PERMISSION_INTERNET, TEST_UIDS);
}
+
+ private void doTestGetChainEnabled(final List<Integer> enableChains) throws Exception {
+ long match = 0;
+ for (final int chain: enableChains) {
+ match |= mBpfNetMaps.getMatchByFirewallChain(chain);
+ }
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(match));
+
+ for (final int chain: FIREWALL_CHAINS) {
+ final String testCase = "EnabledChains: " + enableChains + " CheckedChain: " + chain;
+ if (enableChains.contains(chain)) {
+ assertTrue("Expected getChainEnabled returns True, " + testCase,
+ mBpfNetMaps.getChainEnabled(chain));
+ } else {
+ assertFalse("Expected getChainEnabled returns False, " + testCase,
+ mBpfNetMaps.getChainEnabled(chain));
+ }
+ }
+ }
+
+ private void doTestGetChainEnabled(final int enableChain) throws Exception {
+ doTestGetChainEnabled(List.of(enableChain));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetChainEnabled() throws Exception {
+ doTestGetChainEnabled(FIREWALL_CHAIN_DOZABLE);
+ doTestGetChainEnabled(FIREWALL_CHAIN_STANDBY);
+ doTestGetChainEnabled(FIREWALL_CHAIN_POWERSAVE);
+ doTestGetChainEnabled(FIREWALL_CHAIN_RESTRICTED);
+ doTestGetChainEnabled(FIREWALL_CHAIN_LOW_POWER_STANDBY);
+ doTestGetChainEnabled(FIREWALL_CHAIN_OEM_DENY_1);
+ doTestGetChainEnabled(FIREWALL_CHAIN_OEM_DENY_2);
+ doTestGetChainEnabled(FIREWALL_CHAIN_OEM_DENY_3);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetChainEnabledMultipleChainEnabled() throws Exception {
+ doTestGetChainEnabled(List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY));
+ doTestGetChainEnabled(List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY,
+ FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_RESTRICTED));
+ doTestGetChainEnabled(FIREWALL_CHAINS);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetChainEnabledInvalidChain() {
+ final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
+ assertThrows(expected, () -> mBpfNetMaps.getChainEnabled(-1 /* childChain */));
+ assertThrows(expected, () -> mBpfNetMaps.getChainEnabled(1000 /* childChain */));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testGetChainEnabledMissingConfiguration() {
+ // sConfigurationMap does not have entry for UID_RULES_CONFIGURATION_KEY
+ assertThrows(ServiceSpecificException.class,
+ () -> mBpfNetMaps.getChainEnabled(FIREWALL_CHAIN_DOZABLE));
+ }
+
+ @Test
+ @IgnoreAfter(Build.VERSION_CODES.S_V2)
+ public void testGetChainEnabledBeforeT() {
+ assertThrows(UnsupportedOperationException.class,
+ () -> mBpfNetMaps.getChainEnabled(FIREWALL_CHAIN_DOZABLE));
+ }
+
+ private void doTestSetChildChain(final List<Integer> testChains) throws Exception {
+ long expectedMatch = 0;
+ for (final int chain: testChains) {
+ expectedMatch |= mBpfNetMaps.getMatchByFirewallChain(chain);
+ }
+
+ assertEquals(0, sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
+
+ for (final int chain: testChains) {
+ mBpfNetMaps.setChildChain(chain, true /* enable */);
+ }
+ assertEquals(expectedMatch, sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
+
+ for (final int chain: testChains) {
+ mBpfNetMaps.setChildChain(chain, false /* enable */);
+ }
+ assertEquals(0, sConfigurationMap.getValue(UID_RULES_CONFIGURATION_KEY).val);
+ }
+
+ private void doTestSetChildChain(final int testChain) throws Exception {
+ doTestSetChildChain(List.of(testChain));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetChildChain() throws Exception {
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
+ doTestSetChildChain(FIREWALL_CHAIN_DOZABLE);
+ doTestSetChildChain(FIREWALL_CHAIN_STANDBY);
+ doTestSetChildChain(FIREWALL_CHAIN_POWERSAVE);
+ doTestSetChildChain(FIREWALL_CHAIN_RESTRICTED);
+ doTestSetChildChain(FIREWALL_CHAIN_LOW_POWER_STANDBY);
+ doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_1);
+ doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_2);
+ doTestSetChildChain(FIREWALL_CHAIN_OEM_DENY_3);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetChildChainMultipleChain() throws Exception {
+ sConfigurationMap.updateEntry(UID_RULES_CONFIGURATION_KEY, new U32(0));
+ doTestSetChildChain(List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY));
+ doTestSetChildChain(List.of(
+ FIREWALL_CHAIN_DOZABLE,
+ FIREWALL_CHAIN_STANDBY,
+ FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_RESTRICTED));
+ doTestSetChildChain(FIREWALL_CHAINS);
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetChildChainInvalidChain() {
+ final Class<ServiceSpecificException> expected = ServiceSpecificException.class;
+ assertThrows(expected,
+ () -> mBpfNetMaps.setChildChain(-1 /* childChain */, true /* enable */));
+ assertThrows(expected,
+ () -> mBpfNetMaps.setChildChain(1000 /* childChain */, true /* enable */));
+ }
+
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2)
+ public void testSetChildChainMissingConfiguration() {
+ // sConfigurationMap does not have entry for UID_RULES_CONFIGURATION_KEY
+ assertThrows(ServiceSpecificException.class,
+ () -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */));
+ }
+
+ @Test
+ @IgnoreAfter(Build.VERSION_CODES.S_V2)
+ public void testSetChildChainBeforeT() {
+ assertThrows(UnsupportedOperationException.class,
+ () -> mBpfNetMaps.setChildChain(FIREWALL_CHAIN_DOZABLE, true /* enable */));
+ }
}
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index e8702b9..8f1d3b8 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -1846,6 +1846,16 @@
startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
}
+ @Test
+ public void testStartPptp() throws Exception {
+ startPptp(true /* useMppe */);
+ }
+
+ @Test
+ public void testStartPptp_NoMppe() throws Exception {
+ startPptp(false /* useMppe */);
+ }
+
private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
assertNotNull(nc);
VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
@@ -1853,6 +1863,49 @@
assertEquals(type, ti.getType());
}
+ private void startPptp(boolean useMppe) throws Exception {
+ final VpnProfile profile = new VpnProfile("testProfile" /* key */);
+ profile.type = VpnProfile.TYPE_PPTP;
+ profile.name = "testProfileName";
+ profile.username = "userName";
+ profile.password = "thePassword";
+ profile.server = "192.0.2.123";
+ profile.mppe = useMppe;
+
+ doReturn(new Network[] { new Network(101) }).when(mConnectivityManager).getAllNetworks();
+ doReturn(new Network(102)).when(mConnectivityManager).registerNetworkAgent(any(), any(),
+ any(), any(), any(), any(), anyInt());
+
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
+ final TestDeps deps = (TestDeps) vpn.mDeps;
+
+ // TODO: use import when this is merged in all branches and there's no merge conflict
+ com.android.testutils.Cleanup.testAndCleanup(() -> {
+ final String[] mtpdArgs = deps.mtpdArgs.get(10, TimeUnit.SECONDS);
+ final String[] argsPrefix = new String[]{
+ EGRESS_IFACE, "pptp", profile.server, "1723", "name", profile.username,
+ "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute",
+ "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270"
+ };
+ assertArrayEquals(argsPrefix, Arrays.copyOf(mtpdArgs, argsPrefix.length));
+ if (useMppe) {
+ assertEquals(argsPrefix.length + 2, mtpdArgs.length);
+ assertEquals("+mppe", mtpdArgs[argsPrefix.length]);
+ assertEquals("-pap", mtpdArgs[argsPrefix.length + 1]);
+ } else {
+ assertEquals(argsPrefix.length + 1, mtpdArgs.length);
+ assertEquals("nomppe", mtpdArgs[argsPrefix.length]);
+ }
+
+ verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
+ any(), any(), any(), any(), anyInt());
+ }, () -> { // Cleanup
+ vpn.mVpnRunner.exitVpnRunner();
+ deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
+ vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
+ });
+ }
+
public void startRacoon(final String serverAddr, final String expectedAddr)
throws Exception {
final ConditionVariable legacyRunnerReady = new ConditionVariable();
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java
index b2b9f2c..a1d93a0 100644
--- a/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java
+++ b/tests/unit/java/com/android/server/ethernet/EthernetServiceImplTest.java
@@ -16,6 +16,7 @@
package com.android.server.ethernet;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static org.junit.Assert.assertThrows;
@@ -35,10 +36,12 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.EthernetNetworkSpecifier;
import android.net.EthernetNetworkUpdateRequest;
import android.net.INetworkInterfaceOutcomeReceiver;
import android.net.IpConfiguration;
import android.net.NetworkCapabilities;
+import android.net.StringNetworkSpecifier;
import android.os.Build;
import android.os.Handler;
@@ -56,10 +59,14 @@
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
public class EthernetServiceImplTest {
private static final String TEST_IFACE = "test123";
+ private static final NetworkCapabilities DEFAULT_CAPS = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE))
+ .build();
private static final EthernetNetworkUpdateRequest UPDATE_REQUEST =
new EthernetNetworkUpdateRequest.Builder()
.setIpConfiguration(new IpConfiguration())
- .setNetworkCapabilities(new NetworkCapabilities.Builder().build())
+ .setNetworkCapabilities(DEFAULT_CAPS)
.build();
private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_CAPABILITIES =
new EthernetNetworkUpdateRequest.Builder()
@@ -67,7 +74,7 @@
.build();
private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_IP_CONFIG =
new EthernetNetworkUpdateRequest.Builder()
- .setNetworkCapabilities(new NetworkCapabilities.Builder().build())
+ .setNetworkCapabilities(DEFAULT_CAPS)
.build();
private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
private EthernetServiceImpl mEthernetServiceImpl;
@@ -161,6 +168,41 @@
}
@Test
+ public void testUpdateConfigurationRejectsWithInvalidSpecifierType() {
+ final StringNetworkSpecifier invalidSpecifierType = new StringNetworkSpecifier("123");
+ final EthernetNetworkUpdateRequest request =
+ new EthernetNetworkUpdateRequest.Builder()
+ .setNetworkCapabilities(
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(invalidSpecifierType)
+ .build()
+ ).build();
+ assertThrows(IllegalArgumentException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(
+ "" /* iface */, request, null /* listener */);
+ });
+ }
+
+ @Test
+ public void testUpdateConfigurationRejectsWithInvalidSpecifierName() {
+ final String ifaceToUpdate = "eth0";
+ final String ifaceOnSpecifier = "wlan0";
+ EthernetNetworkUpdateRequest request =
+ new EthernetNetworkUpdateRequest.Builder()
+ .setNetworkCapabilities(
+ new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(
+ new EthernetNetworkSpecifier(ifaceOnSpecifier))
+ .build()
+ ).build();
+ assertThrows(IllegalArgumentException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(ifaceToUpdate, request, null /* listener */);
+ });
+ }
+
+ @Test
public void testUpdateConfigurationWithCapabilitiesWithAutomotiveFeature() {
toggleAutomotiveFeature(false);
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_CAPABILITIES,
@@ -247,6 +289,24 @@
}
@Test
+ public void testUpdateConfigurationAddsSpecifierWhenNotSet() {
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_ETHERNET).build();
+ final EthernetNetworkUpdateRequest requestSansSpecifier =
+ new EthernetNetworkUpdateRequest.Builder()
+ .setNetworkCapabilities(nc)
+ .build();
+ final NetworkCapabilities ncWithSpecifier = new NetworkCapabilities(nc)
+ .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE));
+
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, requestSansSpecifier, NULL_LISTENER);
+ verify(mEthernetTracker).updateConfiguration(
+ eq(TEST_IFACE),
+ isNull(),
+ eq(ncWithSpecifier), eq(NULL_LISTENER));
+ }
+
+ @Test
public void testEnableInterface() {
mEthernetServiceImpl.enableInterface(TEST_IFACE, NULL_LISTENER);
verify(mEthernetTracker).enableInterface(eq(TEST_IFACE), eq(NULL_LISTENER));
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 1385d8b..f9cbb10 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -2025,18 +2025,18 @@
}
private NetworkStatsRecorder makeTestRecorder(File directory, String prefix, Config config,
- boolean includeTags) {
+ boolean includeTags, boolean wipeOnError) {
final NetworkStats.NonMonotonicObserver observer =
mock(NetworkStats.NonMonotonicObserver.class);
final DropBoxManager dropBox = mock(DropBoxManager.class);
return new NetworkStatsRecorder(new FileRotator(
directory, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
- observer, dropBox, prefix, config.bucketDuration, includeTags);
+ observer, dropBox, prefix, config.bucketDuration, includeTags, wipeOnError);
}
private NetworkStatsCollection getLegacyCollection(String prefix, boolean includeTags) {
final NetworkStatsRecorder recorder = makeTestRecorder(mLegacyStatsDir, prefix,
- mSettings.getDevConfig(), includeTags);
+ mSettings.getDevConfig(), includeTags, false);
return recorder.getOrLoadCompleteLocked();
}