Merge "Add an idea for how we could reduce the netId size in the future." into main
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index dd60be7..414e50a 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -81,7 +81,10 @@
"framework-tethering.impl",
],
manifest: "AndroidManifestBase.xml",
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
// build tethering static library, used to compile both variants of the tethering.
@@ -215,7 +218,10 @@
use_embedded_native_libs: true,
privapp_allowlist: ":privapp_allowlist_com.android.tethering",
apex_available: ["com.android.tethering"],
- lint: { strict_updatability_linting: true },
+ lint: {
+ strict_updatability_linting: true,
+ error_checks: ["NewApi"],
+ },
}
sdk {
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 79d9a23..c065cd6 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -838,7 +838,7 @@
private void addInterfaceToNetwork(final int netId, @NonNull final String ifaceName) {
try {
- if (null != mRoutingCoordinator.value) {
+ if (SdkLevel.isAtLeastS() && null != mRoutingCoordinator.value) {
// TODO : remove this call in favor of using the LocalNetworkConfiguration
// correctly, which will let ConnectivityService do it automatically.
mRoutingCoordinator.value.addInterfaceToNetwork(netId, ifaceName);
@@ -852,7 +852,7 @@
private void addInterfaceForward(@NonNull final String fromIface,
@NonNull final String toIface) throws ServiceSpecificException, RemoteException {
- if (null != mRoutingCoordinator.value) {
+ if (SdkLevel.isAtLeastS() && null != mRoutingCoordinator.value) {
mRoutingCoordinator.value.addInterfaceForward(fromIface, toIface);
} else {
mNetd.tetherAddForward(fromIface, toIface);
@@ -862,7 +862,7 @@
private void removeInterfaceForward(@NonNull final String fromIface,
@NonNull final String toIface) {
- if (null != mRoutingCoordinator.value) {
+ if (SdkLevel.isAtLeastS() && null != mRoutingCoordinator.value) {
try {
mRoutingCoordinator.value.removeInterfaceForward(fromIface, toIface);
} catch (ServiceSpecificException e) {
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java b/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java
index e7dc757..9ef0f45 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadHalAidlImpl.java
@@ -19,18 +19,21 @@
import static com.android.networkstack.tethering.OffloadHardwareInterface.OFFLOAD_HAL_VERSION_AIDL;
import android.annotation.NonNull;
+import android.annotation.TargetApi;
import android.hardware.tetheroffload.ForwardedStats;
import android.hardware.tetheroffload.IOffload;
import android.hardware.tetheroffload.ITetheringOffloadCallback;
import android.hardware.tetheroffload.NatTimeoutUpdate;
import android.hardware.tetheroffload.NetworkProtocol;
import android.hardware.tetheroffload.OffloadCallbackEvent;
+import android.os.Build;
import android.os.Handler;
import android.os.NativeHandle;
import android.os.ParcelFileDescriptor;
import android.os.ServiceManager;
import android.system.OsConstants;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.SharedLog;
import com.android.networkstack.tethering.OffloadHardwareInterface.OffloadHalCallback;
@@ -40,6 +43,7 @@
/**
* The implementation of IOffloadHal which based on Stable AIDL interface
*/
+@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public class OffloadHalAidlImpl implements IOffloadHal {
private static final String TAG = OffloadHalAidlImpl.class.getSimpleName();
private static final String HAL_INSTANCE_NAME = IOffload.DESCRIPTOR + "/default";
@@ -52,6 +56,7 @@
private TetheringOffloadCallback mTetheringOffloadCallback;
+ @VisibleForTesting
public OffloadHalAidlImpl(int version, @NonNull IOffload offload, @NonNull Handler handler,
@NonNull SharedLog log) {
mOffloadVersion = version;
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java b/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
index e0a9878..71922f9 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
@@ -74,10 +74,7 @@
*/
public boolean initOffload(@NonNull NativeHandle handle1, @NonNull NativeHandle handle2,
@NonNull OffloadHalCallback callback) {
- final String logmsg = String.format("initOffload(%d, %d, %s)",
- handle1.getFileDescriptor().getInt$(), handle2.getFileDescriptor().getInt$(),
- (callback == null) ? "null"
- : "0x" + Integer.toHexString(System.identityHashCode(callback)));
+ final String logmsg = "initOffload()";
mOffloadHalCallback = callback;
mTetheringOffloadCallback = new TetheringOffloadCallback(
diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java
index e23faa4..20c5f30 100644
--- a/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/framework-t/src/android/net/NetworkStatsCollection.java
@@ -31,6 +31,7 @@
import static android.net.NetworkTemplate.MATCH_BLUETOOTH;
import static android.net.NetworkTemplate.MATCH_ETHERNET;
import static android.net.NetworkTemplate.MATCH_MOBILE;
+import static android.net.NetworkTemplate.MATCH_PROXY;
import static android.net.NetworkTemplate.MATCH_WIFI;
import static android.net.TrafficStats.UID_REMOVED;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
@@ -784,6 +785,7 @@
dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_WIFI).build(), "wifi");
dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_ETHERNET).build(), "eth");
dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_BLUETOOTH).build(), "bt");
+ dumpCheckin(pw, start, end, new NetworkTemplate.Builder(MATCH_PROXY).build(), "proxy");
}
/**
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java
index 33bd884..77b166c 100644
--- a/framework-t/src/android/net/NetworkTemplate.java
+++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -1170,7 +1170,7 @@
* @param matchRule the target match rule to be checked.
*/
private static void assertRequestableMatchRule(final int matchRule) {
- if (!isKnownMatchRule(matchRule) || matchRule == MATCH_PROXY) {
+ if (!isKnownMatchRule(matchRule)) {
throw new IllegalArgumentException("Invalid match rule: "
+ getMatchRuleName(matchRule));
}
diff --git a/framework/Android.bp b/framework/Android.bp
index c88bacc..fab37e9 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -301,6 +301,10 @@
],
flags: [
"--show-annotation android.annotation.FlaggedApi",
+ "--show-for-stub-purposes-annotation android.annotation.SystemApi" +
+ "\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)",
+ "--show-for-stub-purposes-annotation android.annotation.SystemApi" +
+ "\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
],
aidl: {
include_dirs: [
diff --git a/framework/src/android/net/BpfNetMapsReader.java b/framework/src/android/net/BpfNetMapsReader.java
index 37c58f0..4ab6d3e 100644
--- a/framework/src/android/net/BpfNetMapsReader.java
+++ b/framework/src/android/net/BpfNetMapsReader.java
@@ -17,6 +17,9 @@
package android.net;
import static android.net.BpfNetMapsConstants.CONFIGURATION_MAP_PATH;
+import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED;
+import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY;
+import static android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_MAP_PATH;
import static android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH;
import static android.net.BpfNetMapsConstants.UID_OWNER_MAP_PATH;
@@ -33,14 +36,15 @@
import android.os.ServiceSpecificException;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.Log;
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.IBpfMap;
-import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.S32;
import com.android.net.module.util.Struct.U32;
+import com.android.net.module.util.Struct.U8;
/**
* A helper class to *read* java BpfMaps.
@@ -48,6 +52,8 @@
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU) // BPF maps were only mainlined in T
public class BpfNetMapsReader {
+ private static final String TAG = BpfNetMapsReader.class.getSimpleName();
+
// Locally store the handle of bpf maps. The FileDescriptors are statically cached inside the
// BpfMap implementation.
@@ -57,6 +63,7 @@
// Bpf map to store per uid traffic control configurations.
// See {@link UidOwnerValue} for more detail.
private final IBpfMap<S32, UidOwnerValue> mUidOwnerMap;
+ private final IBpfMap<S32, U8> mDataSaverEnabledMap;
private final Dependencies mDeps;
// Bitmaps for calculating whether a given uid is blocked by firewall chains.
@@ -104,6 +111,7 @@
mDeps = deps;
mConfigurationMap = mDeps.getConfigurationMap();
mUidOwnerMap = mDeps.getUidOwnerMap();
+ mDataSaverEnabledMap = mDeps.getDataSaverEnabledMap();
}
/**
@@ -130,6 +138,16 @@
throw new IllegalStateException("Cannot open uid owner map", e);
}
}
+
+ /** Get the data saver enabled map. */
+ public IBpfMap<S32, U8> getDataSaverEnabledMap() {
+ try {
+ return new BpfMap<>(DATA_SAVER_ENABLED_MAP_PATH, BpfMap.BPF_F_RDONLY, S32.class,
+ U8.class);
+ } catch (ErrnoException e) {
+ throw new IllegalStateException("Cannot open data saver enabled map", e);
+ }
+ }
}
/**
@@ -171,12 +189,12 @@
* cause of the failure.
*/
public static boolean isChainEnabled(
- final IBpfMap<Struct.S32, Struct.U32> configurationMap, final int chain) {
+ final IBpfMap<S32, U32> configurationMap, final int chain) {
throwIfPreT("isChainEnabled is not available on pre-T devices");
final long match = getMatchByFirewallChain(chain);
try {
- final Struct.U32 config = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
+ final U32 config = configurationMap.getValue(UID_RULES_CONFIGURATION_KEY);
return (config.val & match) != 0;
} catch (ErrnoException e) {
throw new ServiceSpecificException(e.errno,
@@ -195,14 +213,14 @@
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
*/
- public static int getUidRule(final IBpfMap<Struct.S32, UidOwnerValue> uidOwnerMap,
+ public static int getUidRule(final IBpfMap<S32, UidOwnerValue> uidOwnerMap,
final int chain, final int uid) {
throwIfPreT("getUidRule is not available on pre-T devices");
final long match = getMatchByFirewallChain(chain);
final boolean isAllowList = isFirewallAllowList(chain);
try {
- final UidOwnerValue uidMatch = uidOwnerMap.getValue(new Struct.S32(uid));
+ final UidOwnerValue uidMatch = uidOwnerMap.getValue(new S32(uid));
final boolean isMatchEnabled = uidMatch != null && (uidMatch.rule & match) != 0;
return isMatchEnabled == isAllowList ? FIREWALL_RULE_ALLOW : FIREWALL_RULE_DENY;
} catch (ErrnoException e) {
@@ -249,4 +267,29 @@
if ((uidMatch & HAPPY_BOX_MATCH) != 0) return false;
return isDataSaverEnabled;
}
+
+ /**
+ * Get Data Saver enabled or disabled
+ *
+ * @return whether Data Saver is enabled or disabled.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ public boolean getDataSaverEnabled() {
+ throwIfPreT("getDataSaverEnabled is not available on pre-T devices");
+
+ // Note that this is not expected to be called until V given that it relies on the
+ // counterpart platform solution to set data saver status to bpf.
+ // See {@code NetworkManagementService#setDataSaverModeEnabled}.
+ if (!SdkLevel.isAtLeastV()) {
+ Log.wtf(TAG, "getDataSaverEnabled is not expected to be called on pre-V devices");
+ }
+
+ try {
+ return mDataSaverEnabledMap.getValue(DATA_SAVER_ENABLED_KEY).val == DATA_SAVER_ENABLED;
+ } catch (ErrnoException e) {
+ throw new ServiceSpecificException(e.errno, "Unable to get data saver: "
+ + Os.strerror(e.errno));
+ }
+ }
}
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 57ecf49..a934ddb 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -83,6 +83,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import libcore.net.event.NetworkEventDispatcher;
@@ -6371,10 +6372,13 @@
final BpfNetMapsReader reader = BpfNetMapsReader.getInstance();
final boolean isDataSaverEnabled;
- // TODO: For U-QPR3+ devices, get data saver status from bpf configuration map directly.
- final DataSaverStatusTracker dataSaverStatusTracker =
- DataSaverStatusTracker.getInstance(mContext);
- isDataSaverEnabled = dataSaverStatusTracker.getDataSaverEnabled();
+ if (SdkLevel.isAtLeastV()) {
+ isDataSaverEnabled = reader.getDataSaverEnabled();
+ } else {
+ final DataSaverStatusTracker dataSaverStatusTracker =
+ DataSaverStatusTracker.getInstance(mContext);
+ isDataSaverEnabled = dataSaverStatusTracker.getDataSaverEnabled();
+ }
return reader.isUidNetworkingBlocked(uid, isNetworkMetered, isDataSaverEnabled);
}
diff --git a/service/Android.bp b/service/Android.bp
index 82f64ba..76741bc 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -107,10 +107,6 @@
"-Werror",
"-Wno-unused-parameter",
"-Wthread-safety",
-
- // AServiceManager_waitForService is available on only 31+, but it's still safe for Thread
- // service because it's enabled on only 34+
- "-Wno-unguarded-availability",
],
srcs: [
":services.connectivity-netstats-jni-sources",
diff --git a/service/jni/com_android_server_ServiceManagerWrapper.cpp b/service/jni/com_android_server_ServiceManagerWrapper.cpp
index 0cd58f4..0e32726 100644
--- a/service/jni/com_android_server_ServiceManagerWrapper.cpp
+++ b/service/jni/com_android_server_ServiceManagerWrapper.cpp
@@ -25,7 +25,13 @@
static jobject com_android_server_ServiceManagerWrapper_waitForService(
JNIEnv* env, jobject clazz, jstring serviceName) {
ScopedUtfChars name(env, serviceName);
+
+// AServiceManager_waitForService is available on only 31+, but it's still safe for Thread
+// service because it's enabled on only 34+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
return AIBinder_toJavaBinder(env, AServiceManager_waitForService(name.c_str()));
+#pragma clang diagnostic pop
}
/*
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 1837b84..ba9ea86 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -1770,7 +1770,12 @@
mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
null /* broadcastPermission */, mHandler);
- mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNetd, mHandler);
+ // TrackMultiNetworkActivities feature should be enabled by trunk stable flag.
+ // But reading the trunk stable flags from mainline modules is not supported yet.
+ // So enabling this feature on V+ release.
+ mTrackMultiNetworkActivities = mDeps.isAtLeastV();
+ mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNetd, mHandler,
+ mTrackMultiNetworkActivities);
final NetdCallback netdCallback = new NetdCallback();
try {
@@ -3246,9 +3251,20 @@
private void handleReportNetworkActivity(final NetworkActivityParams params) {
mNetworkActivityTracker.handleReportNetworkActivity(params);
+ final boolean isCellNetworkActivity;
+ if (mTrackMultiNetworkActivities) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(params.label);
+ // nai could be null if netd receives a netlink message and calls the network
+ // activity change callback after the network is unregistered from ConnectivityService.
+ isCellNetworkActivity = nai != null
+ && nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
+ } else {
+ isCellNetworkActivity = params.label == TRANSPORT_CELLULAR;
+ }
+
if (mDelayDestroyFrozenSockets
&& params.isActive
- && params.label == TRANSPORT_CELLULAR
+ && isCellNetworkActivity
&& !mPendingFrozenUids.isEmpty()) {
closePendingFrozenSockets();
}
@@ -4965,6 +4981,11 @@
if (wasDefault) {
mDefaultInetConditionPublished = 0;
}
+ if (mTrackMultiNetworkActivities) {
+ // If trackMultiNetworkActivities is disabled, ActivityTracker removes idleTimer when
+ // the network becomes no longer the default network.
+ mNetworkActivityTracker.removeDataActivityTracking(nai);
+ }
notifyIfacesChangedForNetworkStats();
// If this was a local network forwarded to some upstream, or if some local network was
// forwarded to this nai, then disable forwarding rules now.
@@ -5018,12 +5039,7 @@
}
if (mDefaultRequest == nri) {
- // TODO : make battery stats aware that since 2013 multiple interfaces may be
- // active at the same time. For now keep calling this with the default
- // network, because while incorrect this is the closest to the old (also
- // incorrect) behavior.
- mNetworkActivityTracker.updateDataActivityTracking(
- null /* newNetwork */, nai);
+ mNetworkActivityTracker.updateDefaultNetwork(null /* newNetwork */, nai);
maybeClosePendingFrozenSockets(null /* newNetwork */, nai);
ensureNetworkTransitionWakelock(nai.toShortString());
}
@@ -6246,8 +6262,10 @@
if (!networkFound) return;
if (underpinnedNetworkFound) {
+ final NetworkCapabilities underpinnedNc =
+ getNetworkCapabilitiesInternal(underpinnedNetwork);
mKeepaliveTracker.handleMonitorAutomaticKeepalive(ki,
- underpinnedNetwork.netId);
+ underpinnedNetwork.netId, underpinnedNc.getUids());
} else {
// If no underpinned network, then make sure the keepalive is running.
mKeepaliveTracker.handleMaybeResumeKeepalive(ki);
@@ -9644,7 +9662,7 @@
if (oldDefaultNetwork != null) {
mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
}
- mNetworkActivityTracker.updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ mNetworkActivityTracker.updateDefaultNetwork(newDefaultNetwork, oldDefaultNetwork);
maybeClosePendingFrozenSockets(newDefaultNetwork, oldDefaultNetwork);
mProxyTracker.setDefaultProxy(null != newDefaultNetwork
? newDefaultNetwork.linkProperties.getHttpProxy() : null);
@@ -10067,6 +10085,45 @@
// Process default network changes if applicable.
processDefaultNetworkChanges(changes);
+ // Update forwarding rules for the upstreams of local networks. Do this before sending
+ // onAvailable so that by the time onAvailable is sent the forwarding rules are set up.
+ // Don't send CALLBACK_LOCAL_NETWORK_INFO_CHANGED yet though : they should be sent after
+ // onAvailable so clients know what network the change is about. Store such changes in
+ // an array that's only allocated if necessary (because it's almost never necessary).
+ ArrayList<NetworkAgentInfo> localInfoChangedAgents = null;
+ for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
+ if (!nai.isLocalNetwork()) continue;
+ final NetworkRequest nr = nai.localNetworkConfig.getUpstreamSelector();
+ if (null == nr) continue; // No upstream for this local network
+ final NetworkRequestInfo nri = mNetworkRequests.get(nr);
+ final NetworkReassignment.RequestReassignment change = changes.getReassignment(nri);
+ if (null == change) continue; // No change in upstreams for this network
+ final String fromIface = nai.linkProperties.getInterfaceName();
+ if (!hasSameInterfaceName(change.mOldNetwork, change.mNewNetwork)
+ || change.mOldNetwork.isDestroyed()) {
+ // There can be a change with the same interface name if the new network is the
+ // replacement for the old network that was unregisteredAfterReplacement.
+ try {
+ if (null != change.mOldNetwork) {
+ mRoutingCoordinatorService.removeInterfaceForward(fromIface,
+ change.mOldNetwork.linkProperties.getInterfaceName());
+ }
+ // If the new upstream is already destroyed, there is no point in setting up
+ // a forward (in fact, it might forward to the interface for some new network !)
+ // Later when the upstream disconnects CS will try to remove the forward, which
+ // is ignored with a benign log by RoutingCoordinatorService.
+ if (null != change.mNewNetwork && !change.mNewNetwork.isDestroyed()) {
+ mRoutingCoordinatorService.addInterfaceForward(fromIface,
+ change.mNewNetwork.linkProperties.getInterfaceName());
+ }
+ } catch (final RemoteException e) {
+ loge("Can't update forwarding rules", e);
+ }
+ }
+ if (null == localInfoChangedAgents) localInfoChangedAgents = new ArrayList<>();
+ localInfoChangedAgents.add(nai);
+ }
+
// Notify requested networks are available after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (final NetworkReassignment.RequestReassignment event :
@@ -10115,38 +10172,12 @@
notifyNetworkLosing(nai, now);
}
- // Update forwarding rules for the upstreams of local networks. Do this after sending
- // onAvailable so that clients understand what network this is about.
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (!nai.isLocalNetwork()) continue;
- final NetworkRequest nr = nai.localNetworkConfig.getUpstreamSelector();
- if (null == nr) continue; // No upstream for this local network
- final NetworkRequestInfo nri = mNetworkRequests.get(nr);
- final NetworkReassignment.RequestReassignment change = changes.getReassignment(nri);
- if (null == change) continue; // No change in upstreams for this network
- final String fromIface = nai.linkProperties.getInterfaceName();
- if (!hasSameInterfaceName(change.mOldNetwork, change.mNewNetwork)
- || change.mOldNetwork.isDestroyed()) {
- // There can be a change with the same interface name if the new network is the
- // replacement for the old network that was unregisteredAfterReplacement.
- try {
- if (null != change.mOldNetwork) {
- mRoutingCoordinatorService.removeInterfaceForward(fromIface,
- change.mOldNetwork.linkProperties.getInterfaceName());
- }
- // If the new upstream is already destroyed, there is no point in setting up
- // a forward (in fact, it might forward to the interface for some new network !)
- // Later when the upstream disconnects CS will try to remove the forward, which
- // is ignored with a benign log by RoutingCoordinatorService.
- if (null != change.mNewNetwork && !change.mNewNetwork.isDestroyed()) {
- mRoutingCoordinatorService.addInterfaceForward(fromIface,
- change.mNewNetwork.linkProperties.getInterfaceName());
- }
- } catch (final RemoteException e) {
- loge("Can't update forwarding rules", e);
- }
+ // Send LOCAL_NETWORK_INFO_CHANGED callbacks now that onAvailable and onLost have been sent.
+ if (null != localInfoChangedAgents) {
+ for (final NetworkAgentInfo nai : localInfoChangedAgents) {
+ notifyNetworkCallbacks(nai,
+ ConnectivityManager.CALLBACK_LOCAL_NETWORK_INFO_CHANGED);
}
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOCAL_NETWORK_INFO_CHANGED);
}
updateLegacyTypeTrackerAndVpnLockdownForRematch(changes, nais);
@@ -10544,6 +10575,15 @@
SystemClock.elapsedRealtime(), mNascentDelayMs);
networkAgent.setInactive();
+ if (mTrackMultiNetworkActivities) {
+ // Start tracking activity of this network.
+ // This must be called before rematchAllNetworksAndRequests since the network
+ // should be tracked when the network becomes the default network.
+ // This method does not trigger any callbacks or broadcasts. Callbacks or broadcasts
+ // can be triggered later if this network becomes the default network.
+ mNetworkActivityTracker.setupDataActivityTracking(networkAgent);
+ }
+
// Consider network even though it is not yet validated.
rematchAllNetworksAndRequests();
@@ -11735,8 +11775,8 @@
*/
private static final class NetworkActivityParams {
public final boolean isActive;
- // Label used for idle timer. Transport type is used as label.
- // label is int since NMS was using the identifier as int, and it has not been changed
+ // If TrackMultiNetworkActivities is enabled, idleTimer label is netid.
+ // If TrackMultiNetworkActivities is disabled, idleTimer label is transport type.
public final int label;
public final long timestampNs;
// Uid represents the uid that was responsible for waking the radio.
@@ -11778,13 +11818,15 @@
}
}
+ private final boolean mTrackMultiNetworkActivities;
private final LegacyNetworkActivityTracker mNetworkActivityTracker;
/**
* Class used for updating network activity tracking with netd and notify network activity
* changes.
*/
- private static final class LegacyNetworkActivityTracker {
+ @VisibleForTesting
+ public static final class LegacyNetworkActivityTracker {
private static final int NO_UID = -1;
private final Context mContext;
private final INetd mNetd;
@@ -11796,8 +11838,14 @@
// If there is no default network, default network is considered active to keep the existing
// behavior. Initial value is used until first connect to the default network.
private volatile boolean mIsDefaultNetworkActive = true;
+ private Network mDefaultNetwork;
// Key is netId. Value is configured idle timer information.
private final SparseArray<IdleTimerParams> mActiveIdleTimers = new SparseArray<>();
+ private final boolean mTrackMultiNetworkActivities;
+ // Store netIds of Wi-Fi networks whose idletimers report that they are active
+ private final Set<Integer> mActiveWifiNetworks = new ArraySet<>();
+ // Store netIds of cellular networks whose idletimers report that they are active
+ private final Set<Integer> mActiveCellularNetworks = new ArraySet<>();
private static class IdleTimerParams {
public final int timeout;
@@ -11810,10 +11858,11 @@
}
LegacyNetworkActivityTracker(@NonNull Context context, @NonNull INetd netd,
- @NonNull Handler handler) {
+ @NonNull Handler handler, boolean trackMultiNetworkActivities) {
mContext = context;
mNetd = netd;
mHandler = handler;
+ mTrackMultiNetworkActivities = trackMultiNetworkActivities;
}
private void ensureRunningOnConnectivityServiceThread() {
@@ -11823,19 +11872,97 @@
}
}
- public void handleReportNetworkActivity(NetworkActivityParams activityParams) {
- ensureRunningOnConnectivityServiceThread();
+ /**
+ * Update network activity and call BatteryStats to update radio power state if the
+ * mobile or Wi-Fi activity is changed.
+ * LegacyNetworkActivityTracker considers the mobile network is active if at least one
+ * mobile network is active since BatteryStatsService only maintains a single power state
+ * for the mobile network.
+ * The Wi-Fi network is also the same.
+ *
+ * {@link #setupDataActivityTracking} and {@link #removeDataActivityTracking} use
+ * TRANSPORT_CELLULAR as the transportType argument if the network has both cell and Wi-Fi
+ * transports.
+ */
+ private void maybeUpdateRadioPowerState(final int netId, final int transportType,
+ final boolean isActive, final int uid) {
+ if (transportType != TRANSPORT_WIFI && transportType != TRANSPORT_CELLULAR) {
+ Log.e(TAG, "Unexpected transportType in maybeUpdateRadioPowerState: "
+ + transportType);
+ return;
+ }
+ final Set<Integer> activeNetworks = transportType == TRANSPORT_WIFI
+ ? mActiveWifiNetworks : mActiveCellularNetworks;
+
+ final boolean wasEmpty = activeNetworks.isEmpty();
+ if (isActive) {
+ activeNetworks.add(netId);
+ } else {
+ activeNetworks.remove(netId);
+ }
+
+ if (wasEmpty != activeNetworks.isEmpty()) {
+ updateRadioPowerState(isActive, transportType, uid);
+ }
+ }
+
+ private void handleDefaultNetworkActivity(final int transportType,
+ final boolean isActive, final long timestampNs) {
+ mIsDefaultNetworkActive = isActive;
+ sendDataActivityBroadcast(transportTypeToLegacyType(transportType),
+ isActive, timestampNs);
+ if (isActive) {
+ reportNetworkActive();
+ }
+ }
+
+ private void handleReportNetworkActivityWithNetIdLabel(
+ NetworkActivityParams activityParams) {
+ final int netId = activityParams.label;
+ final IdleTimerParams idleTimerParams = mActiveIdleTimers.get(netId);
+ if (idleTimerParams == null) {
+ // This network activity change is not tracked anymore
+ // This can happen if netd callback post activity change event message but idle
+ // timer is removed before processing this message.
+ return;
+ }
+ // TODO: if a network changes transports, storing the transport type in the
+ // IdleTimerParams is not correct. Consider getting it from the network's
+ // NetworkCapabilities instead.
+ final int transportType = idleTimerParams.transportType;
+ maybeUpdateRadioPowerState(netId, transportType,
+ activityParams.isActive, activityParams.uid);
+
+ if (mDefaultNetwork == null || mDefaultNetwork.netId != netId) {
+ // This activity change is not for the default network.
+ return;
+ }
+
+ handleDefaultNetworkActivity(transportType, activityParams.isActive,
+ activityParams.timestampNs);
+ }
+
+ private void handleReportNetworkActivityWithTransportTypeLabel(
+ NetworkActivityParams activityParams) {
if (mActiveIdleTimers.size() == 0) {
// This activity change is not for the current default network.
// This can happen if netd callback post activity change event message but
// the default network is lost before processing this message.
return;
}
- sendDataActivityBroadcast(transportTypeToLegacyType(activityParams.label),
- activityParams.isActive, activityParams.timestampNs);
- mIsDefaultNetworkActive = activityParams.isActive;
- if (mIsDefaultNetworkActive) {
- reportNetworkActive();
+ handleDefaultNetworkActivity(activityParams.label, activityParams.isActive,
+ activityParams.timestampNs);
+ }
+
+ /**
+ * Handle network activity change
+ */
+ public void handleReportNetworkActivity(NetworkActivityParams activityParams) {
+ ensureRunningOnConnectivityServiceThread();
+ if (mTrackMultiNetworkActivities) {
+ handleReportNetworkActivityWithNetIdLabel(activityParams);
+ } else {
+ handleReportNetworkActivityWithTransportTypeLabel(activityParams);
}
}
@@ -11892,6 +12019,30 @@
}
/**
+ * Get idle timer label
+ */
+ @VisibleForTesting
+ public static int getIdleTimerLabel(final boolean trackMultiNetworkActivities,
+ final int netId, final int transportType) {
+ return trackMultiNetworkActivities ? netId : transportType;
+ }
+
+ private boolean maybeCreateIdleTimer(
+ String iface, int netId, int timeout, int transportType) {
+ if (timeout <= 0 || iface == null) return false;
+ try {
+ final String label = Integer.toString(getIdleTimerLabel(
+ mTrackMultiNetworkActivities, netId, transportType));
+ mNetd.idletimerAddInterface(iface, timeout, label);
+ mActiveIdleTimers.put(netId, new IdleTimerParams(timeout, transportType));
+ return true;
+ } catch (Exception e) {
+ loge("Exception in createIdleTimer", e);
+ return false;
+ }
+ }
+
+ /**
* Setup data activity tracking for the given network.
*
* Every {@code setupDataActivityTracking} should be paired with a
@@ -11900,13 +12051,17 @@
* @return true if the idleTimer is added to the network, false otherwise
*/
private boolean setupDataActivityTracking(NetworkAgentInfo networkAgent) {
+ ensureRunningOnConnectivityServiceThread();
final String iface = networkAgent.linkProperties.getInterfaceName();
final int netId = networkAgent.network().netId;
final int timeout;
final int type;
- if (networkAgent.networkCapabilities.hasTransport(
+ if (!networkAgent.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_VPN)) {
+ // Do not track VPN network.
+ return false;
+ } else if (networkAgent.networkCapabilities.hasTransport(
NetworkCapabilities.TRANSPORT_CELLULAR)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE,
@@ -11922,25 +12077,21 @@
return false; // do not track any other networks
}
- updateRadioPowerState(true /* isActive */, type);
-
- if (timeout > 0 && iface != null) {
- try {
- mActiveIdleTimers.put(netId, new IdleTimerParams(timeout, type));
- mNetd.idletimerAddInterface(iface, timeout, Integer.toString(type));
- return true;
- } catch (Exception e) {
- // You shall not crash!
- loge("Exception in setupDataActivityTracking " + e);
- }
+ final boolean hasIdleTimer = maybeCreateIdleTimer(iface, netId, timeout, type);
+ if (hasIdleTimer || !mTrackMultiNetworkActivities) {
+ // If trackMultiNetwork is disabled, NetworkActivityTracker updates radio power
+ // state in all cases. If trackMultiNetwork is enabled, it updates radio power
+ // state only about a network that has an idletimer.
+ maybeUpdateRadioPowerState(netId, type, true /* isActive */, NO_UID);
}
- return false;
+ return hasIdleTimer;
}
/**
* Remove data activity tracking when network disconnects.
*/
- private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+ public void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
+ ensureRunningOnConnectivityServiceThread();
final String iface = networkAgent.linkProperties.getInterfaceName();
final int netId = networkAgent.network().netId;
final NetworkCapabilities caps = networkAgent.networkCapabilities;
@@ -11948,7 +12099,10 @@
if (iface == null) return;
final int type;
- if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ if (!networkAgent.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_VPN)) {
+ // Do not track VPN network.
+ return;
+ } else if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
type = NetworkCapabilities.TRANSPORT_CELLULAR;
} else if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
type = NetworkCapabilities.TRANSPORT_WIFI;
@@ -11957,16 +12111,17 @@
}
try {
- updateRadioPowerState(false /* isActive */, type);
+ maybeUpdateRadioPowerState(netId, type, false /* isActive */, NO_UID);
final IdleTimerParams params = mActiveIdleTimers.get(netId);
if (params == null) {
// IdleTimer is not added if the configured timeout is 0 or negative value
return;
}
mActiveIdleTimers.remove(netId);
- // The call fails silently if no idle timer setup for this interface
- mNetd.idletimerRemoveInterface(iface, params.timeout,
- Integer.toString(params.transportType));
+ final String label = Integer.toString(getIdleTimerLabel(
+ mTrackMultiNetworkActivities, netId, params.transportType));
+ // The call fails silently if no idle timer setup for this interface
+ mNetd.idletimerRemoveInterface(iface, params.timeout, label);
} catch (Exception e) {
// You shall not crash!
loge("Exception in removeDataActivityTracking " + e);
@@ -11976,12 +12131,15 @@
private void updateDefaultNetworkActivity(NetworkAgentInfo defaultNetwork,
boolean hasIdleTimer) {
if (defaultNetwork != null) {
+ mDefaultNetwork = defaultNetwork.network();
mIsDefaultNetworkActive = true;
- // Callbacks are called only when the network has the idle timer.
- if (hasIdleTimer) {
+ // If only the default network is tracked, callbacks are called only when the
+ // network has the idle timer.
+ if (mTrackMultiNetworkActivities || hasIdleTimer) {
reportNetworkActive();
}
} else {
+ mDefaultNetwork = null;
// If there is no default network, default network is considered active to keep the
// existing behavior.
mIsDefaultNetworkActive = true;
@@ -11989,29 +12147,34 @@
}
/**
- * Update data activity tracking when network state is updated.
+ * Update the default network this class tracks the activity of.
*/
- public void updateDataActivityTracking(NetworkAgentInfo newNetwork,
+ public void updateDefaultNetwork(NetworkAgentInfo newNetwork,
NetworkAgentInfo oldNetwork) {
ensureRunningOnConnectivityServiceThread();
+ // If TrackMultiNetworkActivities is enabled, devices add idleTimer when the network is
+ // first connected and remove when the network is disconnected.
+ // If TrackMultiNetworkActivities is disabled, devices add idleTimer when the network
+ // becomes the default network and remove when the network becomes no longer the default
+ // network.
boolean hasIdleTimer = false;
- if (newNetwork != null) {
+ if (!mTrackMultiNetworkActivities && newNetwork != null) {
hasIdleTimer = setupDataActivityTracking(newNetwork);
}
updateDefaultNetworkActivity(newNetwork, hasIdleTimer);
- if (oldNetwork != null) {
+ if (!mTrackMultiNetworkActivities && oldNetwork != null) {
removeDataActivityTracking(oldNetwork);
}
}
- private void updateRadioPowerState(boolean isActive, int transportType) {
+ private void updateRadioPowerState(boolean isActive, int transportType, int uid) {
final BatteryStatsManager bs = mContext.getSystemService(BatteryStatsManager.class);
switch (transportType) {
case NetworkCapabilities.TRANSPORT_CELLULAR:
- bs.reportMobileRadioPowerState(isActive, NO_UID);
+ bs.reportMobileRadioPowerState(isActive, uid);
break;
case NetworkCapabilities.TRANSPORT_WIFI:
- bs.reportWifiRadioPowerState(isActive, NO_UID);
+ bs.reportWifiRadioPowerState(isActive, uid);
break;
default:
logw("Untracked transport type:" + transportType);
@@ -12031,7 +12194,9 @@
}
public void dump(IndentingPrintWriter pw) {
+ pw.print("mTrackMultiNetworkActivities="); pw.println(mTrackMultiNetworkActivities);
pw.print("mIsDefaultNetworkActive="); pw.println(mIsDefaultNetworkActive);
+ pw.print("mDefaultNetwork="); pw.println(mDefaultNetwork);
pw.println("Idle timers:");
try {
for (int i = 0; i < mActiveIdleTimers.size(); i++) {
@@ -12040,11 +12205,13 @@
pw.print(" timeout="); pw.print(params.timeout);
pw.print(" type="); pw.println(params.transportType);
}
+ pw.println("WiFi active networks: " + mActiveWifiNetworks);
+ pw.println("Cellular active networks: " + mActiveCellularNetworks);
} catch (Exception e) {
- // mActiveIdleTimers should only be accessed from handler thread, except dump().
- // As dump() is never called in normal usage, it would be needlessly expensive
- // to lock the collection only for its benefit.
- // Also, mActiveIdleTimers is not expected to be updated frequently.
+ // mActiveIdleTimers, mActiveWifiNetworks, and mActiveCellularNetworks should only
+ // be accessed from handler thread, except dump(). As dump() is never called in
+ // normal usage, it would be needlessly expensive to lock the collection only for
+ // its benefit. Also, they are not expected to be updated frequently.
// So catching the exception and logging.
pw.println("Failed to dump NetworkActivityTracker: " + e);
}
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index bba132f..8036ae9 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -53,6 +53,7 @@
import android.util.LocalLog;
import android.util.Log;
import android.util.Pair;
+import android.util.Range;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -77,6 +78,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Manages automatic on/off socket keepalive requests.
@@ -373,26 +375,27 @@
* Determine if any state transition is needed for the specific automatic keepalive.
*/
public void handleMonitorAutomaticKeepalive(@NonNull final AutomaticOnOffKeepalive ki,
- final int vpnNetId) {
+ final int vpnNetId, @NonNull Set<Range<Integer>> vpnUidRanges) {
// Might happen if the automatic keepalive was removed by the app just as the alarm fires.
if (!mAutomaticOnOffKeepalives.contains(ki)) return;
if (STATE_ALWAYS_ON == ki.mAutomaticOnOffState) {
throw new IllegalStateException("Should not monitor non-auto keepalive");
}
- handleMonitorTcpConnections(ki, vpnNetId);
+ handleMonitorTcpConnections(ki, vpnNetId, vpnUidRanges);
}
/**
* Determine if disable or re-enable keepalive is needed or not based on TCP sockets status.
*/
- private void handleMonitorTcpConnections(@NonNull AutomaticOnOffKeepalive ki, int vpnNetId) {
+ private void handleMonitorTcpConnections(@NonNull AutomaticOnOffKeepalive ki, int vpnNetId,
+ @NonNull Set<Range<Integer>> vpnUidRanges) {
// Might happen if the automatic keepalive was removed by the app just as the alarm fires.
if (!mAutomaticOnOffKeepalives.contains(ki)) return;
if (STATE_ALWAYS_ON == ki.mAutomaticOnOffState) {
throw new IllegalStateException("Should not monitor non-auto keepalive");
}
- if (!isAnyTcpSocketConnected(vpnNetId)) {
+ if (!isAnyTcpSocketConnected(vpnNetId, vpnUidRanges)) {
// No TCP socket exists. Stop keepalive if ENABLED, and remain SUSPENDED if currently
// SUSPENDED.
if (ki.mAutomaticOnOffState == STATE_ENABLED) {
@@ -744,7 +747,7 @@
}
@VisibleForTesting
- boolean isAnyTcpSocketConnected(int netId) {
+ boolean isAnyTcpSocketConnected(int netId, @NonNull Set<Range<Integer>> vpnUidRanges) {
FileDescriptor fd = null;
try {
@@ -757,7 +760,8 @@
// Send request for each IP family
for (final int family : ADDRESS_FAMILIES) {
- if (isAnyTcpSocketConnectedForFamily(fd, family, networkMark, networkMask)) {
+ if (isAnyTcpSocketConnectedForFamily(
+ fd, family, networkMark, networkMask, vpnUidRanges)) {
return true;
}
}
@@ -771,7 +775,8 @@
}
private boolean isAnyTcpSocketConnectedForFamily(FileDescriptor fd, int family, int networkMark,
- int networkMask) throws ErrnoException, InterruptedIOException {
+ int networkMask, @NonNull Set<Range<Integer>> vpnUidRanges)
+ throws ErrnoException, InterruptedIOException {
ensureRunningOnHandlerThread();
// Build SocketDiag messages and cache it.
if (mSockDiagMsg.get(family) == null) {
diff --git a/staticlibs/device/com/android/net/module/util/BpfBitmap.java b/staticlibs/device/com/android/net/module/util/BpfBitmap.java
index d2a5b65..acb3ca5 100644
--- a/staticlibs/device/com/android/net/module/util/BpfBitmap.java
+++ b/staticlibs/device/com/android/net/module/util/BpfBitmap.java
@@ -16,9 +16,11 @@
package com.android.net.module.util;
+import android.os.Build;
import android.system.ErrnoException;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
/**
*
@@ -26,6 +28,7 @@
* array type with key->int and value->uint64_t defined in the bpf program.
*
*/
+@RequiresApi(Build.VERSION_CODES.S)
public class BpfBitmap {
private BpfMap<Struct.S32, Struct.S64> mBpfMap;
diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java
index d622427..e3ef0f0 100644
--- a/staticlibs/device/com/android/net/module/util/BpfMap.java
+++ b/staticlibs/device/com/android/net/module/util/BpfMap.java
@@ -18,12 +18,14 @@
import static android.system.OsConstants.EEXIST;
import static android.system.OsConstants.ENOENT;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -40,6 +42,7 @@
* @param <K> the key of the map.
* @param <V> the value of the map.
*/
+@RequiresApi(Build.VERSION_CODES.S)
public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V> {
static {
System.loadLibrary(JniUtil.getJniLibraryName(BpfMap.class.getPackage()));
diff --git a/staticlibs/device/com/android/net/module/util/BpfUtils.java b/staticlibs/device/com/android/net/module/util/BpfUtils.java
index 10a8f60..cdd6fd7 100644
--- a/staticlibs/device/com/android/net/module/util/BpfUtils.java
+++ b/staticlibs/device/com/android/net/module/util/BpfUtils.java
@@ -15,7 +15,10 @@
*/
package com.android.net.module.util;
+import android.os.Build;
+
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import java.io.IOException;
@@ -24,6 +27,7 @@
*
* {@hide}
*/
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public class BpfUtils {
static {
System.loadLibrary(JniUtil.getJniLibraryName(BpfUtils.class.getPackage()));
diff --git a/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmAddressT.java b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmAddressT.java
new file mode 100644
index 0000000..4c19887
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmAddressT.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 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.net.module.util.netlink;
+
+import android.system.OsConstants;
+
+import androidx.annotation.NonNull;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Struct xfrm_address_t
+ *
+ * <p>see include/uapi/linux/xfrm.h
+ *
+ * <pre>
+ * typedef union {
+ * __be32 a4;
+ * __be32 a6[4];
+ * struct in6_addr in6;
+ * } xfrm_address_t;
+ * </pre>
+ *
+ * @hide
+ */
+public class IpSecStructXfrmAddressT extends Struct {
+ private static final int IPV4_ADDRESS_LEN = 4;
+
+ public static final int STRUCT_SIZE = 16;
+
+ @Field(order = 0, type = Type.ByteArray, arraysize = STRUCT_SIZE)
+ public final byte[] address;
+
+ // Constructor that allows Strutc.parse(Class<T>, ByteBuffer) to work
+ public IpSecStructXfrmAddressT(@NonNull byte[] address) {
+ this.address = address.clone();
+ }
+
+ // Constructor to build a new message
+ public IpSecStructXfrmAddressT(@NonNull InetAddress inetAddress) {
+ this.address = new byte[STRUCT_SIZE];
+ final byte[] addressBytes = inetAddress.getAddress();
+ System.arraycopy(addressBytes, 0, address, 0, addressBytes.length);
+ }
+
+ /** Return the address in InetAddress */
+ public InetAddress getAddress(int family) {
+ final byte[] addressBytes;
+ if (family == OsConstants.AF_INET6) {
+ addressBytes = this.address;
+ } else if (family == OsConstants.AF_INET) {
+ addressBytes = new byte[IPV4_ADDRESS_LEN];
+ System.arraycopy(this.address, 0, addressBytes, 0, addressBytes.length);
+ } else {
+ throw new IllegalArgumentException("Invalid IP family " + family);
+ }
+
+ try {
+ return InetAddress.getByAddress(addressBytes);
+ } catch (UnknownHostException e) {
+ // This should never happen
+ throw new IllegalArgumentException(
+ "Illegal length of IP address " + addressBytes.length, e);
+ }
+ }
+}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmUsersaId.java b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmUsersaId.java
new file mode 100644
index 0000000..6f7b656
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/netlink/IpSecStructXfrmUsersaId.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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.net.module.util.netlink;
+
+import androidx.annotation.NonNull;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+import java.net.InetAddress;
+
+/**
+ * Struct xfrm_usersa_id
+ *
+ * <p>see include/uapi/linux/xfrm.h
+ *
+ * <pre>
+ * struct xfrm_usersa_id {
+ * xfrm_address_t daddr;
+ * __be32 spi;
+ * __u16 family;
+ * __u8 proto;
+ * };
+ * </pre>
+ *
+ * @hide
+ */
+public class IpSecStructXfrmUsersaId extends Struct {
+ public static final int STRUCT_SIZE = 24;
+
+ @Field(order = 0, type = Type.ByteArray, arraysize = 16)
+ public final byte[] nestedStructDAddr; // xfrm_address_t
+
+ @Field(order = 1, type = Type.UBE32)
+ public final long spi;
+
+ @Field(order = 2, type = Type.U16)
+ public final int family;
+
+ @Field(order = 3, type = Type.U8, padding = 1)
+ public final short proto;
+
+ @Computed private final IpSecStructXfrmAddressT mDestXfrmAddressT;
+
+ // Constructor that allows Strutc.parse(Class<T>, ByteBuffer) to work
+ public IpSecStructXfrmUsersaId(
+ @NonNull byte[] nestedStructDAddr, long spi, int family, short proto) {
+ this.nestedStructDAddr = nestedStructDAddr.clone();
+ this.spi = spi;
+ this.family = family;
+ this.proto = proto;
+
+ mDestXfrmAddressT = new IpSecStructXfrmAddressT(this.nestedStructDAddr);
+ }
+
+ // Constructor to build a new message
+ public IpSecStructXfrmUsersaId(
+ @NonNull InetAddress destAddress, long spi, int family, short proto) {
+ this(new IpSecStructXfrmAddressT(destAddress).writeToBytes(), spi, family, proto);
+ }
+
+ /** Return the destination address */
+ public InetAddress getDestAddress() {
+ return mDestXfrmAddressT.getAddress(family);
+ }
+}
diff --git a/staticlibs/device/com/android/net/module/util/netlink/IpSecXfrmNetlinkMessage.java b/staticlibs/device/com/android/net/module/util/netlink/IpSecXfrmNetlinkMessage.java
new file mode 100644
index 0000000..8ad784b
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/netlink/IpSecXfrmNetlinkMessage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 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.net.module.util.netlink;
+
+import androidx.annotation.NonNull;
+
+/** Base calss for XFRM netlink messages */
+// Developer notes: The Linux kernel includes a number of XFRM structs that are not standard netlink
+// attributes (e.g., xfrm_usersa_id). These structs are unlikely to change size, so this XFRM
+// netlink message implementation assumes their sizes will remain stable. If any non-attribute
+// struct size changes, it should be caught by CTS and then developers should add
+// kernel-version-based behvaiours.
+public abstract class IpSecXfrmNetlinkMessage extends NetlinkMessage {
+ // TODO: STOPSHIP: b/308011229 Remove it when OsConstants.IPPROTO_ESP is exposed
+ public static final int IPPROTO_ESP = 50;
+
+ public IpSecXfrmNetlinkMessage(@NonNull StructNlMsgHdr header) {
+ super(header);
+ }
+
+ // TODO: Add the support for parsing messages
+}
diff --git a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
index e4de812..e81fb92 100644
--- a/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
+++ b/staticlibs/native/bpf_headers/BpfRingbufTest.cpp
@@ -74,11 +74,27 @@
ASSERT_RESULT_OK(result);
EXPECT_TRUE(result.value()->isEmpty());
+ struct timespec t1, t2;
+ EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t1));
+ EXPECT_FALSE(result.value()->wait(1000 /*ms*/)); // false because wait should timeout
+ EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t2));
+ long long time1 = t1.tv_sec * 1000000000LL + t1.tv_nsec;
+ long long time2 = t2.tv_sec * 1000000000LL + t2.tv_nsec;
+ EXPECT_GE(time2 - time1, 1000000000 /*ns*/); // 1000 ms as ns
+
for (int i = 0; i < n; i++) {
RunProgram();
}
EXPECT_FALSE(result.value()->isEmpty());
+
+ EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t1));
+ EXPECT_TRUE(result.value()->wait());
+ EXPECT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &t2));
+ time1 = t1.tv_sec * 1000000000LL + t1.tv_nsec;
+ time2 = t2.tv_sec * 1000000000LL + t2.tv_nsec;
+ EXPECT_LE(time2 - time1, 1000000 /*ns*/); // in x86 CF testing < 5000 ns
+
EXPECT_THAT(result.value()->ConsumeAll(callback), HasValue(n));
EXPECT_TRUE(result.value()->isEmpty());
EXPECT_EQ(output, TEST_RINGBUF_MAGIC_NUM);
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
index 9aff790..d716358 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
@@ -19,6 +19,7 @@
#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <linux/bpf.h>
+#include <poll.h>
#include <sys/mman.h>
#include <utils/Log.h>
@@ -41,6 +42,9 @@
bool isEmpty(void);
+ // returns !isEmpty() for convenience
+ bool wait(int timeout_ms = -1);
+
protected:
// Non-initializing constructor, used by Create.
BpfRingbufBase(size_t value_size) : mValueSize(value_size) {}
@@ -200,12 +204,21 @@
}
inline bool BpfRingbufBase::isEmpty(void) {
- uint32_t prod_pos = mProducerPos->load(std::memory_order_acquire);
- // Only userspace writes to mConsumerPos, so no need to use std::memory_order_acquire
+ uint32_t prod_pos = mProducerPos->load(std::memory_order_relaxed);
uint64_t cons_pos = mConsumerPos->load(std::memory_order_relaxed);
return (cons_pos & 0xFFFFFFFF) == prod_pos;
}
+inline bool BpfRingbufBase::wait(int timeout_ms) {
+ // possible optimization: if (!isEmpty()) return true;
+ struct pollfd pfd = { // 1-element array
+ .fd = mRingFd.get(),
+ .events = POLLIN,
+ };
+ (void)poll(&pfd, 1, timeout_ms); // 'best effort' poll
+ return !isEmpty();
+}
+
inline base::Result<int> BpfRingbufBase::ConsumeAll(
const std::function<void(const void*)>& callback) {
int64_t count = 0;
diff --git a/staticlibs/netd/Android.bp b/staticlibs/netd/Android.bp
index 65b3b09..56565ed 100644
--- a/staticlibs/netd/Android.bp
+++ b/staticlibs/netd/Android.bp
@@ -21,7 +21,7 @@
sdk_version: "system_current",
min_sdk_version: "30",
static_libs: [
- "netd_aidl_interface-V13-java",
+ "netd_aidl_interface-V14-java",
],
apex_available: [
"//apex_available:platform", // used from services.net
@@ -44,7 +44,7 @@
cc_library_static {
name: "netd_aidl_interface-lateststable-ndk",
whole_static_libs: [
- "netd_aidl_interface-V13-ndk",
+ "netd_aidl_interface-V14-ndk",
],
apex_available: [
"com.android.resolv",
@@ -55,12 +55,12 @@
cc_defaults {
name: "netd_aidl_interface_lateststable_cpp_static",
- static_libs: ["netd_aidl_interface-V13-cpp"],
+ static_libs: ["netd_aidl_interface-V14-cpp"],
}
cc_defaults {
name: "netd_aidl_interface_lateststable_cpp_shared",
- shared_libs: ["netd_aidl_interface-V13-cpp"],
+ shared_libs: ["netd_aidl_interface-V14-cpp"],
}
aidl_interface {
@@ -162,8 +162,13 @@
version: "13",
imports: [],
},
+ {
+ version: "14",
+ imports: [],
+ },
],
+ frozen: true,
}
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/14/.hash b/staticlibs/netd/aidl_api/netd_aidl_interface/14/.hash
new file mode 100644
index 0000000..0bf7bde
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/.hash
@@ -0,0 +1 @@
+50bce96bc8d5811ed952950df30ec503f8a561ed
diff --git a/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/INetd.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/INetd.aidl
new file mode 100644
index 0000000..8ccefb2
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/INetd.aidl
@@ -0,0 +1,259 @@
+/**
+ * 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);
+ 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/14/android/net/INetdUnsolicitedEventListener.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/INetdUnsolicitedEventListener.aidl
new file mode 100644
index 0000000..31775df
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/InterfaceConfigurationParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/InterfaceConfigurationParcel.aidl
new file mode 100644
index 0000000..1869d8d
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/IpSecMigrateInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/IpSecMigrateInfoParcel.aidl
new file mode 100644
index 0000000..975a261
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/MarkMaskParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/MarkMaskParcel.aidl
new file mode 100644
index 0000000..8ea20d1
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/NativeNetworkConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/NativeNetworkConfig.aidl
new file mode 100644
index 0000000..77d814b
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/NativeNetworkType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/NativeNetworkType.aidl
new file mode 100644
index 0000000..e77a143
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/NativeVpnType.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/NativeVpnType.aidl
new file mode 100644
index 0000000..8a8be83
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/RouteInfoParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/RouteInfoParcel.aidl
new file mode 100644
index 0000000..5ef95e6
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/TetherConfigParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/TetherConfigParcel.aidl
new file mode 100644
index 0000000..7b39c22
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/TetherOffloadRuleParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/TetherOffloadRuleParcel.aidl
new file mode 100644
index 0000000..983e986
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/TetherStatsParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/TetherStatsParcel.aidl
new file mode 100644
index 0000000..5f1b722
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/UidRangeParcel.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/UidRangeParcel.aidl
new file mode 100644
index 0000000..72e987a
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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/14/android/net/netd/aidl/NativeUidRangeConfig.aidl b/staticlibs/netd/aidl_api/netd_aidl_interface/14/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 0000000..9bb679f
--- /dev/null
+++ b/staticlibs/netd/aidl_api/netd_aidl_interface/14/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 3507784..8ccefb2 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
@@ -35,6 +35,9 @@
/* @hide */
interface INetd {
boolean isAlive();
+ /**
+ * @deprecated unimplemented on T+.
+ */
boolean firewallReplaceUidChain(in @utf8InCpp String chainName, boolean isAllowlist, in int[] uids);
boolean bandwidthEnableDataSaver(boolean enable);
/**
@@ -95,9 +98,21 @@
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();
@@ -117,13 +132,22 @@
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);
@@ -136,8 +160,17 @@
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);
@@ -196,7 +229,7 @@
const int NO_PERMISSIONS = 0;
const int PERMISSION_INTERNET = 4;
const int PERMISSION_UPDATE_DEVICE_STATS = 8;
- const int PERMISSION_UNINSTALLED = (-1);
+ const int PERMISSION_UNINSTALLED = (-1) /* -1 */;
/**
* @deprecated use FIREWALL_ALLOWLIST.
*/
diff --git a/staticlibs/netd/binder/android/net/INetd.aidl b/staticlibs/netd/binder/android/net/INetd.aidl
index 27d9a03..ee27e84 100644
--- a/staticlibs/netd/binder/android/net/INetd.aidl
+++ b/staticlibs/netd/binder/android/net/INetd.aidl
@@ -47,6 +47,7 @@
* @param isAllowlist Whether this is an allowlist or denylist chain.
* @param uids The list of UIDs to allow/deny.
* @return true if the chain was successfully replaced, false otherwise.
+ * @deprecated unimplemented on T+.
*/
boolean firewallReplaceUidChain(in @utf8InCpp String chainName,
boolean isAllowlist,
@@ -683,6 +684,7 @@
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void bandwidthAddNaughtyApp(int uid);
@@ -692,6 +694,7 @@
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void bandwidthRemoveNaughtyApp(int uid);
@@ -701,6 +704,7 @@
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void bandwidthAddNiceApp(int uid);
@@ -710,6 +714,7 @@
* @param uid uid of target app
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void bandwidthRemoveNiceApp(int uid);
@@ -983,6 +988,7 @@
* PERMISSION_UPDATE_DEVICE_STATS. If the permission is NO_PERMISSIONS, then
* revoke all permissions for the uids.
* @param uids uid of users to grant permission
+ * @deprecated unimplemented on T+.
*/
void trafficSetNetPermForUids(int permission, in int[] uids);
@@ -1071,6 +1077,7 @@
* @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void firewallSetUidRule(int childChain, int uid, int firewallRule);
@@ -1081,6 +1088,7 @@
* @param enable whether to enable or disable child chain.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void firewallEnableChildChain(int childChain, boolean enable);
@@ -1212,6 +1220,7 @@
* @param uids an array of UIDs which the filtering rules will be set
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void firewallAddUidInterfaceRules(in @utf8InCpp String ifName, in int[] uids);
@@ -1224,6 +1233,7 @@
* @param uids an array of UIDs from which the filtering rules will be removed
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void firewallRemoveUidInterfaceRules(in int[] uids);
@@ -1231,6 +1241,7 @@
* Request netd to change the current active network stats map.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
+ * @deprecated unimplemented on T+.
*/
void trafficSwapActiveStatsMap();
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/IpSecStructXfrmUsersaIdTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/IpSecStructXfrmUsersaIdTest.java
new file mode 100644
index 0000000..4266f68
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/IpSecStructXfrmUsersaIdTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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.net.module.util.netlink;
+
+import static com.android.net.module.util.netlink.IpSecXfrmNetlinkMessage.IPPROTO_ESP;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.system.OsConstants;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.net.module.util.HexDump;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpSecStructXfrmUsersaIdTest {
+ private static final String EXPECTED_HEX_STRING =
+ "C0000201000000000000000000000000" + "7768440002003200";
+ private static final byte[] EXPECTED_HEX = HexDump.hexStringToByteArray(EXPECTED_HEX_STRING);
+
+ private static final InetAddress DEST_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1");
+ private static final long SPI = 0x77684400;
+ private static final int FAMILY = OsConstants.AF_INET;
+ private static final short PROTO = IPPROTO_ESP;
+
+ @Test
+ public void testEncode() throws Exception {
+ final IpSecStructXfrmUsersaId struct =
+ new IpSecStructXfrmUsersaId(DEST_ADDRESS, SPI, FAMILY, PROTO);
+
+ ByteBuffer buffer = ByteBuffer.allocate(EXPECTED_HEX.length);
+ buffer.order(ByteOrder.nativeOrder());
+ struct.writeToByteBuffer(buffer);
+
+ assertArrayEquals(EXPECTED_HEX, buffer.array());
+ }
+
+ @Test
+ public void testDecode() throws Exception {
+ final ByteBuffer buffer = ByteBuffer.wrap(EXPECTED_HEX);
+ buffer.order(ByteOrder.nativeOrder());
+
+ final IpSecStructXfrmUsersaId struct =
+ IpSecStructXfrmUsersaId.parse(IpSecStructXfrmUsersaId.class, buffer);
+
+ assertEquals(DEST_ADDRESS, struct.getDestAddress());
+ assertEquals(SPI, struct.spi);
+ assertEquals(FAMILY, struct.family);
+ assertEquals(PROTO, struct.proto);
+ }
+}
diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt
index d75d9ca..df6067d 100644
--- a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt
+++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt
@@ -61,8 +61,8 @@
commonError)
}
assertTrue(tm.isDataConnectivityPossible,
- "The device is not setup with a SIM card that supports data connectivity. " +
- commonError)
+ "The device has a SIM card, but it does not supports data connectivity. " +
+ "Check the data plan, and verify that mobile data is working. " + commonError)
connectUtil.ensureCellularValidated()
}
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt
index 1ba83ca..10accd4 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/DevSdkIgnoreRunner.kt
@@ -17,9 +17,9 @@
package com.android.testutils
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import java.lang.IllegalStateException
import java.lang.reflect.Modifier
import org.junit.runner.Description
import org.junit.runner.Runner
@@ -110,10 +110,19 @@
notifier.fireTestStarted(leakMonitorDesc)
val threadCountsAfterTest = getAllThreadNameCounts()
- if (threadCountsBeforeTest != threadCountsAfterTest) {
+ // TODO : move CompareOrUpdateResult to its own util instead of LinkProperties.
+ val threadsDiff = CompareOrUpdateResult(
+ threadCountsBeforeTest.entries,
+ threadCountsAfterTest.entries
+ ) { it.key }
+ // Ignore removed threads, which typically are generated by previous tests.
+ // Because this is in the threadsDiff.updated member, for sure there is a
+ // corresponding key in threadCountsBeforeTest.
+ val increasedThreads = threadsDiff.updated
+ .filter { threadCountsBeforeTest[it.key]!! < it.value }
+ if (threadsDiff.added.isNotEmpty() || increasedThreads.isNotEmpty()) {
notifier.fireTestFailure(Failure(leakMonitorDesc,
- IllegalStateException("Expected threads: $threadCountsBeforeTest " +
- "but got: $threadCountsAfterTest")))
+ IllegalStateException("Unexpected thread changes: $threadsDiff")))
}
notifier.fireTestFinished(leakMonitorDesc)
}
@@ -121,9 +130,13 @@
private fun getAllThreadNameCounts(): Map<String, Int> {
// Get the counts of threads in the group per name.
// Filter system thread groups.
+ // Also ignore threads with 1 count, this effectively filtered out threads created by the
+ // test runner or other system components. e.g. hwuiTask*, queued-work-looper,
+ // SurfaceSyncGroupTimer, RenderThread, Time-limited test, etc.
return Thread.getAllStackTraces().keys
.filter { it.threadGroup?.name != "system" }
.groupingBy { it.name }.eachCount()
+ .filter { it.value != 1 }
}
override fun getDescription(): Description {
diff --git a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
index fd7bd74..1b55be9 100644
--- a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
+++ b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
@@ -62,11 +62,6 @@
}
}
- // Verify hidden match rules cannot construct templates.
- assertFailsWith<IllegalArgumentException> {
- NetworkTemplate.Builder(MATCH_PROXY).build()
- }
-
// Verify template which matches metered cellular and carrier networks with
// the given IMSI. See buildTemplateMobileAll and buildTemplateCarrierMetered.
listOf(MATCH_MOBILE, MATCH_CARRIER).forEach { matchRule ->
@@ -170,9 +165,9 @@
assertEquals(expectedTemplate, it)
}
- // Verify template which matches ethernet and bluetooth networks.
+ // Verify template which matches ethernet, bluetooth and proxy networks.
// See buildTemplateEthernet and buildTemplateBluetooth.
- listOf(MATCH_ETHERNET, MATCH_BLUETOOTH).forEach { matchRule ->
+ listOf(MATCH_ETHERNET, MATCH_BLUETOOTH, MATCH_PROXY).forEach { matchRule ->
NetworkTemplate.Builder(matchRule).build().let {
val expectedTemplate = NetworkTemplate(matchRule,
emptyArray<String>() /*subscriberIds*/, emptyArray<String>(),
diff --git a/tests/unit/java/android/net/BpfNetMapsReaderTest.kt b/tests/unit/java/android/net/BpfNetMapsReaderTest.kt
index 258e422..9de7f4d 100644
--- a/tests/unit/java/android/net/BpfNetMapsReaderTest.kt
+++ b/tests/unit/java/android/net/BpfNetMapsReaderTest.kt
@@ -16,6 +16,9 @@
package android.net
+import android.net.BpfNetMapsConstants.DATA_SAVER_DISABLED
+import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED
+import android.net.BpfNetMapsConstants.DATA_SAVER_ENABLED_KEY
import android.net.BpfNetMapsConstants.DOZABLE_MATCH
import android.net.BpfNetMapsConstants.HAPPY_BOX_MATCH
import android.net.BpfNetMapsConstants.PENALTY_BOX_MATCH
@@ -26,6 +29,8 @@
import com.android.net.module.util.IBpfMap
import com.android.net.module.util.Struct.S32
import com.android.net.module.util.Struct.U32
+import com.android.net.module.util.Struct.U8
+import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.TestBpfMap
@@ -33,6 +38,7 @@
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,17 +51,24 @@
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(VERSION_CODES.S_V2)
class BpfNetMapsReaderTest {
+ @Rule
+ @JvmField
+ val ignoreRule = DevSdkIgnoreRule()
+
private val testConfigurationMap: IBpfMap<S32, U32> = TestBpfMap()
private val testUidOwnerMap: IBpfMap<S32, UidOwnerValue> = TestBpfMap()
+ private val testDataSaverEnabledMap: IBpfMap<S32, U8> = TestBpfMap()
private val bpfNetMapsReader = BpfNetMapsReader(
- TestDependencies(testConfigurationMap, testUidOwnerMap))
+ TestDependencies(testConfigurationMap, testUidOwnerMap, testDataSaverEnabledMap))
class TestDependencies(
private val configMap: IBpfMap<S32, U32>,
- private val uidOwnerMap: IBpfMap<S32, UidOwnerValue>
+ private val uidOwnerMap: IBpfMap<S32, UidOwnerValue>,
+ private val dataSaverEnabledMap: IBpfMap<S32, U8>
) : BpfNetMapsReader.Dependencies() {
override fun getConfigurationMap() = configMap
override fun getUidOwnerMap() = uidOwnerMap
+ override fun getDataSaverEnabledMap() = dataSaverEnabledMap
}
private fun doTestIsChainEnabled(chain: Int) {
@@ -199,4 +212,13 @@
assertFalse(isUidNetworkingBlocked(TEST_UID2))
assertFalse(isUidNetworkingBlocked(TEST_UID3))
}
+
+ @IgnoreUpTo(VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Test
+ fun testGetDataSaverEnabled() {
+ testDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, U8(DATA_SAVER_DISABLED))
+ assertFalse(bpfNetMapsReader.dataSaverEnabled)
+ testDataSaverEnabledMap.updateEntry(DATA_SAVER_ENABLED_KEY, U8(DATA_SAVER_ENABLED))
+ assertTrue(bpfNetMapsReader.dataSaverEnabled)
+ }
}
diff --git a/tests/unit/java/android/net/ConnectivityManagerTest.java b/tests/unit/java/android/net/ConnectivityManagerTest.java
index b8c5447..0082af2 100644
--- a/tests/unit/java/android/net/ConnectivityManagerTest.java
+++ b/tests/unit/java/android/net/ConnectivityManagerTest.java
@@ -90,6 +90,7 @@
import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -102,6 +103,8 @@
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R)
public class ConnectivityManagerTest {
+ @Rule
+ public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
private static final int TIMEOUT_MS = 30_000;
private static final int SHORT_TIMEOUT_MS = 150;
@@ -524,6 +527,7 @@
+ " attempts", ref.get());
}
+ @DevSdkIgnoreRule.IgnoreAfter(VERSION_CODES.UPSIDE_DOWN_CAKE)
@Test
public void testDataSaverStatusTracker() {
mockService(NetworkPolicyManager.class, Context.NETWORK_POLICY_SERVICE, mNpm);
diff --git a/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
index b2dff2e..acae7d2 100644
--- a/tests/unit/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/unit/java/com/android/internal/net/VpnProfileTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -311,4 +312,12 @@
decoded.password = profile.password;
assertEquals(profile, decoded);
}
+
+ @Test
+ public void testClone() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+ final VpnProfile clone = profile.clone();
+ assertEquals(profile, clone);
+ assertNotSame(profile, clone);
+ }
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 97e134a..fff9a30 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -155,6 +155,8 @@
import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
+import static android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+import static android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
import static com.android.server.ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION;
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
@@ -640,8 +642,8 @@
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
- final BatteryStatsManager mBatteryStatsManager =
- new BatteryStatsManager(mock(IBatteryStats.class));
+ final IBatteryStats mIBatteryStats = mock(IBatteryStats.class);
+ final BatteryStatsManager mBatteryStatsManager = new BatteryStatsManager(mIBatteryStats);
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -1657,8 +1659,7 @@
waitForIdle();
}
- public void startLegacyVpnPrivileged(VpnProfile profile,
- @Nullable Network underlying, @NonNull LinkProperties egress) {
+ public void startLegacyVpnPrivileged(VpnProfile profile) {
switch (profile.type) {
case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
@@ -10250,7 +10251,7 @@
b.expectBroadcast();
// Simulate LockdownVpnTracker attempting to start the VPN since it received the
// systemDefault callback.
- mMockVpn.startLegacyVpnPrivileged(profile, mCellAgent.getNetwork(), cellLp);
+ mMockVpn.startLegacyVpnPrivileged(profile);
if (expectSetVpnDefaultForUids) {
// setVpnDefaultForUids() releases the original network request and creates a VPN
// request so LOST callback is received.
@@ -10321,7 +10322,7 @@
// callback with different network.
final ExpectedBroadcast b6 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
mMockVpn.stopVpnRunnerPrivileged();
- mMockVpn.startLegacyVpnPrivileged(profile, mWiFiAgent.getNetwork(), wifiLp);
+ mMockVpn.startLegacyVpnPrivileged(profile);
// VPN network is disconnected (to restart)
callback.expect(LOST, mMockVpn);
defaultCallback.expect(LOST, mMockVpn);
@@ -10807,6 +10808,11 @@
expectNativeNetworkCreated(netId, permission, iface, null /* inOrder */);
}
+ private int getIdleTimerLabel(int netId, int transportType) {
+ return ConnectivityService.LegacyNetworkActivityTracker.getIdleTimerLabel(
+ mDeps.isAtLeastV(), netId, transportType);
+ }
+
@Test
public void testStackedLinkProperties() throws Exception {
final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
@@ -11048,7 +11054,7 @@
networkCallback.expect(LOST, mCellAgent);
networkCallback.assertNoCallback();
verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ eq(Integer.toString(getIdleTimerLabel(cellNetId, TRANSPORT_CELLULAR))));
verify(mMockNetd).networkDestroy(cellNetId);
if (mDeps.isAtLeastU()) {
verify(mMockNetd).setNetworkAllowlist(any());
@@ -11107,7 +11113,7 @@
}
verify(mMockNetd).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ eq(Integer.toString(getIdleTimerLabel(cellNetId, TRANSPORT_CELLULAR))));
verify(mMockNetd).networkDestroy(cellNetId);
if (mDeps.isAtLeastU()) {
verify(mMockNetd).setNetworkAllowlist(any());
@@ -11362,8 +11368,21 @@
final ConditionVariable onNetworkActiveCv = new ConditionVariable();
final ConnectivityManager.OnNetworkActiveListener listener = onNetworkActiveCv::open;
+ TestNetworkCallback defaultCallback = new TestNetworkCallback();
+
testAndCleanup(() -> {
+ mCm.registerDefaultNetworkCallback(defaultCallback);
agent.connect(true);
+ defaultCallback.expectAvailableThenValidatedCallbacks(agent);
+ if (transportType == TRANSPORT_CELLULAR) {
+ verify(mIBatteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_HIGH),
+ anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID));
+ } else if (transportType == TRANSPORT_WIFI) {
+ verify(mIBatteryStats).noteWifiRadioPowerState(eq(DC_POWER_STATE_HIGH),
+ anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID));
+ }
+ clearInvocations(mIBatteryStats);
+ final int idleTimerLabel = getIdleTimerLabel(agent.getNetwork().netId, transportType);
// Network is considered active when the network becomes the default network.
assertTrue(mCm.isDefaultNetworkActive());
@@ -11372,19 +11391,57 @@
// Interface goes to inactive state
netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
- transportType, TIMESTAMP, NETWORK_ACTIVITY_NO_UID);
+ idleTimerLabel, TIMESTAMP, NETWORK_ACTIVITY_NO_UID);
mServiceContext.expectDataActivityBroadcast(legacyType, false /* isActive */,
TIMESTAMP);
assertFalse(onNetworkActiveCv.block(TEST_CALLBACK_TIMEOUT_MS));
assertFalse(mCm.isDefaultNetworkActive());
+ if (mDeps.isAtLeastV()) {
+ if (transportType == TRANSPORT_CELLULAR) {
+ verify(mIBatteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_LOW),
+ anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID));
+ } else if (transportType == TRANSPORT_WIFI) {
+ verify(mIBatteryStats).noteWifiRadioPowerState(eq(DC_POWER_STATE_LOW),
+ anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID));
+ }
+ } else {
+ // If TrackMultiNetworks is disabled, LegacyNetworkActivityTracker does not call
+ // BatteryStats API by the netd activity change callback since BatteryStatsService
+ // listen to netd callback via NetworkManagementService and update battery stats by
+ // itself.
+ verify(mIBatteryStats, never())
+ .noteMobileRadioPowerState(anyInt(), anyLong(), anyInt());
+ verify(mIBatteryStats, never())
+ .noteWifiRadioPowerState(anyInt(), anyLong(), anyInt());
+ }
// Interface goes to active state
netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
- transportType, TIMESTAMP, TEST_PACKAGE_UID);
+ idleTimerLabel, TIMESTAMP, TEST_PACKAGE_UID);
mServiceContext.expectDataActivityBroadcast(legacyType, true /* isActive */, TIMESTAMP);
assertTrue(onNetworkActiveCv.block(TEST_CALLBACK_TIMEOUT_MS));
assertTrue(mCm.isDefaultNetworkActive());
+ if (mDeps.isAtLeastV()) {
+ if (transportType == TRANSPORT_CELLULAR) {
+ verify(mIBatteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_HIGH),
+ anyLong() /* timestampNs */, eq(TEST_PACKAGE_UID));
+ } else if (transportType == TRANSPORT_WIFI) {
+ verify(mIBatteryStats).noteWifiRadioPowerState(eq(DC_POWER_STATE_HIGH),
+ anyLong() /* timestampNs */, eq(TEST_PACKAGE_UID));
+ }
+ } else {
+ // If TrackMultiNetworks is disabled, LegacyNetworkActivityTracker does not call
+ // BatteryStats API by the netd activity change callback since BatteryStatsService
+ // listen to netd callback via NetworkManagementService and update battery stats by
+ // itself.
+ verify(mIBatteryStats, never())
+ .noteMobileRadioPowerState(anyInt(), anyLong(), anyInt());
+ verify(mIBatteryStats, never())
+ .noteWifiRadioPowerState(anyInt(), anyLong(), anyInt());
+ }
}, () -> { // Cleanup
+ mCm.unregisterNetworkCallback(defaultCallback);
+ }, () -> { // Cleanup
mCm.removeDefaultNetworkActiveListener(listener);
}, () -> { // Cleanup
agent.disconnect();
@@ -11432,12 +11489,13 @@
}
@Test
- public void testOnNetworkActive_NewEthernetConnects_CallbackNotCalled() throws Exception {
- // LegacyNetworkActivityTracker calls onNetworkActive callback only for networks that
- // tracker adds the idle timer to. And the tracker does not set the idle timer for the
- // ethernet network.
+ public void testOnNetworkActive_NewEthernetConnects_Callback() throws Exception {
+ // On pre-V devices, LegacyNetworkActivityTracker calls onNetworkActive callback only for
+ // networks that tracker adds the idle timer to. And the tracker does not set the idle timer
+ // for the ethernet network.
// So onNetworkActive is not called when the ethernet becomes the default network
- doTestOnNetworkActive_NewNetworkConnects(TRANSPORT_ETHERNET, false /* expectCallback */);
+ final boolean expectCallback = mDeps.isAtLeastV();
+ doTestOnNetworkActive_NewNetworkConnects(TRANSPORT_ETHERNET, expectCallback);
}
@Test
@@ -11467,15 +11525,19 @@
mCm.registerNetworkCallback(networkRequest, networkCallback);
mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ final String cellIdleTimerLabel = Integer.toString(getIdleTimerLabel(
+ mCellAgent.getNetwork().netId, TRANSPORT_CELLULAR));
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
mCellAgent.sendLinkProperties(cellLp);
mCellAgent.connect(true);
networkCallback.expectAvailableThenValidatedCallbacks(mCellAgent);
verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ eq(cellIdleTimerLabel));
mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ String wifiIdleTimerLabel = Integer.toString(getIdleTimerLabel(
+ mWiFiAgent.getNetwork().netId, TRANSPORT_WIFI));
final LinkProperties wifiLp = new LinkProperties();
wifiLp.setInterfaceName(WIFI_IFNAME);
mWiFiAgent.sendLinkProperties(wifiLp);
@@ -11486,9 +11548,18 @@
networkCallback.expectLosing(mCellAgent);
networkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ eq(wifiIdleTimerLabel));
+ if (mDeps.isAtLeastV()) {
+ // V+ devices add idleTimer when the network is first connected and remove when the
+ // network is disconnected.
+ verify(mMockNetd, never()).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(mCellAgent.getNetwork().netId)));
+ } else {
+ // pre V devices add idleTimer when the network becomes the default network and remove
+ // when the network becomes no longer the default network.
+ verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(TRANSPORT_CELLULAR)));
+ }
// Disconnect wifi and switch back to cell
reset(mMockNetd);
@@ -11496,13 +11567,20 @@
networkCallback.expect(LOST, mWiFiAgent);
assertNoCallbacks(networkCallback);
verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ eq(wifiIdleTimerLabel));
+ if (mDeps.isAtLeastV()) {
+ verify(mMockNetd, never()).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(mCellAgent.getNetwork().netId)));
+ } else {
+ verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(TRANSPORT_CELLULAR)));
+ }
// reconnect wifi
reset(mMockNetd);
mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ wifiIdleTimerLabel = Integer.toString(getIdleTimerLabel(
+ mWiFiAgent.getNetwork().netId, TRANSPORT_WIFI));
wifiLp.setInterfaceName(WIFI_IFNAME);
mWiFiAgent.sendLinkProperties(wifiLp);
mWiFiAgent.connect(true);
@@ -11510,20 +11588,30 @@
networkCallback.expectLosing(mCellAgent);
networkCallback.expectCaps(mWiFiAgent, c -> c.hasCapability(NET_CAPABILITY_VALIDATED));
verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ eq(wifiIdleTimerLabel));
+ if (mDeps.isAtLeastV()) {
+ verify(mMockNetd, never()).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(mCellAgent.getNetwork().netId)));
+ } else {
+ verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(TRANSPORT_CELLULAR)));
+ }
// Disconnect cell
reset(mMockNetd);
mCellAgent.disconnect();
networkCallback.expect(LOST, mCellAgent);
- // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
- // sent as network being switched. Ensure rule removal for cell will not be triggered
- // unexpectedly before network being removed.
waitForIdle();
- verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
+ if (mDeps.isAtLeastV()) {
+ verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(mCellAgent.getNetwork().netId)));
+ } else {
+ // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
+ // sent as network being switched. Ensure rule removal for cell will not be triggered
+ // unexpectedly before network being removed.
+ verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
+ eq(Integer.toString(TRANSPORT_CELLULAR)));
+ }
verify(mMockNetd, times(1)).networkDestroy(eq(mCellAgent.getNetwork().netId));
verify(mMockDnsResolver, times(1)).destroyNetworkCache(eq(mCellAgent.getNetwork().netId));
@@ -11532,12 +11620,27 @@
mWiFiAgent.disconnect();
b.expectBroadcast();
verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
+ eq(wifiIdleTimerLabel));
// Clean up
mCm.unregisterNetworkCallback(networkCallback);
}
+ @Test
+ public void testDataActivityTracking_VpnNetwork() throws Exception {
+ mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiAgent.connect(true /* validated */);
+ mMockVpn.setUnderlyingNetworks(new Network[] { mWiFiAgent.getNetwork() });
+
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(VPN_IFNAME);
+ mMockVpn.establishForMyUid(lp);
+
+ // NetworkActivityTracker should not track the VPN network since VPN can change the
+ // underlying network without disconnect.
+ verify(mMockNetd, never()).idletimerAddInterface(eq(VPN_IFNAME), anyInt(), any());
+ }
+
private void verifyTcpBufferSizeChange(String tcpBufferSizes) throws Exception {
String[] values = tcpBufferSizes.split(",");
String rmemValues = String.join(" ", values[0], values[1], values[2]);
@@ -18728,6 +18831,7 @@
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(transportToTestIfaceName(transportType));
final TestNetworkAgentWrapper agent = new TestNetworkAgentWrapper(transportType, lp);
+ final int idleTimerLabel = getIdleTimerLabel(agent.getNetwork().netId, transportType);
testAndCleanup(() -> {
final UidFrozenStateChangedCallback uidFrozenStateChangedCallback =
getUidFrozenStateChangedCallback().get();
@@ -18740,7 +18844,7 @@
if (freezeWithNetworkInactive) {
// Make network inactive
netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
- transportType, TIMESTAMP, NETWORK_ACTIVITY_NO_UID);
+ idleTimerLabel, TIMESTAMP, NETWORK_ACTIVITY_NO_UID);
}
// Freeze TEST_FROZEN_UID and TEST_UNFROZEN_UID
@@ -18764,7 +18868,7 @@
// Make network active
netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
- transportType, TIMESTAMP, TEST_PACKAGE_UID);
+ idleTimerLabel, TIMESTAMP, TEST_PACKAGE_UID);
waitForIdle();
if (expectDelay) {
@@ -18783,8 +18887,8 @@
@Test
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
public void testDelayFrozenUidSocketDestroy_ActiveCellular() throws Exception {
- doTestDelayFrozenUidSocketDestroy(TRANSPORT_CELLULAR,
- false /* freezeWithNetworkInactive */, false /* expectDelay */);
+ doTestDelayFrozenUidSocketDestroy(TRANSPORT_CELLULAR, false /* freezeWithNetworkInactive */,
+ false /* expectDelay */);
}
@Test
@@ -18792,22 +18896,22 @@
public void testDelayFrozenUidSocketDestroy_InactiveCellular() throws Exception {
// When the default network is cellular and cellular network is inactive, closing socket
// is delayed.
- doTestDelayFrozenUidSocketDestroy(TRANSPORT_CELLULAR,
- true /* freezeWithNetworkInactive */, true /* expectDelay */);
+ doTestDelayFrozenUidSocketDestroy(TRANSPORT_CELLULAR, true /* freezeWithNetworkInactive */,
+ true /* expectDelay */);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
public void testDelayFrozenUidSocketDestroy_ActiveWifi() throws Exception {
- doTestDelayFrozenUidSocketDestroy(TRANSPORT_WIFI,
- false /* freezeWithNetworkInactive */, false /* expectDelay */);
+ doTestDelayFrozenUidSocketDestroy(TRANSPORT_WIFI, false /* freezeWithNetworkInactive */,
+ false /* expectDelay */);
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
public void testDelayFrozenUidSocketDestroy_InactiveWifi() throws Exception {
- doTestDelayFrozenUidSocketDestroy(TRANSPORT_WIFI,
- true /* freezeWithNetworkInactive */, false /* expectDelay */);
+ doTestDelayFrozenUidSocketDestroy(TRANSPORT_WIFI, true /* freezeWithNetworkInactive */,
+ false /* expectDelay */);
}
/**
@@ -18828,6 +18932,8 @@
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
mCellAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ final int idleTimerLabel =
+ getIdleTimerLabel(mCellAgent.getNetwork().netId, TRANSPORT_CELLULAR);
final TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
@@ -18837,7 +18943,7 @@
// Make cell network inactive
netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
- TRANSPORT_CELLULAR, TIMESTAMP, NETWORK_ACTIVITY_NO_UID);
+ idleTimerLabel, TIMESTAMP, NETWORK_ACTIVITY_NO_UID);
// Freeze TEST_FROZEN_UID
final int[] uids = {TEST_FROZEN_UID};
diff --git a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
index 8e19c01..10a0982 100644
--- a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
@@ -72,7 +72,9 @@
import android.os.SystemClock;
import android.telephony.SubscriptionManager;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
import android.util.Log;
+import android.util.Range;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -102,7 +104,9 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Set;
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
@@ -232,6 +236,9 @@
private static final byte[] TEST_RESPONSE_BYTES =
HexEncoding.decode(TEST_RESPONSE_HEX.toCharArray(), false);
+ private static final Set<Range<Integer>> TEST_UID_RANGES =
+ new ArraySet<>(Arrays.asList(new Range<>(10000, 99999)));
+
private static class TestKeepaliveInfo {
private static List<Socket> sOpenSockets = new ArrayList<>();
@@ -409,28 +416,28 @@
public void testIsAnyTcpSocketConnected_runOnNonHandlerThread() throws Exception {
setupResponseWithSocketExisting();
assertThrows(IllegalStateException.class,
- () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID));
+ () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID, TEST_UID_RANGES));
}
@Test
public void testIsAnyTcpSocketConnected_withTargetNetId() throws Exception {
setupResponseWithSocketExisting();
assertTrue(visibleOnHandlerThread(mTestHandler,
- () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)));
+ () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID, TEST_UID_RANGES)));
}
@Test
public void testIsAnyTcpSocketConnected_withIncorrectNetId() throws Exception {
setupResponseWithSocketExisting();
assertFalse(visibleOnHandlerThread(mTestHandler,
- () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(OTHER_NETID)));
+ () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(OTHER_NETID, TEST_UID_RANGES)));
}
@Test
public void testIsAnyTcpSocketConnected_noSocketExists() throws Exception {
setupResponseWithoutSocketExisting();
assertFalse(visibleOnHandlerThread(mTestHandler,
- () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID)));
+ () -> mAOOKeepaliveTracker.isAnyTcpSocketConnected(TEST_NETID, TEST_UID_RANGES)));
}
private void triggerEventKeepalive(int slot, int reason) {
@@ -474,14 +481,16 @@
setupResponseWithoutSocketExisting();
visibleOnHandlerThread(
mTestHandler,
- () -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(autoKi, TEST_NETID));
+ () -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(
+ autoKi, TEST_NETID, TEST_UID_RANGES));
}
private void doResumeKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
setupResponseWithSocketExisting();
visibleOnHandlerThread(
mTestHandler,
- () -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(autoKi, TEST_NETID));
+ () -> mAOOKeepaliveTracker.handleMonitorAutomaticKeepalive(
+ autoKi, TEST_NETID, TEST_UID_RANGES));
}
private void doStopKeepalive(AutomaticOnOffKeepalive autoKi) throws Exception {
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index ff801e5..ea2228e 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -74,7 +74,9 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.longThat;
import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
@@ -188,6 +190,7 @@
import org.mockito.AdditionalAnswers;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -204,6 +207,7 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -314,6 +318,8 @@
@Mock DeviceIdleInternal mDeviceIdleInternal;
private final VpnProfile mVpnProfile;
+ @Captor private ArgumentCaptor<Collection<Range<Integer>>> mUidRangesCaptor;
+
private IpSecManager mIpSecManager;
private TestDeps mTestDeps;
@@ -1093,37 +1099,53 @@
}
}
- private Vpn prepareVpnForVerifyAppExclusionList() throws Exception {
- final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ private String startVpnForVerifyAppExclusionList(Vpn vpn) throws Exception {
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
when(mVpnProfileStore.get(PRIMARY_USER_APP_EXCLUDE_KEY))
.thenReturn(HexDump.hexStringToByteArray(PKGS_BYTES));
-
- vpn.startVpnProfile(TEST_VPN_PKG);
+ final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
+ final Set<Range<Integer>> uidRanges = vpn.createUserAndRestrictedProfilesRanges(
+ PRIMARY_USER.id, null /* allowedApplications */, Arrays.asList(PKGS));
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+ clearInvocations(mConnectivityManager);
verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
vpn.mNetworkAgent = mMockNetworkAgent;
+
+ return sessionKey;
+ }
+
+ private Vpn prepareVpnForVerifyAppExclusionList() throws Exception {
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ startVpnForVerifyAppExclusionList(vpn);
+
return vpn;
}
@Test
public void testSetAndGetAppExclusionList() throws Exception {
- final Vpn vpn = prepareVpnForVerifyAppExclusionList();
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final String sessionKey = startVpnForVerifyAppExclusionList(vpn);
verify(mVpnProfileStore, never()).put(eq(PRIMARY_USER_APP_EXCLUDE_KEY), any());
vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
verify(mVpnProfileStore)
.put(eq(PRIMARY_USER_APP_EXCLUDE_KEY),
eq(HexDump.hexStringToByteArray(PKGS_BYTES)));
- assertEquals(vpn.createUserAndRestrictedProfilesRanges(
- PRIMARY_USER.id, null, Arrays.asList(PKGS)),
- vpn.mNetworkCapabilities.getUids());
+ final Set<Range<Integer>> uidRanges = vpn.createUserAndRestrictedProfilesRanges(
+ PRIMARY_USER.id, null /* allowedApplications */, Arrays.asList(PKGS));
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
+ assertEquals(uidRanges, vpn.mNetworkCapabilities.getUids());
assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
}
@Test
public void testRefreshPlatformVpnAppExclusionList_updatesExcludedUids() throws Exception {
- final Vpn vpn = prepareVpnForVerifyAppExclusionList();
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final String sessionKey = startVpnForVerifyAppExclusionList(vpn);
vpn.setAppExclusionList(TEST_VPN_PKG, Arrays.asList(PKGS));
+ final Set<Range<Integer>> uidRanges = vpn.createUserAndRestrictedProfilesRanges(
+ PRIMARY_USER.id, null /* allowedApplications */, Arrays.asList(PKGS));
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
verify(mMockNetworkAgent).doSendNetworkCapabilities(any());
assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
@@ -1132,33 +1154,36 @@
// Remove one of the package
List<Integer> newExcludedUids = toList(PKG_UIDS);
newExcludedUids.remove((Integer) PKG_UIDS[0]);
+ Set<Range<Integer>> newUidRanges = makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids);
sPackages.remove(PKGS[0]);
vpn.refreshPlatformVpnAppExclusionList();
// List in keystore is not changed, but UID for the removed packages is no longer exempted.
assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
- assertEquals(makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids),
- vpn.mNetworkCapabilities.getUids());
+ assertEquals(newUidRanges, vpn.mNetworkCapabilities.getUids());
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
- assertEquals(makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids),
- ncCaptor.getValue().getUids());
+ assertEquals(newUidRanges, ncCaptor.getValue().getUids());
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(newUidRanges));
reset(mMockNetworkAgent);
// Add the package back
newExcludedUids.add(PKG_UIDS[0]);
+ newUidRanges = makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids);
sPackages.put(PKGS[0], PKG_UIDS[0]);
vpn.refreshPlatformVpnAppExclusionList();
// List in keystore is not changed and the uid list should be updated in the net cap.
assertEquals(Arrays.asList(PKGS), vpn.getAppExclusionList(TEST_VPN_PKG));
- assertEquals(makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids),
- vpn.mNetworkCapabilities.getUids());
+ assertEquals(newUidRanges, vpn.mNetworkCapabilities.getUids());
verify(mMockNetworkAgent).doSendNetworkCapabilities(ncCaptor.capture());
- assertEquals(makeVpnUidRangeSet(PRIMARY_USER.id, newExcludedUids),
- ncCaptor.getValue().getUids());
+ assertEquals(newUidRanges, ncCaptor.getValue().getUids());
+
+ // The uidRange is the same as the original setAppExclusionList so this is the second call
+ verify(mConnectivityManager, times(2))
+ .setVpnDefaultForUids(eq(sessionKey), eq(newUidRanges));
}
private List<Range<Integer>> makeVpnUidRange(int userId, List<Integer> excludedAppIdList) {
@@ -1784,6 +1809,9 @@
.getRedactedLinkPropertiesForPackage(any(), anyInt(), anyString());
final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
+ final Set<Range<Integer>> uidRanges = rangeSet(PRIMARY_USER_RANGE);
+ // This is triggered by Ikev2VpnRunner constructor.
+ verify(mConnectivityManager, times(1)).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
@@ -1792,6 +1820,8 @@
// state
verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
.createIkeSession(any(), any(), any(), any(), captor.capture(), any());
+ // This is triggered by Vpn#startOrMigrateIkeSession().
+ verify(mConnectivityManager, times(2)).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
reset(mIkev2SessionCreator);
// For network lost case, the process should be triggered by calling onLost(), which is the
// same process with the real case.
@@ -1811,16 +1841,43 @@
new String[] {TEST_VPN_PKG}, new VpnProfileState(VpnProfileState.STATE_CONNECTING,
sessionKey, false /* alwaysOn */, false /* lockdown */));
if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey),
+ eq(Collections.EMPTY_LIST));
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
.unregisterNetworkCallback(eq(cb));
} else if (errorType == VpnManager.ERROR_CLASS_RECOVERABLE
// Vpn won't retry when there is no usable underlying network.
&& errorCode != VpnManager.ERROR_CODE_NETWORK_LOST) {
int retryIndex = 0;
- final IkeSessionCallback ikeCb2 = verifyRetryAndGetNewIkeCb(retryIndex++);
+ // First failure occurred above.
+ final IkeSessionCallback retryCb = verifyRetryAndGetNewIkeCb(retryIndex++);
+ // Trigger 2 more failures to let the retry delay increase to 5s.
+ mExecutor.execute(() -> retryCb.onClosedWithException(exception));
+ final IkeSessionCallback retryCb2 = verifyRetryAndGetNewIkeCb(retryIndex++);
+ mExecutor.execute(() -> retryCb2.onClosedWithException(exception));
+ final IkeSessionCallback retryCb3 = verifyRetryAndGetNewIkeCb(retryIndex++);
- mExecutor.execute(() -> ikeCb2.onClosedWithException(exception));
+ // setVpnDefaultForUids may be called again but the uidRanges should not change.
+ verify(mConnectivityManager, atLeast(2)).setVpnDefaultForUids(eq(sessionKey),
+ mUidRangesCaptor.capture());
+ final List<Collection<Range<Integer>>> capturedUidRanges =
+ mUidRangesCaptor.getAllValues();
+ for (int i = 2; i < capturedUidRanges.size(); i++) {
+ // Assert equals no order.
+ assertTrue(
+ "uid ranges should not be modified. Expected: " + uidRanges
+ + ", actual: " + capturedUidRanges.get(i),
+ capturedUidRanges.get(i).containsAll(uidRanges)
+ && capturedUidRanges.get(i).size() == uidRanges.size());
+ }
+
+ // A fourth failure will cause the retry delay to be greater than 5s.
+ mExecutor.execute(() -> retryCb3.onClosedWithException(exception));
verifyRetryAndGetNewIkeCb(retryIndex++);
+
+ // The VPN network preference will be cleared when the retry delay is greater than 5s.
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey),
+ eq(Collections.EMPTY_LIST));
}
}
@@ -1982,16 +2039,7 @@
private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
setMockedUsers(PRIMARY_USER);
-
- // Dummy egress interface
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(EGRESS_IFACE);
-
- final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
- InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
- lp.addRoute(defaultRoute);
-
- vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp);
+ vpn.startLegacyVpn(vpnProfile);
return vpn;
}
@@ -2103,7 +2151,9 @@
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(vpnProfile.encode());
- vpn.startVpnProfile(TEST_VPN_PKG);
+ final String sessionKey = vpn.startVpnProfile(TEST_VPN_PKG);
+ final Set<Range<Integer>> uidRanges = Collections.singleton(PRIMARY_USER_RANGE);
+ verify(mConnectivityManager).setVpnDefaultForUids(eq(sessionKey), eq(uidRanges));
final NetworkCallback nwCb = triggerOnAvailableAndGetCallback(underlyingNetworkCaps);
// There are 4 interactions with the executor.
// - Network available
@@ -2196,6 +2246,7 @@
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+ verify(mConnectivityManager).setVpnDefaultForUids(anyString(), eq(Collections.EMPTY_LIST));
}
@Test
@@ -3104,6 +3155,20 @@
assertThrows(UnsupportedOperationException.class, () -> startLegacyVpn(vpn, profile));
}
+ @Test
+ public void testStartLegacyVpnModifyProfile_TypePSK() throws Exception {
+ setMockedUsers(PRIMARY_USER);
+ final Vpn vpn = createVpn(PRIMARY_USER.id);
+ final Ikev2VpnProfile ikev2VpnProfile =
+ new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY)
+ .setAuthPsk(TEST_VPN_PSK)
+ .build();
+ final VpnProfile profile = ikev2VpnProfile.toVpnProfile();
+
+ startLegacyVpn(vpn, profile);
+ assertEquals(profile, ikev2VpnProfile.toVpnProfile());
+ }
+
private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
assertNotNull(nc);
VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
@@ -3248,12 +3313,6 @@
}
@Override
- public long getNextRetryDelayMs(int retryCount) {
- // Simply return retryCount as the delay seconds for retrying.
- return retryCount * 1000;
- }
-
- @Override
public long getValidationFailRecoveryMs(int retryCount) {
// Simply return retryCount as the delay seconds for retrying.
return retryCount * 100L;
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
index 2126a09..a753922 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSKeepConnectedTest.kt
@@ -47,8 +47,9 @@
val keepConnectedAgent = Agent(nc = nc, score = FromS(NetworkScore.Builder()
.setKeepConnectedReason(KEEP_CONNECTED_LOCAL_NETWORK)
.build()),
- lnc = LocalNetworkConfig.Builder().build())
- val dontKeepConnectedAgent = Agent(nc = nc, lnc = LocalNetworkConfig.Builder().build())
+ lnc = FromS(LocalNetworkConfig.Builder().build()))
+ val dontKeepConnectedAgent = Agent(nc = nc,
+ lnc = FromS(LocalNetworkConfig.Builder().build()))
doTestKeepConnected(keepConnectedAgent, dontKeepConnectedAgent)
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt
index cfc3a3d..6add6b9 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentCreationTests.kt
@@ -49,7 +49,7 @@
private fun keepConnectedScore() =
FromS(NetworkScore.Builder().setKeepConnectedReason(KEEP_CONNECTED_FOR_TEST).build())
-private fun defaultLnc() = LocalNetworkConfig.Builder().build()
+private fun defaultLnc() = FromS(LocalNetworkConfig.Builder().build())
@RunWith(DevSdkIgnoreRunner::class)
@SmallTest
@@ -124,8 +124,7 @@
lnc = null)
}
assertFailsWith<IllegalArgumentException> {
- Agent(nc = NetworkCapabilities.Builder().build(),
- lnc = LocalNetworkConfig.Builder().build())
+ Agent(nc = NetworkCapabilities.Builder().build(), lnc = defaultLnc())
}
}
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
index 1dab548..ad21bf5 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
@@ -94,7 +94,7 @@
}
assertFailsWith<IllegalArgumentException> {
Agent(nc = NetworkCapabilities.Builder().build(),
- lnc = LocalNetworkConfig.Builder().build())
+ lnc = FromS(LocalNetworkConfig.Builder().build()))
}
}
@@ -110,7 +110,7 @@
val agent = Agent(nc = NetworkCapabilities.Builder()
.addCapability(NET_CAPABILITY_LOCAL_NETWORK)
.build(),
- lnc = LocalNetworkConfig.Builder().build())
+ lnc = FromS(LocalNetworkConfig.Builder().build()))
agent.connect()
cb.expectAvailableCallbacks(agent.network, validated = false)
agent.sendNetworkCapabilities(NetworkCapabilities.Builder().build())
@@ -141,7 +141,7 @@
val localAgent = Agent(
nc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK),
lp = lp("local0"),
- lnc = LocalNetworkConfig.Builder().build(),
+ lnc = FromS(LocalNetworkConfig.Builder().build()),
)
localAgent.connect()
@@ -194,11 +194,11 @@
// Set up a local agent that should forward its traffic to the best wifi upstream.
val localAgent = Agent(nc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK),
lp = lp("local0"),
- lnc = LocalNetworkConfig.Builder()
+ lnc = FromS(LocalNetworkConfig.Builder()
.setUpstreamSelector(NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build())
- .build(),
+ .build()),
score = FromS(NetworkScore.Builder()
.setKeepConnectedReason(KEEP_CONNECTED_LOCAL_NETWORK)
.build())
@@ -247,11 +247,11 @@
// Set up a local agent that should forward its traffic to the best wifi upstream.
val localAgent = Agent(nc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK),
lp = lp("local0"),
- lnc = LocalNetworkConfig.Builder()
+ lnc = FromS(LocalNetworkConfig.Builder()
.setUpstreamSelector(NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build())
- .build(),
+ .build()),
score = FromS(NetworkScore.Builder()
.setKeepConnectedReason(KEEP_CONNECTED_LOCAL_NETWORK)
.build())
@@ -293,11 +293,11 @@
cm.registerNetworkCallback(NetworkRequest.Builder().clearCapabilities().build(), cb)
val localNc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK)
- val lnc = LocalNetworkConfig.Builder()
+ val lnc = FromS(LocalNetworkConfig.Builder()
.setUpstreamSelector(NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build())
- .build()
+ .build())
val localScore = FromS(NetworkScore.Builder().build())
// Set up a local agent that should forward its traffic to the best wifi upstream.
@@ -346,11 +346,11 @@
wifiAgent.unregisterAfterReplacement(LONG_TIMEOUT_MS)
val localAgent = Agent(nc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK),
lp = lp("local0"),
- lnc = LocalNetworkConfig.Builder()
+ lnc = FromS(LocalNetworkConfig.Builder()
.setUpstreamSelector(NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build())
- .build(),
+ .build()),
score = FromS(NetworkScore.Builder()
.setKeepConnectedReason(KEEP_CONNECTED_LOCAL_NETWORK)
.build())
@@ -374,11 +374,11 @@
fun testForwardingRules() {
deps.setBuildSdk(VERSION_V)
// Set up a local agent that should forward its traffic to the best DUN upstream.
- val lnc = LocalNetworkConfig.Builder()
+ val lnc = FromS(LocalNetworkConfig.Builder()
.setUpstreamSelector(NetworkRequest.Builder()
.addCapability(NET_CAPABILITY_DUN)
.build())
- .build()
+ .build())
val localAgent = Agent(nc = nc(TRANSPORT_WIFI, NET_CAPABILITY_LOCAL_NETWORK),
lp = lp("local0"),
lnc = lnc,
@@ -426,7 +426,7 @@
// Make sure sending the same config again doesn't do anything
repeat(5) {
- localAgent.sendLocalNetworkConfig(lnc)
+ localAgent.sendLocalNetworkConfig(lnc.value)
}
inOrder.verifyNoMoreInteractions()
@@ -501,13 +501,13 @@
}
// Set up a local agent.
- val lnc = LocalNetworkConfig.Builder().apply {
+ val lnc = FromS(LocalNetworkConfig.Builder().apply {
if (haveUpstream) {
setUpstreamSelector(NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI)
.build())
}
- }.build()
+ }.build())
val localAgent = Agent(nc = nc(TRANSPORT_THREAD, NET_CAPABILITY_LOCAL_NETWORK),
lp = lp("local0"),
lnc = lnc,
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt
new file mode 100644
index 0000000..526ec9d
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivityservice/CSNetworkActivityTest.kt
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2023 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
+import android.net.ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE
+import android.net.ConnectivityManager.EXTRA_DEVICE_TYPE
+import android.net.ConnectivityManager.EXTRA_IS_ACTIVE
+import android.net.ConnectivityManager.EXTRA_REALTIME_NS
+import android.net.LinkProperties
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_IMS
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+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.os.Build
+import android.os.ConditionVariable
+import android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+import android.telephony.DataConnectionRealTimeInfo.DC_POWER_STATE_LOW
+import androidx.test.filters.SmallTest
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener
+import com.android.server.CSTest.CSContext
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.RecorderCallback.CallbackEntry.Lost
+import com.android.testutils.TestableNetworkCallback
+import kotlin.test.assertNotNull
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.never
+import org.mockito.Mockito.timeout
+import org.mockito.Mockito.verify
+
+private const val DATA_CELL_IFNAME = "rmnet_data"
+private const val IMS_CELL_IFNAME = "rmnet_ims"
+private const val WIFI_IFNAME = "wlan0"
+private const val TIMESTAMP = 1234L
+private const val NETWORK_ACTIVITY_NO_UID = -1
+private const val PACKAGE_UID = 123
+private const val TIMEOUT_MS = 250L
+
+@RunWith(DevSdkIgnoreRunner::class)
+@SmallTest
+@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+class CSNetworkActivityTest : CSTest() {
+
+ private fun getRegisteredNetdUnsolicitedEventListener(): BaseNetdUnsolicitedEventListener {
+ val captor = ArgumentCaptor.forClass(BaseNetdUnsolicitedEventListener::class.java)
+ verify(netd).registerUnsolicitedEventListener(captor.capture())
+ return captor.value
+ }
+
+ @Test
+ fun testInterfaceClassActivityChanged_NonDefaultNetwork() {
+ val netdUnsolicitedEventListener = getRegisteredNetdUnsolicitedEventListener()
+ val batteryStatsInorder = inOrder(batteryStats)
+
+ val cellNr = NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build()
+ val cellCb = TestableNetworkCallback()
+ // Request cell network to keep cell network up
+ cm.requestNetwork(cellNr, cellCb)
+
+ val defaultCb = TestableNetworkCallback()
+ cm.registerDefaultNetworkCallback(defaultCb)
+
+ val cellNc = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build()
+ val cellLp = LinkProperties().apply {
+ interfaceName = DATA_CELL_IFNAME
+ }
+ // Connect Cellular network
+ val cellAgent = Agent(nc = cellNc, lp = cellLp)
+ cellAgent.connect()
+ defaultCb.expectAvailableCallbacks(cellAgent.network, validated = false)
+
+ val wifiNc = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build()
+ val wifiLp = LinkProperties().apply {
+ interfaceName = WIFI_IFNAME
+ }
+ // Connect Wi-Fi network, Wi-Fi network should be the default network.
+ val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
+ wifiAgent.connect()
+ defaultCb.expectAvailableCallbacks(wifiAgent.network, validated = false)
+ batteryStatsInorder.verify(batteryStats).noteWifiRadioPowerState(eq(DC_POWER_STATE_HIGH),
+ anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
+
+ val onNetworkActiveCv = ConditionVariable()
+ val listener = ConnectivityManager.OnNetworkActiveListener { onNetworkActiveCv::open }
+ cm.addDefaultNetworkActiveListener(listener)
+
+ // Cellular network (non default network) goes to inactive state.
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
+ cellAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
+ // Non-default network activity change does not change default network activity
+ // But cellular radio power state is updated
+ assertFalse(onNetworkActiveCv.block(TIMEOUT_MS))
+ context.expectNoDataActivityBroadcast(0 /* timeoutMs */)
+ assertTrue(cm.isDefaultNetworkActive)
+ batteryStatsInorder.verify(batteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_LOW),
+ anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
+
+ // Cellular network (non default network) goes to active state.
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
+ cellAgent.network.netId, TIMESTAMP, PACKAGE_UID)
+ // Non-default network activity change does not change default network activity
+ // But cellular radio power state is updated
+ assertFalse(onNetworkActiveCv.block(TIMEOUT_MS))
+ context.expectNoDataActivityBroadcast(0 /* timeoutMs */)
+ assertTrue(cm.isDefaultNetworkActive)
+ batteryStatsInorder.verify(batteryStats).noteMobileRadioPowerState(eq(DC_POWER_STATE_HIGH),
+ anyLong() /* timestampNs */, eq(PACKAGE_UID))
+
+ cm.unregisterNetworkCallback(cellCb)
+ cm.unregisterNetworkCallback(defaultCb)
+ cm.removeDefaultNetworkActiveListener(listener)
+ }
+
+ @Test
+ fun testDataActivityTracking_MultiCellNetwork() {
+ val netdUnsolicitedEventListener = getRegisteredNetdUnsolicitedEventListener()
+ val batteryStatsInorder = inOrder(batteryStats)
+
+ val dataNetworkNc = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .build()
+ val dataNetworkNr = NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build()
+ val dataNetworkLp = LinkProperties().apply {
+ interfaceName = DATA_CELL_IFNAME
+ }
+ val dataNetworkCb = TestableNetworkCallback()
+ cm.requestNetwork(dataNetworkNr, dataNetworkCb)
+ val dataNetworkAgent = Agent(nc = dataNetworkNc, lp = dataNetworkLp)
+ val dataNetworkNetId = dataNetworkAgent.network.netId.toString()
+
+ val imsNetworkNc = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_IMS)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .build()
+ val imsNetworkNr = NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_IMS)
+ .build()
+ val imsNetworkLp = LinkProperties().apply {
+ interfaceName = IMS_CELL_IFNAME
+ }
+ val imsNetworkCb = TestableNetworkCallback()
+ cm.requestNetwork(imsNetworkNr, imsNetworkCb)
+ val imsNetworkAgent = Agent(nc = imsNetworkNc, lp = imsNetworkLp)
+ val imsNetworkNetId = imsNetworkAgent.network.netId.toString()
+
+ dataNetworkAgent.connect()
+ dataNetworkCb.expectAvailableCallbacks(dataNetworkAgent.network, validated = false)
+
+ imsNetworkAgent.connect()
+ imsNetworkCb.expectAvailableCallbacks(imsNetworkAgent.network, validated = false)
+
+ // Both cell networks have idleTimers
+ verify(netd).idletimerAddInterface(eq(DATA_CELL_IFNAME), anyInt(), eq(dataNetworkNetId))
+ verify(netd).idletimerAddInterface(eq(IMS_CELL_IFNAME), anyInt(), eq(imsNetworkNetId))
+ verify(netd, never()).idletimerRemoveInterface(eq(DATA_CELL_IFNAME), anyInt(),
+ eq(dataNetworkNetId))
+ verify(netd, never()).idletimerRemoveInterface(eq(IMS_CELL_IFNAME), anyInt(),
+ eq(imsNetworkNetId))
+
+ // Both cell networks go to inactive state
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
+ imsNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
+ dataNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
+
+ // Data cell network goes to active state. This should update the cellular radio power state
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
+ dataNetworkAgent.network.netId, TIMESTAMP, PACKAGE_UID)
+ batteryStatsInorder.verify(batteryStats, timeout(TIMEOUT_MS)).noteMobileRadioPowerState(
+ eq(DC_POWER_STATE_HIGH), anyLong() /* timestampNs */, eq(PACKAGE_UID))
+ // Ims cell network goes to active state. But this should not update the cellular radio
+ // power state since cellular radio power state is already high
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(true /* isActive */,
+ imsNetworkAgent.network.netId, TIMESTAMP, PACKAGE_UID)
+ waitForIdle()
+ batteryStatsInorder.verify(batteryStats, never()).noteMobileRadioPowerState(anyInt(),
+ anyLong() /* timestampNs */, anyInt())
+
+ // Data cell network goes to inactive state. But this should not update the cellular radio
+ // power state ims cell network is still active state
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
+ dataNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
+ waitForIdle()
+ batteryStatsInorder.verify(batteryStats, never()).noteMobileRadioPowerState(anyInt(),
+ anyLong() /* timestampNs */, anyInt())
+
+ // Ims cell network goes to inactive state.
+ // This should update the cellular radio power state
+ netdUnsolicitedEventListener.onInterfaceClassActivityChanged(false /* isActive */,
+ imsNetworkAgent.network.netId, TIMESTAMP, NETWORK_ACTIVITY_NO_UID)
+ batteryStatsInorder.verify(batteryStats, timeout(TIMEOUT_MS)).noteMobileRadioPowerState(
+ eq(DC_POWER_STATE_LOW), anyLong() /* timestampNs */, eq(NETWORK_ACTIVITY_NO_UID))
+
+ dataNetworkAgent.disconnect()
+ dataNetworkCb.expect<Lost>(dataNetworkAgent.network)
+ verify(netd).idletimerRemoveInterface(eq(DATA_CELL_IFNAME), anyInt(), eq(dataNetworkNetId))
+
+ imsNetworkAgent.disconnect()
+ imsNetworkCb.expect<Lost>(imsNetworkAgent.network)
+ verify(netd).idletimerRemoveInterface(eq(IMS_CELL_IFNAME), anyInt(), eq(imsNetworkNetId))
+
+ cm.unregisterNetworkCallback(dataNetworkCb)
+ cm.unregisterNetworkCallback(imsNetworkCb)
+ }
+}
+
+internal fun CSContext.expectDataActivityBroadcast(
+ deviceType: Int,
+ isActive: Boolean,
+ tsNanos: Long
+) {
+ assertNotNull(orderedBroadcastAsUserHistory.poll(BROADCAST_TIMEOUT_MS) {
+ intent -> intent.action.equals(ACTION_DATA_ACTIVITY_CHANGE) &&
+ intent.getIntExtra(EXTRA_DEVICE_TYPE, -1) == deviceType &&
+ intent.getBooleanExtra(EXTRA_IS_ACTIVE, !isActive) == isActive &&
+ intent.getLongExtra(EXTRA_REALTIME_NS, -1) == tsNanos
+ })
+}
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
index 013a749..d41c742 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
@@ -69,7 +69,7 @@
nac: NetworkAgentConfig,
val nc: NetworkCapabilities,
val lp: LinkProperties,
- val lnc: LocalNetworkConfig?,
+ val lnc: FromS<LocalNetworkConfig>?,
val score: FromS<NetworkScore>,
val provider: NetworkProvider?
) : TestableNetworkCallback.HasNetwork {
@@ -101,7 +101,7 @@
// Create the actual agent. NetworkAgent is abstract, so make an anonymous subclass.
if (deps.isAtLeastS()) {
agent = object : NetworkAgent(context, csHandlerThread.looper, TAG,
- nc, lp, lnc, score.value, nac, provider) {}
+ nc, lp, lnc?.value, score.value, nac, provider) {}
} else {
agent = object : NetworkAgent(context, csHandlerThread.looper, TAG,
nc, lp, 50 /* score */, nac, provider) {}
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 1786edc..4f5cfc0 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
@@ -43,6 +43,7 @@
import android.net.PacProxyManager
import android.net.networkstack.NetworkStackClientBase
import android.os.BatteryStatsManager
+import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.os.UserHandle
@@ -54,6 +55,7 @@
import com.android.internal.app.IBatteryStats
import com.android.internal.util.test.BroadcastInterceptingContext
import com.android.modules.utils.build.SdkLevel
+import com.android.net.module.util.ArrayTrackRecord
import com.android.networkstack.apishim.common.UnsupportedApiLevelException
import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker
import com.android.server.connectivity.CarrierPrivilegeAuthenticator
@@ -64,14 +66,16 @@
import com.android.server.connectivity.ProxyTracker
import com.android.testutils.visibleOnHandlerThread
import com.android.testutils.waitForIdle
+import java.util.concurrent.Executors
+import kotlin.test.assertNull
+import kotlin.test.fail
import org.mockito.AdditionalAnswers.delegatesTo
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
-import java.util.concurrent.Executors
-import kotlin.test.fail
internal const val HANDLER_TIMEOUT_MS = 2_000
+internal const val BROADCAST_TIMEOUT_MS = 3_000L
internal const val TEST_PACKAGE_NAME = "com.android.test.package"
internal const val WIFI_WOL_IFNAME = "test_wlan_wol"
internal val LOCAL_IPV4_ADDRESS = InetAddresses.parseNumericAddress("192.0.2.1")
@@ -155,7 +159,8 @@
val proxyTracker = ProxyTracker(context, mock<Handler>(), 16 /* EVENT_PROXY_HAS_CHANGED */)
val alarmManager = makeMockAlarmManager()
val systemConfigManager = makeMockSystemConfigManager()
- val batteryManager = BatteryStatsManager(mock<IBatteryStats>())
+ val batteryStats = mock<IBatteryStats>()
+ val batteryManager = BatteryStatsManager(batteryStats)
val telephonyManager = mock<TelephonyManager>().also {
doReturn(true).`when`(it).isDataCapable()
}
@@ -285,6 +290,26 @@
Context.STATS_MANAGER -> null // Stats manager is final and can't be mocked
else -> super.getSystemService(serviceName)
}
+
+ internal val orderedBroadcastAsUserHistory = ArrayTrackRecord<Intent>().newReadHead()
+
+ fun expectNoDataActivityBroadcast(timeoutMs: Int) {
+ assertNull(orderedBroadcastAsUserHistory.poll(
+ timeoutMs.toLong()) { intent -> true })
+ }
+
+ override fun sendOrderedBroadcastAsUser(
+ intent: Intent,
+ user: UserHandle,
+ receiverPermission: String?,
+ resultReceiver: BroadcastReceiver?,
+ scheduler: Handler?,
+ initialCode: Int,
+ initialData: String?,
+ initialExtras: Bundle?
+ ) {
+ orderedBroadcastAsUserHistory.add(intent)
+ }
}
// Utility methods for subclasses to use
@@ -296,7 +321,7 @@
nc: NetworkCapabilities = defaultNc(),
nac: NetworkAgentConfig = emptyAgentConfig(nc.getLegacyType()),
lp: LinkProperties = defaultLp(),
- lnc: LocalNetworkConfig? = null,
+ lnc: FromS<LocalNetworkConfig>? = null,
score: FromS<NetworkScore> = defaultScore(),
provider: NetworkProvider? = null
) = CSAgentWrapper(context, deps, csHandlerThread, networkStack,
diff --git a/thread/service/Android.bp b/thread/service/Android.bp
index bd265e6..35ae3c2 100644
--- a/thread/service/Android.bp
+++ b/thread/service/Android.bp
@@ -43,6 +43,9 @@
"ot-daemon-aidl-java",
],
apex_available: ["com.android.tethering"],
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ },
}
cc_library_shared {
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
index 33516aa..60c97bf 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
@@ -14,6 +14,10 @@
package com.android.server.thread;
+import static android.net.MulticastRoutingConfig.CONFIG_FORWARD_NONE;
+import static android.net.MulticastRoutingConfig.FORWARD_NONE;
+import static android.net.MulticastRoutingConfig.FORWARD_SELECTED;
+import static android.net.MulticastRoutingConfig.FORWARD_WITH_MIN_SCOPE;
import static android.net.thread.ActiveOperationalDataset.CHANNEL_PAGE_24_GHZ;
import static android.net.thread.ActiveOperationalDataset.LENGTH_EXTENDED_PAN_ID;
import static android.net.thread.ActiveOperationalDataset.LENGTH_MESH_LOCAL_PREFIX_BITS;
@@ -51,13 +55,20 @@
import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.LocalNetworkConfig;
+import android.net.MulticastRoutingConfig;
+import android.net.LocalNetworkInfo;
+import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
+import android.net.NetworkRequest;
import android.net.NetworkScore;
+import android.net.RouteInfo;
import android.net.thread.ActiveOperationalDataset;
import android.net.thread.ActiveOperationalDataset.SecurityPolicy;
import android.net.thread.IActiveOperationalDatasetReceiver;
@@ -85,8 +96,10 @@
import com.android.server.thread.openthread.IOtStatusReceiver;
import com.android.server.thread.openthread.Ipv6AddressInfo;
import com.android.server.thread.openthread.OtDaemonState;
+import com.android.server.thread.openthread.BorderRouterConfigurationParcel;
import java.io.IOException;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
@@ -131,6 +144,14 @@
private IOtDaemon mOtDaemon;
private NetworkAgent mNetworkAgent;
+ private MulticastRoutingConfig mUpstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
+ private MulticastRoutingConfig mDownstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
+ private Network mUpstreamNetwork;
+ private final NetworkRequest mUpstreamNetworkRequest;
+ private final HashMap<Network, String> mNetworkToInterface;
+ private final LocalNetworkConfig mLocalNetworkConfig;
+
+ private BorderRouterConfigurationParcel mBorderRouterConfig;
@VisibleForTesting
ThreadNetworkControllerService(
@@ -147,6 +168,18 @@
mOtDaemonSupplier = otDaemonSupplier;
mConnectivityManager = connectivityManager;
mTunIfController = tunIfController;
+ mUpstreamNetworkRequest =
+ new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .build();
+ mLocalNetworkConfig =
+ new LocalNetworkConfig.Builder()
+ .setUpstreamSelector(mUpstreamNetworkRequest)
+ .build();
+ mNetworkToInterface = new HashMap<Network, String>();
+ mBorderRouterConfig = new BorderRouterConfigurationParcel();
}
public static ThreadNetworkControllerService newInstance(Context context) {
@@ -167,19 +200,24 @@
private static NetworkCapabilities newNetworkCapabilities() {
return new NetworkCapabilities.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_THREAD)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
.build();
}
- private static InetAddress addressInfoToInetAddress(Ipv6AddressInfo addressInfo) {
+ private static Inet6Address bytesToInet6Address(byte[] addressBytes) {
try {
- return InetAddress.getByAddress(addressInfo.address);
+ return (Inet6Address) Inet6Address.getByAddress(addressBytes);
} catch (UnknownHostException e) {
- // This is impossible unless the Thread daemon is critically broken
+ // This is unlikely to happen unless the Thread daemon is critically broken
return null;
}
}
+ private static InetAddress addressInfoToInetAddress(Ipv6AddressInfo addressInfo) {
+ return bytesToInet6Address(addressInfo.address);
+ }
+
private static LinkAddress newLinkAddress(Ipv6AddressInfo addressInfo) {
long deprecationTimeMillis =
addressInfo.isPreferred
@@ -244,11 +282,77 @@
mLinkProperties.setInterfaceName(TUN_IF_NAME);
mLinkProperties.setMtu(TunInterfaceController.MTU);
mConnectivityManager.registerNetworkProvider(mNetworkProvider);
+ requestUpstreamNetwork();
initializeOtDaemon();
});
}
+ private void requestUpstreamNetwork() {
+ mConnectivityManager.registerNetworkCallback(
+ mUpstreamNetworkRequest,
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ Log.i(TAG, "onAvailable: " + network);
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ Log.i(TAG, "onLost: " + network);
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(
+ @NonNull Network network, @NonNull LinkProperties linkProperties) {
+ Log.i(
+ TAG,
+ String.format(
+ "onLinkPropertiesChanged: {network: %s, interface: %s}",
+ network, linkProperties.getInterfaceName()));
+ mNetworkToInterface.put(network, linkProperties.getInterfaceName());
+ if (network.equals(mUpstreamNetwork)) {
+ enableBorderRouting(mNetworkToInterface.get(mUpstreamNetwork));
+ }
+ }
+ },
+ mHandler);
+ }
+
+ private final class ThreadNetworkCallback extends ConnectivityManager.NetworkCallback {
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ Log.i(TAG, "onAvailable: Thread network Available");
+ }
+
+ @Override
+ public void onLocalNetworkInfoChanged(
+ @NonNull Network network, @NonNull LocalNetworkInfo localNetworkInfo) {
+ Log.i(TAG, "onLocalNetworkInfoChanged: " + localNetworkInfo);
+ if (localNetworkInfo.getUpstreamNetwork() == null) {
+ mUpstreamNetwork = null;
+ return;
+ }
+ if (!localNetworkInfo.getUpstreamNetwork().equals(mUpstreamNetwork)) {
+ mUpstreamNetwork = localNetworkInfo.getUpstreamNetwork();
+ if (mNetworkToInterface.containsKey(mUpstreamNetwork)) {
+ enableBorderRouting(mNetworkToInterface.get(mUpstreamNetwork));
+ }
+ }
+ }
+ }
+
+ private void requestThreadNetwork() {
+ mConnectivityManager.registerNetworkCallback(
+ new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_THREAD)
+ .removeForbiddenCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)
+ .build(),
+ new ThreadNetworkCallback(),
+ mHandler);
+ }
+
private void registerThreadNetwork() {
if (mNetworkAgent != null) {
return;
@@ -258,6 +362,7 @@
new NetworkScore.Builder()
.setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_LOCAL_NETWORK)
.build();
+ requestThreadNetwork();
mNetworkAgent =
new NetworkAgent(
mContext,
@@ -265,6 +370,7 @@
TAG,
netCaps,
mLinkProperties,
+ mLocalNetworkConfig,
score,
new NetworkAgentConfig.Builder().build(),
mNetworkProvider) {};
@@ -304,10 +410,19 @@
}
private void updateNetworkLinkProperties(LinkAddress linkAddress, boolean isAdded) {
+ RouteInfo routeInfo =
+ new RouteInfo(
+ new IpPrefix(linkAddress.getAddress(), 64),
+ null,
+ TUN_IF_NAME,
+ RouteInfo.RTN_UNICAST,
+ TunInterfaceController.MTU);
if (isAdded) {
mLinkProperties.addLinkAddress(linkAddress);
+ mLinkProperties.addRoute(routeInfo);
} else {
mLinkProperties.removeLinkAddress(linkAddress);
+ mLinkProperties.removeRoute(routeInfo);
}
// The Thread daemon can send link property updates before the networkAgent is
@@ -557,6 +672,39 @@
}
}
+ private void enableBorderRouting(String infraIfName) {
+ if (mBorderRouterConfig.isBorderRoutingEnabled
+ && infraIfName.equals(mBorderRouterConfig.infraInterfaceName)) {
+ return;
+ }
+ Log.i(TAG, "enableBorderRouting on AIL: " + infraIfName);
+ try {
+ mBorderRouterConfig.infraInterfaceName = infraIfName;
+ mBorderRouterConfig.infraInterfaceIcmp6Socket =
+ InfraInterfaceController.createIcmp6Socket(infraIfName);
+ mBorderRouterConfig.isBorderRoutingEnabled = true;
+
+ mOtDaemon.configureBorderRouter(
+ mBorderRouterConfig,
+ new IOtStatusReceiver.Stub() {
+ @Override
+ public void onSuccess() {
+ Log.i(TAG, "configure border router successfully");
+ }
+
+ @Override
+ public void onError(int i, String s) {
+ Log.w(
+ TAG,
+ String.format(
+ "failed to configure border router: %d %s", i, s));
+ }
+ });
+ } catch (Exception e) {
+ Log.w(TAG, "enableBorderRouting failed: " + e);
+ }
+ }
+
private void handleThreadInterfaceStateChanged(boolean isUp) {
try {
mTunIfController.setInterfaceUp(isUp);
@@ -597,6 +745,100 @@
updateNetworkLinkProperties(linkAddress, isAdded);
}
+ private boolean isMulticastForwardingEnabled() {
+ return !(mUpstreamMulticastRoutingConfig.getForwardingMode() == FORWARD_NONE
+ && mDownstreamMulticastRoutingConfig.getForwardingMode() == FORWARD_NONE);
+ }
+
+ private void sendLocalNetworkConfig() {
+ if (mNetworkAgent == null) {
+ return;
+ }
+ final LocalNetworkConfig.Builder configBuilder = new LocalNetworkConfig.Builder();
+ LocalNetworkConfig localNetworkConfig =
+ configBuilder
+ .setUpstreamMulticastRoutingConfig(mUpstreamMulticastRoutingConfig)
+ .setDownstreamMulticastRoutingConfig(mDownstreamMulticastRoutingConfig)
+ .setUpstreamSelector(mUpstreamNetworkRequest)
+ .build();
+ mNetworkAgent.sendLocalNetworkConfig(localNetworkConfig);
+ Log.d(
+ TAG,
+ "Sent localNetworkConfig with upstreamConfig "
+ + mUpstreamMulticastRoutingConfig
+ + " downstreamConfig"
+ + mDownstreamMulticastRoutingConfig);
+ }
+
+ private void handleMulticastForwardingStateChanged(boolean isEnabled) {
+ if (isMulticastForwardingEnabled() == isEnabled) {
+ return;
+ }
+ if (isEnabled) {
+ // When multicast forwarding is enabled, setup upstream forwarding to any address
+ // with minimal scope 4
+ // setup downstream forwarding with addresses subscribed from Thread network
+ mUpstreamMulticastRoutingConfig =
+ new MulticastRoutingConfig.Builder(FORWARD_WITH_MIN_SCOPE, 4).build();
+ mDownstreamMulticastRoutingConfig =
+ new MulticastRoutingConfig.Builder(FORWARD_SELECTED).build();
+ } else {
+ // When multicast forwarding is disabled, set both upstream and downstream
+ // forwarding config to FORWARD_NONE.
+ mUpstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
+ mDownstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
+ }
+ sendLocalNetworkConfig();
+ Log.d(
+ TAG,
+ "Sent updated localNetworkConfig with multicast forwarding "
+ + (isEnabled ? "enabled" : "disabled"));
+ }
+
+ private void handleMulticastForwardingAddressChanged(byte[] addressBytes, boolean isAdded) {
+ Inet6Address address = bytesToInet6Address(addressBytes);
+ MulticastRoutingConfig newDownstreamConfig;
+ MulticastRoutingConfig.Builder builder;
+
+ if (mDownstreamMulticastRoutingConfig.getForwardingMode() !=
+ MulticastRoutingConfig.FORWARD_SELECTED) {
+ Log.e(
+ TAG,
+ "Ignore multicast listening address updates when downstream multicast "
+ + "forwarding mode is not FORWARD_SELECTED");
+ // Don't update the address set if downstream multicast forwarding is disabled.
+ return;
+ }
+ if (isAdded ==
+ mDownstreamMulticastRoutingConfig.getListeningAddresses().contains(address)) {
+ return;
+ }
+
+ builder = new MulticastRoutingConfig.Builder(FORWARD_SELECTED);
+ for (Inet6Address listeningAddress :
+ mDownstreamMulticastRoutingConfig.getListeningAddresses()) {
+ builder.addListeningAddress(listeningAddress);
+ }
+
+ if (isAdded) {
+ builder.addListeningAddress(address);
+ } else {
+ builder.clearListeningAddress(address);
+ }
+
+ newDownstreamConfig = builder.build();
+ if (!newDownstreamConfig.equals(mDownstreamMulticastRoutingConfig)) {
+ Log.d(
+ TAG,
+ "Multicast listening address "
+ + address.getHostAddress()
+ + " is "
+ + (isAdded ? "added" : "removed"));
+ mDownstreamMulticastRoutingConfig = newDownstreamConfig;
+ sendLocalNetworkConfig();
+ }
+ }
+
private static final class CallbackMetadata {
private static long gId = 0;
@@ -728,6 +970,7 @@
onInterfaceStateChanged(newState.isInterfaceUp);
onDeviceRoleChanged(newState.deviceRole, listenerId);
onPartitionIdChanged(newState.partitionId, listenerId);
+ onMulticastForwardingStateChanged(newState.multicastForwardingEnabled);
mState = newState;
ActiveOperationalDataset newActiveDataset;
@@ -836,9 +1079,19 @@
}
}
+ private void onMulticastForwardingStateChanged(boolean isEnabled) {
+ checkOnHandlerThread();
+ handleMulticastForwardingStateChanged(isEnabled);
+ }
+
@Override
public void onAddressChanged(Ipv6AddressInfo addressInfo, boolean isAdded) {
mHandler.post(() -> handleAddressChanged(addressInfo, isAdded));
}
+
+ @Override
+ public void onMulticastForwardingAddressChanged(byte[] address, boolean isAdded) {
+ mHandler.post(() -> handleMulticastForwardingAddressChanged(address, isAdded));
+ }
}
}
diff --git a/thread/service/proguard.flags b/thread/service/proguard.flags
new file mode 100644
index 0000000..5028982
--- /dev/null
+++ b/thread/service/proguard.flags
@@ -0,0 +1,4 @@
+# Ensure the callback methods are not stripped
+-keepclassmembers class **.ThreadNetworkControllerService$ThreadNetworkCallback {
+ *;
+}