Merge "Resolve the udc-extended-api diff from aosp" into udc-mainline-prod
diff --git a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index 6f3e865..528991f 100644
--- a/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -189,7 +189,10 @@
return cachedAddress;
}
- for (IpPrefix prefixRange : mTetheringPrefixes) {
+ final int prefixIndex = getStartedPrefixIndex();
+ for (int i = 0; i < mTetheringPrefixes.size(); i++) {
+ final IpPrefix prefixRange = mTetheringPrefixes.get(
+ (prefixIndex + i) % mTetheringPrefixes.size());
final LinkAddress newAddress = chooseDownstreamAddress(prefixRange);
if (newAddress != null) {
mDownstreams.add(ipServer);
@@ -202,6 +205,28 @@
return null;
}
+ private int getStartedPrefixIndex() {
+ if (!mConfig.isRandomPrefixBaseEnabled()) return 0;
+
+ final int random = getRandomInt() & 0xffffff;
+ // This is to select the starting prefix range (/8, /12, or /16) instead of the actual
+ // LinkAddress. To avoid complex operations in the selection logic and make the selected
+ // rate approximate consistency with that /8 is around 2^4 times of /12 and /12 is around
+ // 2^4 times of /16, we simply define a map between the value and the prefix value like
+ // this:
+ //
+ // Value 0 ~ 0xffff (65536/16777216 = 0.39%) -> 192.168.0.0/16
+ // Value 0x10000 ~ 0xfffff (983040/16777216 = 5.86%) -> 172.16.0.0/12
+ // Value 0x100000 ~ 0xffffff (15728640/16777216 = 93.7%) -> 10.0.0.0/8
+ if (random > 0xfffff) {
+ return 2;
+ } else if (random > 0xffff) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
private int getPrefixBaseAddress(final IpPrefix prefix) {
return inet4AddressToIntHTH((Inet4Address) prefix.getAddress());
}
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index da3b584..5022b40 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -303,9 +303,9 @@
mContext = mDeps.getContext();
mNetd = mDeps.getINetd(mContext);
mRoutingCoordinator = mDeps.getRoutingCoordinator(mContext);
- mLooper = mDeps.getTetheringLooper();
- mNotificationUpdater = mDeps.getNotificationUpdater(mContext, mLooper);
- mTetheringMetrics = mDeps.getTetheringMetrics();
+ mLooper = mDeps.makeTetheringLooper();
+ mNotificationUpdater = mDeps.makeNotificationUpdater(mContext, mLooper);
+ mTetheringMetrics = mDeps.makeTetheringMetrics();
// This is intended to ensrure that if something calls startTethering(bluetooth) just after
// bluetooth is enabled. Before onServiceConnected is called, store the calls into this
@@ -319,7 +319,7 @@
mTetherMainSM.start();
mHandler = mTetherMainSM.getHandler();
- mOffloadController = mDeps.getOffloadController(mHandler, mLog,
+ mOffloadController = mDeps.makeOffloadController(mHandler, mLog,
new OffloadController.Dependencies() {
@Override
@@ -327,7 +327,7 @@
return mConfig;
}
});
- mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mHandler, mLog,
+ mUpstreamNetworkMonitor = mDeps.makeUpstreamNetworkMonitor(mContext, mHandler, mLog,
(what, obj) -> {
mTetherMainSM.sendMessage(TetherMainSM.EVENT_UPSTREAM_CALLBACK, what, 0, obj);
});
@@ -337,7 +337,7 @@
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
// EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
// permission is changed according to entitlement check result.
- mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
+ mEntitlementMgr = mDeps.makeEntitlementManager(mContext, mHandler, mLog,
() -> mTetherMainSM.sendMessage(
TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
mEntitlementMgr.setOnTetherProvisioningFailedListener((downstream, reason) -> {
@@ -373,11 +373,11 @@
// It is OK for the configuration to be passed to the PrivateAddressCoordinator at
// construction time because the only part of the configuration it uses is
// shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
- mPrivateAddressCoordinator = mDeps.getPrivateAddressCoordinator(mContext, mConfig);
+ mPrivateAddressCoordinator = mDeps.makePrivateAddressCoordinator(mContext, mConfig);
// Must be initialized after tethering configuration is loaded because BpfCoordinator
// constructor needs to use the configuration.
- mBpfCoordinator = mDeps.getBpfCoordinator(
+ mBpfCoordinator = mDeps.makeBpfCoordinator(
new BpfCoordinator.Dependencies() {
@NonNull
public Handler getHandler() {
@@ -406,7 +406,7 @@
});
if (SdkLevel.isAtLeastT() && mConfig.isWearTetheringEnabled()) {
- mWearableConnectionManager = mDeps.getWearableConnectionManager(mContext);
+ mWearableConnectionManager = mDeps.makeWearableConnectionManager(mContext);
} else {
mWearableConnectionManager = null;
}
@@ -875,7 +875,7 @@
private void changeBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan,
final boolean enable) {
- final BluetoothPanShim panShim = mDeps.getBluetoothPanShim(bluetoothPan);
+ final BluetoothPanShim panShim = mDeps.makeBluetoothPanShim(bluetoothPan);
if (enable) {
if (mBluetoothIfaceRequest != null) {
Log.d(TAG, "Bluetooth tethering settings already enabled");
@@ -1739,7 +1739,7 @@
addState(mSetDnsForwardersErrorState);
mNotifyList = new ArrayList<>();
- mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
+ mIPv6TetheringCoordinator = deps.makeIPv6TetheringCoordinator(mNotifyList, mLog);
mOffload = new OffloadWrapper();
setInitialState(mInitialState);
@@ -2844,7 +2844,7 @@
new IpServer(iface, mHandler, interfaceType, mLog, mNetd, mBpfCoordinator,
mRoutingCoordinator, new ControlCallback(), mConfig,
mPrivateAddressCoordinator, mTetheringMetrics,
- mDeps.getIpServerDependencies()), isNcm);
+ mDeps.makeIpServerDependencies()), isNcm);
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 502fee8..0678525 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -130,6 +130,8 @@
public static final String TETHER_ENABLE_WEAR_TETHERING =
"tether_enable_wear_tethering";
+ public static final String TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION =
+ "tether_force_random_prefix_base_selection";
/**
* Default value that used to periodic polls tether offload stats from tethering offload HAL
* to make the data warnings work.
@@ -171,6 +173,7 @@
private final int mP2pLeasesSubnetPrefixLength;
private final boolean mEnableWearTethering;
+ private final boolean mRandomPrefixBase;
private final int mUsbTetheringFunction;
protected final ContentResolver mContentResolver;
@@ -288,6 +291,8 @@
mEnableWearTethering = shouldEnableWearTethering(ctx);
+ mRandomPrefixBase = mDeps.isFeatureEnabled(ctx, TETHER_FORCE_RANDOM_PREFIX_BASE_SELECTION);
+
configLog.log(toString());
}
@@ -376,6 +381,10 @@
return mEnableWearTethering;
}
+ public boolean isRandomPrefixBaseEnabled() {
+ return mRandomPrefixBase;
+ }
+
/** Does the dumping.*/
public void dump(PrintWriter pw) {
pw.print("activeDataSubId: ");
@@ -426,6 +435,9 @@
pw.print("mUsbTetheringFunction: ");
pw.println(isUsingNcm() ? "NCM" : "RNDIS");
+
+ pw.print("mRandomPrefixBase: ");
+ pw.println(mRandomPrefixBase);
}
/** Returns the string representation of this object.*/
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index d02e8e8..9dfd225 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -53,58 +53,58 @@
*/
public abstract class TetheringDependencies {
/**
- * Get a reference to the BpfCoordinator to be used by tethering.
+ * Make the BpfCoordinator to be used by tethering.
*/
- public @NonNull BpfCoordinator getBpfCoordinator(
+ public @NonNull BpfCoordinator makeBpfCoordinator(
@NonNull BpfCoordinator.Dependencies deps) {
return new BpfCoordinator(deps);
}
/**
- * Get a reference to the offload hardware interface to be used by tethering.
+ * Make the offload hardware interface to be used by tethering.
*/
- public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+ public OffloadHardwareInterface makeOffloadHardwareInterface(Handler h, SharedLog log) {
return new OffloadHardwareInterface(h, log);
}
/**
- * Get a reference to the offload controller to be used by tethering.
+ * Make the offload controller to be used by tethering.
*/
@NonNull
- public OffloadController getOffloadController(@NonNull Handler h,
+ public OffloadController makeOffloadController(@NonNull Handler h,
@NonNull SharedLog log, @NonNull OffloadController.Dependencies deps) {
final NetworkStatsManager statsManager =
(NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE);
- return new OffloadController(h, getOffloadHardwareInterface(h, log),
+ return new OffloadController(h, makeOffloadHardwareInterface(h, log),
getContext().getContentResolver(), statsManager, log, deps);
}
/**
- * Get a reference to the UpstreamNetworkMonitor to be used by tethering.
+ * Make the UpstreamNetworkMonitor to be used by tethering.
*/
- public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, Handler h,
+ public UpstreamNetworkMonitor makeUpstreamNetworkMonitor(Context ctx, Handler h,
SharedLog log, UpstreamNetworkMonitor.EventListener listener) {
return new UpstreamNetworkMonitor(ctx, h, log, listener);
}
/**
- * Get a reference to the IPv6TetheringCoordinator to be used by tethering.
+ * Make the IPv6TetheringCoordinator to be used by tethering.
*/
- public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+ public IPv6TetheringCoordinator makeIPv6TetheringCoordinator(
ArrayList<IpServer> notifyList, SharedLog log) {
return new IPv6TetheringCoordinator(notifyList, log);
}
/**
- * Get dependencies to be used by IpServer.
+ * Make dependencies to be used by IpServer.
*/
- public abstract IpServer.Dependencies getIpServerDependencies();
+ public abstract IpServer.Dependencies makeIpServerDependencies();
/**
- * Get a reference to the EntitlementManager to be used by tethering.
+ * Make the EntitlementManager to be used by tethering.
*/
- public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
+ public EntitlementManager makeEntitlementManager(Context ctx, Handler h, SharedLog log,
Runnable callback) {
return new EntitlementManager(ctx, h, log, callback);
}
@@ -136,17 +136,17 @@
}
/**
- * Get a reference to the TetheringNotificationUpdater to be used by tethering.
+ * Make the TetheringNotificationUpdater to be used by tethering.
*/
- public TetheringNotificationUpdater getNotificationUpdater(@NonNull final Context ctx,
+ public TetheringNotificationUpdater makeNotificationUpdater(@NonNull final Context ctx,
@NonNull final Looper looper) {
return new TetheringNotificationUpdater(ctx, looper);
}
/**
- * Get tethering thread looper.
+ * Make tethering thread looper.
*/
- public abstract Looper getTetheringLooper();
+ public abstract Looper makeTetheringLooper();
/**
* Get Context of TetheringService.
@@ -166,26 +166,26 @@
}
/**
- * Get a reference to PrivateAddressCoordinator to be used by Tethering.
+ * Make PrivateAddressCoordinator to be used by Tethering.
*/
- public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx,
+ public PrivateAddressCoordinator makePrivateAddressCoordinator(Context ctx,
TetheringConfiguration cfg) {
return new PrivateAddressCoordinator(ctx, cfg);
}
/**
- * Get BluetoothPanShim object to enable/disable bluetooth tethering.
+ * Make BluetoothPanShim object to enable/disable bluetooth tethering.
*
* TODO: use BluetoothPan directly when mainline module is built with API 32.
*/
- public BluetoothPanShim getBluetoothPanShim(BluetoothPan pan) {
+ public BluetoothPanShim makeBluetoothPanShim(BluetoothPan pan) {
return BluetoothPanShimImpl.newInstance(pan);
}
/**
- * Get a reference to the TetheringMetrics to be used by tethering.
+ * Make the TetheringMetrics to be used by tethering.
*/
- public TetheringMetrics getTetheringMetrics() {
+ public TetheringMetrics makeTetheringMetrics() {
return new TetheringMetrics();
}
@@ -193,7 +193,7 @@
* Returns the implementation of WearableConnectionManager.
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
- public WearableConnectionManager getWearableConnectionManager(Context ctx) {
+ public WearableConnectionManager makeWearableConnectionManager(Context ctx) {
return new WearableConnectionManager(ctx);
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 96ddfa0..aa73819 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -322,7 +322,7 @@
public TetheringDependencies makeTetheringDependencies() {
return new TetheringDependencies() {
@Override
- public Looper getTetheringLooper() {
+ public Looper makeTetheringLooper() {
final HandlerThread tetherThread = new HandlerThread("android.tethering");
tetherThread.start();
return tetherThread.getLooper();
@@ -334,7 +334,7 @@
}
@Override
- public IpServer.Dependencies getIpServerDependencies() {
+ public IpServer.Dependencies makeIpServerDependencies() {
return new IpServer.Dependencies() {
@Override
public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 6ebd6ae..2298a1a 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -30,6 +30,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
@@ -104,6 +105,7 @@
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr);
when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
+ when(mConfig.isRandomPrefixBaseEnabled()).thenReturn(false);
setUpIpServers();
mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
}
@@ -572,4 +574,41 @@
assertEquals("Wrong local hotspot prefix: ", new LinkAddress("192.168.134.5/24"),
localHotspotAddress);
}
+
+ @Test
+ public void testStartedPrefixRange() throws Exception {
+ when(mConfig.isRandomPrefixBaseEnabled()).thenReturn(true);
+
+ startedPrefixBaseTest("192.168.0.0/16", 0);
+
+ startedPrefixBaseTest("192.168.0.0/16", 1);
+
+ startedPrefixBaseTest("192.168.0.0/16", 0xffff);
+
+ startedPrefixBaseTest("172.16.0.0/12", 0x10000);
+
+ startedPrefixBaseTest("172.16.0.0/12", 0x11111);
+
+ startedPrefixBaseTest("172.16.0.0/12", 0xfffff);
+
+ startedPrefixBaseTest("10.0.0.0/8", 0x100000);
+
+ startedPrefixBaseTest("10.0.0.0/8", 0x1fffff);
+
+ startedPrefixBaseTest("10.0.0.0/8", 0xffffff);
+
+ startedPrefixBaseTest("192.168.0.0/16", 0x1000000);
+ }
+
+ private void startedPrefixBaseTest(final String expected, final int randomIntForPrefixBase)
+ throws Exception {
+ mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
+ when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomIntForPrefixBase);
+ final LinkAddress address = requestDownstreamAddress(mHotspotIpServer,
+ CONNECTIVITY_SCOPE_GLOBAL, false /* useLastAddress */);
+ final IpPrefix prefixBase = new IpPrefix(expected);
+ assertTrue(address + " is not part of " + prefixBase,
+ prefixBase.containsPrefix(asIpPrefix(address)));
+
+ }
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 5877fc5..82b8845 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -436,51 +436,51 @@
ArrayList<IpServer> mAllDownstreams;
@Override
- public BpfCoordinator getBpfCoordinator(
+ public BpfCoordinator makeBpfCoordinator(
BpfCoordinator.Dependencies deps) {
return mBpfCoordinator;
}
@Override
- public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
+ public OffloadHardwareInterface makeOffloadHardwareInterface(Handler h, SharedLog log) {
return mOffloadHardwareInterface;
}
@Override
- public OffloadController getOffloadController(Handler h, SharedLog log,
+ public OffloadController makeOffloadController(Handler h, SharedLog log,
OffloadController.Dependencies deps) {
- mOffloadCtrl = spy(super.getOffloadController(h, log, deps));
+ mOffloadCtrl = spy(super.makeOffloadController(h, log, deps));
// Return real object here instead of mock because
// testReportFailCallbackIfOffloadNotSupported depend on real OffloadController object.
return mOffloadCtrl;
}
@Override
- public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, Handler h,
+ public UpstreamNetworkMonitor makeUpstreamNetworkMonitor(Context ctx, Handler h,
SharedLog log, UpstreamNetworkMonitor.EventListener listener) {
// Use a real object instead of a mock so that some tests can use a real UNM and some
// can use a mock.
mEventListener = listener;
- mUpstreamNetworkMonitor = spy(super.getUpstreamNetworkMonitor(ctx, h, log, listener));
+ mUpstreamNetworkMonitor = spy(super.makeUpstreamNetworkMonitor(ctx, h, log, listener));
return mUpstreamNetworkMonitor;
}
@Override
- public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
+ public IPv6TetheringCoordinator makeIPv6TetheringCoordinator(
ArrayList<IpServer> notifyList, SharedLog log) {
mAllDownstreams = notifyList;
return mIPv6TetheringCoordinator;
}
@Override
- public IpServer.Dependencies getIpServerDependencies() {
+ public IpServer.Dependencies makeIpServerDependencies() {
return mIpServerDependencies;
}
@Override
- public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
+ public EntitlementManager makeEntitlementManager(Context ctx, Handler h, SharedLog log,
Runnable callback) {
- mEntitleMgr = spy(super.getEntitlementManager(ctx, h, log, callback));
+ mEntitleMgr = spy(super.makeEntitlementManager(ctx, h, log, callback));
return mEntitleMgr;
}
@@ -503,7 +503,7 @@
}
@Override
- public Looper getTetheringLooper() {
+ public Looper makeTetheringLooper() {
return mLooper.getLooper();
}
@@ -518,7 +518,7 @@
}
@Override
- public TetheringNotificationUpdater getNotificationUpdater(Context ctx, Looper looper) {
+ public TetheringNotificationUpdater makeNotificationUpdater(Context ctx, Looper looper) {
return mNotificationUpdater;
}
@@ -528,19 +528,19 @@
}
@Override
- public TetheringMetrics getTetheringMetrics() {
+ public TetheringMetrics makeTetheringMetrics() {
return mTetheringMetrics;
}
@Override
- public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx,
+ public PrivateAddressCoordinator makePrivateAddressCoordinator(Context ctx,
TetheringConfiguration cfg) {
- mPrivateAddressCoordinator = super.getPrivateAddressCoordinator(ctx, cfg);
+ mPrivateAddressCoordinator = super.makePrivateAddressCoordinator(ctx, cfg);
return mPrivateAddressCoordinator;
}
@Override
- public BluetoothPanShim getBluetoothPanShim(BluetoothPan pan) {
+ public BluetoothPanShim makeBluetoothPanShim(BluetoothPan pan) {
try {
when(mBluetoothPanShim.requestTetheredInterface(
any(), any())).thenReturn(mTetheredInterfaceRequestShim);
diff --git a/framework/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp
index ca297e5..5403be7 100644
--- a/framework/jni/android_net_NetworkUtils.cpp
+++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -26,6 +26,7 @@
#include <bpf/BpfClassic.h>
#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
#include <nativehelper/JNIPlatformHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
#include <utils/Log.h>
#include "jni.h"
@@ -240,6 +241,15 @@
trw.rcv_wnd, trw.rcv_wup, tcpinfo.tcpi_rcv_wscale);
}
+static void android_net_utils_setsockoptBytes(JNIEnv *env, jclass clazz, jobject javaFd,
+ jint level, jint option, jbyteArray javaBytes) {
+ int sock = AFileDescriptor_getFd(env, javaFd);
+ ScopedByteArrayRO value(env, javaBytes);
+ if (setsockopt(sock, level, option, value.get(), value.size()) != 0) {
+ jniThrowErrnoException(env, "setsockoptBytes", errno);
+ }
+}
+
// ----------------------------------------------------------------------------
/*
@@ -260,6 +270,8 @@
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
{ "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
+ { "setsockoptBytes", "(Ljava/io/FileDescriptor;II[B)V",
+ (void*) android_net_utils_setsockoptBytes},
};
// clang-format on
diff --git a/framework/src/android/net/NetworkUtils.java b/framework/src/android/net/NetworkUtils.java
index 2679b62..fbdc024 100644
--- a/framework/src/android/net/NetworkUtils.java
+++ b/framework/src/android/net/NetworkUtils.java
@@ -426,4 +426,16 @@
return routedIPCount;
}
+ /**
+ * Sets a socket option with byte array
+ *
+ * @param fd The socket file descriptor
+ * @param level The level at which the option is defined
+ * @param option The socket option for which the value is to be set
+ * @param value The option value to be set in byte array
+ * @throws ErrnoException if setsockopt fails
+ */
+ public static native void setsockoptBytes(FileDescriptor fd, int level, int option,
+ byte[] value) throws ErrnoException;
+
}
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 2a9892f..a00c363 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -53,14 +53,10 @@
bpf_attach_type type) {
unique_fd cgroupProg(retrieveProgram(programPath));
if (!cgroupProg.ok()) {
- const int err = errno;
- ALOGE("Failed to get program from %s: %s", programPath, strerror(err));
- return statusFromErrno(err, "cgroup program get failed");
+ return statusFromErrno(errno, fmt::format("Failed to get program from {}", programPath));
}
if (android::bpf::attachProgram(type, cgroupProg, cgroupFd)) {
- const int err = errno;
- ALOGE("Program from %s attach failed: %s", programPath, strerror(err));
- return statusFromErrno(err, "program attach failed");
+ return statusFromErrno(errno, fmt::format("Program {} attach failed", programPath));
}
return netdutils::status::ok;
}
@@ -68,50 +64,38 @@
static Status checkProgramAccessible(const char* programPath) {
unique_fd prog(retrieveProgram(programPath));
if (!prog.ok()) {
- const int err = errno;
- ALOGE("Failed to get program from %s: %s", programPath, strerror(err));
- return statusFromErrno(err, "program retrieve failed");
+ return statusFromErrno(errno, fmt::format("Failed to get program from {}", programPath));
}
return netdutils::status::ok;
}
static Status initPrograms(const char* cg2_path) {
- if (!cg2_path) {
- ALOGE("cg2_path is NULL");
- return statusFromErrno(EINVAL, "cg2_path is NULL");
- }
+ if (!cg2_path) return Status("cg2_path is NULL");
// This code was mainlined in T, so this should be trivially satisfied.
- if (!modules::sdklevel::IsAtLeastT()) {
- ALOGE("S- platform is unsupported");
- abort();
- }
+ if (!modules::sdklevel::IsAtLeastT()) return Status("S- platform is unsupported");
// S requires eBPF support which was only added in 4.9, so this should be satisfied.
if (!bpf::isAtLeastKernelVersion(4, 9, 0)) {
- ALOGE("kernel version < 4.9.0 is unsupported");
- abort();
+ return Status("kernel version < 4.9.0 is unsupported");
}
// U bumps the kernel requirement up to 4.14
if (modules::sdklevel::IsAtLeastU() && !bpf::isAtLeastKernelVersion(4, 14, 0)) {
- ALOGE("U+ platform with kernel version < 4.14.0 is unsupported");
- abort();
+ return Status("U+ platform with kernel version < 4.14.0 is unsupported");
}
if (modules::sdklevel::IsAtLeastV()) {
// V bumps the kernel requirement up to 4.19
// see also: //system/netd/tests/kernel_test.cpp TestKernel419
if (!bpf::isAtLeastKernelVersion(4, 19, 0)) {
- ALOGE("V+ platform with kernel version < 4.19.0 is unsupported");
- abort();
+ return Status("V+ platform with kernel version < 4.19.0 is unsupported");
}
// Technically already required by U, but only enforce on V+
// see also: //system/netd/tests/kernel_test.cpp TestKernel64Bit
if (bpf::isKernel32Bit() && bpf::isAtLeastKernelVersion(5, 16, 0)) {
- ALOGE("V+ platform with 32 bit kernel, version >= 5.16.0 is unsupported");
- abort();
+ return Status("V+ platform with 32 bit kernel, version >= 5.16.0 is unsupported");
}
}
@@ -123,14 +107,12 @@
// problems are AFAIK limited to various CAP_NET_ADMIN protected interfaces.
// see also: //system/bpf/bpfloader/BpfLoader.cpp main()
if (bpf::isUserspace32bit() && bpf::isAtLeastKernelVersion(6, 2, 0)) {
- ALOGE("32 bit userspace with Kernel version >= 6.2.0 is unsupported");
- abort();
+ return Status("32 bit userspace with Kernel version >= 6.2.0 is unsupported");
}
// U mandates this mount point (though it should also be the case on T)
if (modules::sdklevel::IsAtLeastU() && !!strcmp(cg2_path, "/sys/fs/cgroup")) {
- ALOGE("U+ platform with cg2_path != /sys/fs/cgroup is unsupported");
- abort();
+ return Status("U+ platform with cg2_path != /sys/fs/cgroup is unsupported");
}
unique_fd cg_fd(open(cg2_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
diff --git a/netd/NetdUpdatable.cpp b/netd/NetdUpdatable.cpp
index 41b1fdb..8b9e5a7 100644
--- a/netd/NetdUpdatable.cpp
+++ b/netd/NetdUpdatable.cpp
@@ -31,7 +31,7 @@
android::netdutils::Status ret = sBpfHandler.init(cg2_path);
if (!android::netdutils::isOk(ret)) {
- LOG(ERROR) << __func__ << ": BPF handler init failed";
+ LOG(ERROR) << __func__ << ": Failed. " << ret.code() << " " << ret.msg();
return -ret.code();
}
return 0;
diff --git a/staticlibs/netd/libnetdutils/include/netdutils/Status.h b/staticlibs/netd/libnetdutils/include/netdutils/Status.h
index 7b0bd47..34f3bb2 100644
--- a/staticlibs/netd/libnetdutils/include/netdutils/Status.h
+++ b/staticlibs/netd/libnetdutils/include/netdutils/Status.h
@@ -41,6 +41,9 @@
// Constructs an error Status, |code| must be non-zero.
Status(int code, std::string msg) : mCode(code), mMsg(std::move(msg)) { assert(!ok()); }
+ // Constructs an error Status with message. Error |code| is unspecified.
+ explicit Status(std::string msg) : Status(std::numeric_limits<int>::max(), std::move(msg)) {}
+
Status(android::base::Result<void> result)
: mCode(result.ok() ? 0 : static_cast<int>(result.error().code())),
mMsg(result.ok() ? "" : result.error().message()) {}
diff --git a/tests/unit/java/android/net/NetworkUtilsTest.java b/tests/unit/java/android/net/NetworkUtilsTest.java
index a28245d..5d789b4 100644
--- a/tests/unit/java/android/net/NetworkUtilsTest.java
+++ b/tests/unit/java/android/net/NetworkUtilsTest.java
@@ -16,19 +16,32 @@
package android.net;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_RCVTIMEO;
import static junit.framework.Assert.assertEquals;
import android.os.Build;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructTimeval;
import androidx.test.filters.SmallTest;
+import com.android.net.module.util.SocketUtils;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.TreeSet;
@RunWith(DevSdkIgnoreRunner.class)
@@ -131,4 +144,27 @@
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
+
+ private byte[] getTimevalBytes(StructTimeval tv) {
+ byte[] timeval = new byte[16];
+ ByteBuffer buf = ByteBuffer.wrap(timeval);
+ buf.order(ByteOrder.nativeOrder());
+ buf.putLong(tv.tv_sec);
+ buf.putLong(tv.tv_usec);
+ return timeval;
+ }
+
+ @Test
+ public void testSetSockOptBytes() throws ErrnoException {
+ final FileDescriptor sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+ final StructTimeval writeTimeval = StructTimeval.fromMillis(1200);
+ byte[] timeval = getTimevalBytes(writeTimeval);
+ final StructTimeval readTimeval;
+
+ NetworkUtils.setsockoptBytes(sock, SOL_SOCKET, SO_RCVTIMEO, timeval);
+ readTimeval = Os.getsockoptTimeval(sock, SOL_SOCKET, SO_RCVTIMEO);
+
+ assertEquals(writeTimeval, readTimeval);
+ SocketUtils.closeSocketQuietly(sock);
+ }
}