Merge "[Thread] tell ot-daemon about the DNS servers on the infra link" into main
diff --git a/TEST_MAPPING b/TEST_MAPPING
index b773ed8..c1bc31e 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -424,6 +424,11 @@
]
}
],
+ "automotive-mumd-presubmit": [
+ {
+ "name": "CtsNetTestCases"
+ }
+ ],
"imports": [
{
"path": "frameworks/base/core/java/android/net"
diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt
index 460c216..a680590 100644
--- a/Tethering/common/TetheringLib/api/module-lib-current.txt
+++ b/Tethering/common/TetheringLib/api/module-lib-current.txt
@@ -46,5 +46,10 @@
method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
}
+ public static final class TetheringManager.TetheringRequest implements android.os.Parcelable {
+ method @FlaggedApi("com.android.net.flags.tethering_request_with_soft_ap_config") @Nullable public String getPackageName();
+ method @FlaggedApi("com.android.net.flags.tethering_request_with_soft_ap_config") public int getUid();
+ }
+
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 411971d..7c7a4e0 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -33,6 +33,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.ArrayMap;
@@ -746,6 +747,7 @@
mBuilderParcel.exemptFromEntitlementCheck = false;
mBuilderParcel.showProvisioningUi = true;
mBuilderParcel.connectivityScope = getDefaultConnectivityScope(type);
+ mBuilderParcel.uid = Process.INVALID_UID;
mBuilderParcel.softApConfig = null;
}
@@ -920,6 +922,47 @@
}
/**
+ * Sets the UID of the app that sent this request. This should always be overridden when
+ * receiving TetheringRequest from an external source.
+ * @hide
+ */
+ public void setUid(int uid) {
+ mRequestParcel.uid = uid;
+ }
+
+ /**
+ * Sets the package name of the app that sent this request. This should always be overridden
+ * when receiving a TetheringRequest from an external source.
+ * @hide
+ */
+ public void setPackageName(String packageName) {
+ mRequestParcel.packageName = packageName;
+ }
+
+ /**
+ * Gets the UID of the app that sent this request. This defaults to
+ * {@link Process#INVALID_UID} if unset.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_TETHERING_REQUEST_WITH_SOFT_AP_CONFIG)
+ @SystemApi(client = MODULE_LIBRARIES)
+ public int getUid() {
+ return mRequestParcel.uid;
+ }
+
+ /**
+ * Gets the package name of the app that sent this request. This defaults to {@code null} if
+ * unset.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_TETHERING_REQUEST_WITH_SOFT_AP_CONFIG)
+ @SystemApi(client = MODULE_LIBRARIES)
+ @Nullable
+ public String getPackageName() {
+ return mRequestParcel.packageName;
+ }
+
+ /**
* Get a TetheringRequestParcel from the configuration
* @hide
*/
@@ -935,6 +978,8 @@
+ ", exemptFromEntitlementCheck= " + mRequestParcel.exemptFromEntitlementCheck
+ ", showProvisioningUi= " + mRequestParcel.showProvisioningUi
+ ", softApConfig= " + mRequestParcel.softApConfig
+ + ", uid= " + mRequestParcel.uid
+ + ", packageName= " + mRequestParcel.packageName
+ " ]";
}
@@ -950,7 +995,9 @@
&& parcel.exemptFromEntitlementCheck == otherParcel.exemptFromEntitlementCheck
&& parcel.showProvisioningUi == otherParcel.showProvisioningUi
&& parcel.connectivityScope == otherParcel.connectivityScope
- && Objects.equals(parcel.softApConfig, otherParcel.softApConfig);
+ && Objects.equals(parcel.softApConfig, otherParcel.softApConfig)
+ && parcel.uid == otherParcel.uid
+ && Objects.equals(parcel.packageName, otherParcel.packageName);
}
@Override
@@ -958,7 +1005,8 @@
TetheringRequestParcel parcel = getParcel();
return Objects.hash(parcel.tetheringType, parcel.localIPv4Address,
parcel.staticClientAddress, parcel.exemptFromEntitlementCheck,
- parcel.showProvisioningUi, parcel.connectivityScope, parcel.softApConfig);
+ parcel.showProvisioningUi, parcel.connectivityScope, parcel.softApConfig,
+ parcel.uid, parcel.packageName);
}
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
index ea7a353..789d5bb 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -31,4 +31,6 @@
boolean showProvisioningUi;
int connectivityScope;
SoftApConfiguration softApConfig;
+ int uid;
+ String packageName;
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 454cbf1..cea7e82 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -55,6 +55,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.PermissionUtils;
import com.android.networkstack.apishim.SettingsShimImpl;
import com.android.networkstack.apishim.common.SettingsShim;
@@ -138,8 +139,10 @@
listener)) {
return;
}
- // TODO(b/216524590): Add UID/packageName of caller to TetheringRequest here
- mTethering.startTethering(new TetheringRequest(request), callerPkg, listener);
+ TetheringRequest external = new TetheringRequest(request);
+ external.setUid(getBinderCallingUid());
+ external.setPackageName(callerPkg);
+ mTethering.startTethering(external, callerPkg, listener);
}
@Override
@@ -238,6 +241,12 @@
final String callingAttributionTag, final boolean onlyAllowPrivileged,
final IIntResultListener listener) {
try {
+ if (!checkPackageNameMatchesUid(getBinderCallingUid(), callerPkg)) {
+ Log.e(TAG, "Package name " + callerPkg + " does not match UID "
+ + getBinderCallingUid());
+ listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ return true;
+ }
if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
onlyAllowPrivileged)) {
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
@@ -256,6 +265,12 @@
private boolean checkAndNotifyCommonError(final String callerPkg,
final String callingAttributionTag, final ResultReceiver receiver) {
+ if (!checkPackageNameMatchesUid(getBinderCallingUid(), callerPkg)) {
+ Log.e(TAG, "Package name " + callerPkg + " does not match UID "
+ + getBinderCallingUid());
+ receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
+ return true;
+ }
if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
false /* onlyAllowPrivileged */)) {
receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
@@ -290,9 +305,9 @@
if (mTethering.isTetherProvisioningRequired()) return false;
- int uid = Binder.getCallingUid();
+ int uid = getBinderCallingUid();
- // If callerPkg's uid is not same as Binder.getCallingUid(),
+ // If callerPkg's uid is not same as getBinderCallingUid(),
// checkAndNoteWriteSettingsOperation will return false and the operation will be
// denied.
return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
@@ -305,6 +320,14 @@
return mService.checkCallingOrSelfPermission(
ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
}
+
+ private int getBinderCallingUid() {
+ return mService.getBinderCallingUid();
+ }
+
+ private boolean checkPackageNameMatchesUid(final int uid, final String callerPkg) {
+ return mService.checkPackageNameMatchesUid(mService, uid, callerPkg);
+ }
}
/**
@@ -322,6 +345,28 @@
}
/**
+ * Check if the package name matches the uid.
+ */
+ @VisibleForTesting
+ boolean checkPackageNameMatchesUid(@NonNull Context context, int uid,
+ @NonNull String callingPackage) {
+ try {
+ PermissionUtils.enforcePackageNameMatchesUid(context, uid, callingPackage);
+ } catch (SecurityException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Wrapper for the Binder calling UID, used for mocks.
+ */
+ @VisibleForTesting
+ int getBinderCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ /**
* An injection method for testing.
*/
@VisibleForTesting
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
index 3c07580..7fcc5f1 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
@@ -32,6 +32,8 @@
public class MockTetheringService extends TetheringService {
private final Tethering mTethering = mock(Tethering.class);
private final ArrayMap<String, Integer> mMockedPermissions = new ArrayMap<>();
+ private final ArrayMap<String, Integer> mMockedPackageUids = new ArrayMap<>();
+ private int mMockCallingUid;
@Override
public IBinder onBind(Intent intent) {
@@ -61,6 +63,17 @@
return super.checkCallingOrSelfPermission(permission);
}
+ @Override
+ boolean checkPackageNameMatchesUid(@NonNull Context context, int uid,
+ @NonNull String callingPackage) {
+ return mMockedPackageUids.getOrDefault(callingPackage, 0) == uid;
+ }
+
+ @Override
+ int getBinderCallingUid() {
+ return mMockCallingUid;
+ }
+
public Tethering getTethering() {
return mTethering;
}
@@ -91,5 +104,19 @@
mMockedPermissions.put(permission, granted);
}
}
+
+ /**
+ * Mock a package name matching a uid.
+ */
+ public void setPackageNameUid(String packageName, int uid) {
+ mMockedPackageUids.put(packageName, uid);
+ }
+
+ /**
+ * Mock a package name matching a uid.
+ */
+ public void setCallingUid(int uid) {
+ mMockCallingUid = uid;
+ }
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index c0d7ad4..1988311 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -79,6 +80,7 @@
public final class TetheringServiceTest {
private static final String TEST_IFACE_NAME = "test_wlan0";
private static final String TEST_CALLER_PKG = "com.android.shell";
+ private static final int TEST_CALLER_UID = 1234;
private static final String TEST_ATTRIBUTION_TAG = null;
@Mock private ITetheringEventCallback mITetheringEventCallback;
@Rule public ServiceTestRule mServiceTestRule;
@@ -128,6 +130,8 @@
mTetheringConnector = ITetheringConnector.Stub.asInterface(mMockConnector.getIBinder());
final MockTetheringService service = mMockConnector.getService();
mTethering = service.getTethering();
+ mMockConnector.setCallingUid(TEST_CALLER_UID);
+ mMockConnector.setPackageNameUid(TEST_CALLER_PKG, TEST_CALLER_UID);
}
@After
@@ -330,6 +334,16 @@
});
runAsTetherPrivileged((result) -> {
+ String wrongPackage = "wrong.package";
+ mTetheringConnector.startTethering(request, wrongPackage,
+ TEST_ATTRIBUTION_TAG, result);
+ verify(mTethering, never()).startTethering(
+ eq(new TetheringRequest(request)), eq(wrongPackage), eq(result));
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ verifyNoMoreInteractionsForTethering();
+ });
+
+ runAsTetherPrivileged((result) -> {
runStartTethering(result, request);
verifyNoMoreInteractionsForTethering();
});
@@ -445,6 +459,13 @@
verifyNoMoreInteractionsForTethering();
});
+ runAsTetherPrivileged((none) -> {
+ mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
+ true /* showEntitlementUi */, "wrong.package", TEST_ATTRIBUTION_TAG);
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ verifyNoMoreInteractions(mTethering);
+ });
+
runAsWriteSettings((none) -> {
runRequestLatestTetheringEntitlementResult();
verify(mTethering).isTetherProvisioningRequired();
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index 4f01599..a43486e 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -59,6 +59,7 @@
public class MdnsServiceTypeClient {
private static final String TAG = MdnsServiceTypeClient.class.getSimpleName();
+ private static final boolean DBG = MdnsDiscoveryManager.DBG;
@VisibleForTesting
static final int EVENT_START_QUERYTASK = 1;
static final int EVENT_QUERY_RESULT = 2;
@@ -184,10 +185,14 @@
searchOptions.numOfQueriesBeforeBackoff(),
false /* forceEnableBackoff */
);
+ final long timeToNextTaskMs = calculateTimeToNextTask(args, now);
+ sharedLog.log(String.format("Query sent with transactionId: %d. "
+ + "Next run: sessionId: %d, in %d ms",
+ sentResult.transactionId, args.sessionId, timeToNextTaskMs));
dependencies.sendMessageDelayed(
handler,
handler.obtainMessage(EVENT_START_QUERYTASK, args),
- calculateTimeToNextTask(args, now, sharedLog));
+ timeToNextTaskMs);
break;
}
default:
@@ -369,10 +374,13 @@
searchOptions.numOfQueriesBeforeBackoff(),
forceEnableBackoff
);
+ final long timeToNextTaskMs = calculateTimeToNextTask(args, now);
+ sharedLog.log(String.format("Schedule a query. Next run: sessionId: %d, in %d ms",
+ args.sessionId, timeToNextTaskMs));
dependencies.sendMessageDelayed(
handler,
handler.obtainMessage(EVENT_START_QUERYTASK, args),
- calculateTimeToNextTask(args, now, sharedLog));
+ timeToNextTaskMs);
} else {
final List<MdnsResponse> servicesToResolve = makeResponsesForResolve(socketKey);
final QueryTask queryTask = new QueryTask(
@@ -492,6 +500,10 @@
// If the response is not modified and already in the cache. The cache will
// need to be updated to refresh the last receipt time.
serviceCache.addOrUpdateService(cacheKey, response);
+ if (DBG) {
+ sharedLog.v("Update the last receipt time for service:"
+ + serviceInstanceName);
+ }
}
}
if (dependencies.hasMessages(handler, EVENT_START_QUERYTASK)) {
@@ -503,10 +515,13 @@
searchOptions.numOfQueriesBeforeBackoff());
if (args != null) {
removeScheduledTask();
+ final long timeToNextTaskMs = calculateTimeToNextTask(args, now);
+ sharedLog.log(String.format("Reschedule a query. Next run: sessionId: %d, in %d ms",
+ args.sessionId, timeToNextTaskMs));
dependencies.sendMessageDelayed(
handler,
handler.obtainMessage(EVENT_START_QUERYTASK, args),
- calculateTimeToNextTask(args, now, sharedLog));
+ timeToNextTaskMs);
}
}
}
@@ -757,11 +772,8 @@
}
private static long calculateTimeToNextTask(MdnsQueryScheduler.ScheduledQueryTaskArgs args,
- long now, SharedLog sharedLog) {
- long timeToNextTasksWithBackoffInMs = Math.max(args.timeToRun - now, 0);
- sharedLog.log(String.format("Next run: sessionId: %d, in %d ms",
- args.sessionId, timeToNextTasksWithBackoffInMs));
- return timeToNextTasksWithBackoffInMs;
+ long now) {
+ return Math.max(args.timeToRun - now, 0);
}
/**
diff --git a/service/Android.bp b/service/Android.bp
index e6caf9d..567c079 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -311,7 +311,7 @@
apex_available: ["com.android.tethering"],
}
-genrule {
+java_genrule {
name: "connectivity-jarjar-rules",
defaults: ["jarjar-rules-combine-defaults"],
srcs: [
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index 66e1dad..a825b87 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -626,6 +626,31 @@
visibility: ["//visibility:private"],
}
+// Filegroup to build lib used by IPsec/IKE framework
+// Any class here *must* have a corresponding jarjar rule in the IPsec build rules.
+filegroup {
+ name: "net-utils-framework-ipsec-common-srcs",
+ srcs: [
+ "framework/com/android/net/module/util/HexDump.java",
+ ],
+ path: "framework",
+ visibility: ["//visibility:private"],
+}
+
+java_library {
+ name: "net-utils-framework-ipsec",
+ sdk_version: "module_current",
+ min_sdk_version: "30",
+ srcs: [":net-utils-framework-ipsec-common-srcs"],
+ libs: [
+ "androidx.annotation_annotation",
+ ],
+ visibility: [
+ "//packages/modules/IPsec",
+ ],
+ apex_available: ["com.android.ipsec"],
+}
+
// Use a file group containing classes necessary for framework-connectivity. The file group should
// be as small as possible because because the classes end up in the bootclasspath and R8 is not
// used to remove unused classes.
diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp
index 13e1dc0..f4ed9e4 100644
--- a/staticlibs/testutils/Android.bp
+++ b/staticlibs/testutils/Android.bp
@@ -103,7 +103,7 @@
"mcts-wifi",
"mcts-dnsresolver",
],
- data: [":ConnectivityTestPreparer"],
+ device_common_data: [":ConnectivityTestPreparer"],
}
python_library_host {
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt
index 68248ca..785e55a 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceConfigRule.kt
@@ -89,6 +89,7 @@
} cleanupStep {
runAsShell(WRITE_DEVICE_CONFIG) {
originalConfig.forEach { (key, value) ->
+ Log.i(TAG, "Resetting config \"${key.second}\" to \"$value\"")
DeviceConfig.setProperty(
key.first, key.second, value, false /* makeDefault */)
}
diff --git a/staticlibs/testutils/host/python/apf_utils.py b/staticlibs/testutils/host/python/apf_utils.py
index 7fe60bd..55ac860 100644
--- a/staticlibs/testutils/host/python/apf_utils.py
+++ b/staticlibs/testutils/host/python/apf_utils.py
@@ -182,22 +182,23 @@
ad: android_device.AndroidDevice,
) -> bool:
- # Invoke the shell command with empty argument and see how NetworkStack respond.
- # If supported, an IllegalArgumentException with help page will be printed.
- functions_with_args = (
- # list all functions and args with (func, *args) tuple
- (start_capture_packets, (ad, "")),
- (stop_capture_packets, (ad, "")),
- (get_matched_packet_counts, (ad, "", ""))
- )
-
- for func, args in functions_with_args:
- try:
- func(*args)
- except UnsupportedOperationException:
- return False
- except Exception:
- continue
+ try:
+ # Invoke the shell command with empty argument and see how NetworkStack respond.
+ # If supported, an IllegalArgumentException with help page will be printed.
+ assert_utils.expect_throws(
+ lambda: start_capture_packets(ad, ""),
+ assert_utils.UnexpectedBehaviorError
+ )
+ assert_utils.expect_throws(
+ lambda: stop_capture_packets(ad, ""),
+ assert_utils.UnexpectedBehaviorError
+ )
+ assert_utils.expect_throws(
+ lambda: get_matched_packet_counts(ad, "", ""),
+ assert_utils.UnexpectedBehaviorError
+ )
+ except assert_utils.UnexpectedExceptionError:
+ return False
# If no UnsupportOperationException is thrown, regard it as supported
return True
diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt
index 1883387..d1d5649 100644
--- a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt
+++ b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt
@@ -20,11 +20,13 @@
import com.android.testutils.FunctionalUtils.ThrowingRunnable
import java.lang.reflect.Modifier
+import java.util.function.BooleanSupplier
import kotlin.system.measureTimeMillis
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
+import kotlin.test.fail
private const val TAG = "Connectivity unit test"
@@ -118,4 +120,25 @@
val actualSet: HashSet<T> = HashSet(actual)
assertEquals(actualSet.size, actual.size, "actual list contains duplicates")
assertEquals(expectedSet, actualSet)
+}
+
+@JvmOverloads
+fun assertEventuallyTrue(
+ descr: String,
+ timeoutMs: Long,
+ pollIntervalMs: Long = 10L,
+ fn: BooleanSupplier
+) {
+ // This should use SystemClock.elapsedRealtime() since nanoTime does not include time in deep
+ // sleep, but this is a host-device library and SystemClock is Android-specific (not available
+ // on host). When waiting for a condition during tests the device would generally not go into
+ // deep sleep, and the polling sleep would go over the timeout anyway in that case, so this is
+ // fine.
+ val limit = System.nanoTime() + timeoutMs * 1000
+ while (!fn.asBoolean) {
+ if (System.nanoTime() > limit) {
+ fail(descr)
+ }
+ Thread.sleep(pollIntervalMs)
+ }
}
\ No newline at end of file
diff --git a/tests/common/Android.bp b/tests/common/Android.bp
index 920492f..bb1009b 100644
--- a/tests/common/Android.bp
+++ b/tests/common/Android.bp
@@ -61,7 +61,7 @@
// Combine Connectivity, NetworkStack and Tethering jarjar rules for coverage target.
// The jarjar files are simply concatenated in the order specified in srcs.
// jarjar stops at the first matching rule, so order of concatenation affects the output.
-genrule {
+java_genrule {
name: "ConnectivityCoverageJarJarRules",
defaults: ["jarjar-rules-combine-defaults"],
srcs: [
diff --git a/tests/cts/hostside/Android.bp b/tests/cts/hostside/Android.bp
index 97be91a..0ac9ce1 100644
--- a/tests/cts/hostside/Android.bp
+++ b/tests/cts/hostside/Android.bp
@@ -56,7 +56,7 @@
"mts-tethering",
"sts",
],
- data: [
+ device_common_data: [
":CtsHostsideNetworkTestsApp",
":CtsHostsideNetworkTestsApp2",
":CtsHostsideNetworkCapTestsAppWithoutProperty",
diff --git a/tests/cts/multidevices/Android.bp b/tests/cts/multidevices/Android.bp
index 40aa1e4..949be85 100644
--- a/tests/cts/multidevices/Android.bp
+++ b/tests/cts/multidevices/Android.bp
@@ -37,7 +37,7 @@
test_options: {
unit_test: false,
},
- data: [
+ device_common_data: [
// Package the snippet with the mobly test
":connectivity_multi_devices_snippet",
],
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 0e9ea0c..3a8252a 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -113,6 +113,7 @@
import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
import static com.android.testutils.Cleanup.testAndCleanup;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+import static com.android.testutils.MiscAsserts.assertEventuallyTrue;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
import static com.android.testutils.TestPermissionUtil.runAsShell;
@@ -2934,12 +2935,7 @@
mCm.getActiveNetwork(), false /* accept */ , false /* always */));
}
- private void ensureCellIsValidatedBeforeMockingValidationUrls() {
- // Verify that current supported network is validated so that the mock http server will not
- // apply to unexpected networks. Also see aosp/2208680.
- //
- // This may also apply to wifi in principle, but in practice methods that mock validation
- // URL all disconnect wifi forcefully anyway, so don't wait for wifi to validate.
+ private void ensureCellIsValidated() {
if (mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
new ConnectUtil(mContext).ensureCellularValidated();
}
@@ -3022,9 +3018,13 @@
networkCallbackRule.requestCell();
final Network wifiNetwork = prepareUnvalidatedNetwork();
- // Default network should not be wifi ,but checking that wifi is not the default doesn't
- // guarantee that it won't become the default in the future.
- assertNotEquals(wifiNetwork, mCm.getActiveNetwork());
+ // Default network should not be wifi ,but checking that Wi-Fi is not the default
+ // doesn't guarantee that it won't become the default in the future.
+ // On U 24Q2+ telephony may teardown (unregisterAfterReplacement) its network when Wi-Fi
+ // is toggled (as part of prepareUnvalidatedNetwork here). Give some time for Wi-Fi to
+ // not be default in case telephony is reconnecting.
+ assertEventuallyTrue("Wifi remained default despite being unvalidated",
+ WIFI_CONNECT_TIMEOUT_MS, () -> !wifiNetwork.equals(mCm.getActiveNetwork()));
final TestableNetworkCallback wifiCb = networkCallbackRule.registerNetworkCallback(
makeWifiNetworkRequest());
@@ -3061,7 +3061,7 @@
try {
final Network cellNetwork = networkCallbackRule.requestCell();
- ensureCellIsValidatedBeforeMockingValidationUrls();
+ ensureCellIsValidated();
final Network wifiNetwork = prepareValidatedNetwork();
final TestableNetworkCallback defaultCb =
@@ -3157,7 +3157,12 @@
}
private Network prepareValidatedNetwork() throws Exception {
- ensureCellIsValidatedBeforeMockingValidationUrls();
+ // Verify that current supported network is validated so that the mock http server will not
+ // apply to unexpected networks. Also see aosp/2208680.
+ //
+ // This may also apply to wifi in principle, but in practice methods that mock validation
+ // URL all disconnect wifi forcefully anyway, so don't wait for wifi to validate.
+ ensureCellIsValidated();
prepareHttpServer();
configTestServer(Status.NO_CONTENT, Status.NO_CONTENT);
@@ -3169,7 +3174,7 @@
}
private Network preparePartialConnectivity() throws Exception {
- ensureCellIsValidatedBeforeMockingValidationUrls();
+ ensureCellIsValidated();
prepareHttpServer();
// Configure response code for partial connectivity
@@ -3184,7 +3189,7 @@
}
private Network prepareUnvalidatedNetwork() throws Exception {
- ensureCellIsValidatedBeforeMockingValidationUrls();
+ ensureCellIsValidated();
prepareHttpServer();
// Configure response code for unvalidated network
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
index 890c071..f2c6d33 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
@@ -1874,4 +1874,45 @@
},
false /* enableEncrypt */);
}
+
+ @IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ @Test
+ public void testMigrateWhenMultipleTunnelsExist() throws Exception {
+ assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
+ assumeTrue(mCtsNetUtils.hasIpsecTunnelMigrateFeature());
+
+ final int spi = getRandomSpi(LOCAL_OUTER_6, REMOTE_OUTER_6);
+
+ // Create tunnelIfaceFoo and tunnelIfaceBar. Verify tunnelIfaceBar migration will not throw
+ try (IpSecManager.IpSecTunnelInterface tunnelIfaceFoo =
+ mISM.createIpSecTunnelInterface(
+ LOCAL_OUTER_4, REMOTE_OUTER_4, sTunWrapper.network)) {
+
+ buildTunnelNetworkAndRunTestsSimple(
+ spi,
+ (ipsecNetwork,
+ tunnelIfaceBar,
+ tunUtils,
+ inTunnelTransform,
+ outTunnelTransform,
+ localOuter,
+ remoteOuter,
+ seqNum) -> {
+ tunnelIfaceBar.setUnderlyingNetwork(sTunWrapperNew.network);
+
+ mISM.startTunnelModeTransformMigration(
+ inTunnelTransform, REMOTE_OUTER_6_NEW, LOCAL_OUTER_6_NEW);
+ mISM.startTunnelModeTransformMigration(
+ outTunnelTransform, LOCAL_OUTER_6_NEW, REMOTE_OUTER_6_NEW);
+
+ mISM.applyTunnelModeTransform(
+ tunnelIfaceBar, IpSecManager.DIRECTION_IN, inTunnelTransform);
+ mISM.applyTunnelModeTransform(
+ tunnelIfaceBar, IpSecManager.DIRECTION_OUT, outTunnelTransform);
+
+ return 0 /* not used */;
+ },
+ true /* enableEncrypt */);
+ }
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
index 11fc6df..fef085d 100644
--- a/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/NetworkStatsManagerTest.java
@@ -41,6 +41,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.app.Instrumentation;
import android.app.usage.NetworkStats;
@@ -68,13 +69,16 @@
import android.util.Log;
import androidx.test.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
import com.android.modules.utils.build.SdkLevel;
+import com.android.testutils.AutoReleaseNetworkCallbackRule;
import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+import com.android.testutils.RecorderCallback.CallbackEntry;
+import com.android.testutils.TestableNetworkCallback;
import org.junit.After;
import org.junit.Before;
@@ -95,12 +99,18 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
-@ConnectivityModuleTest
+// TODO: Fix thread leaks in testCallback and annotating with @MonitorThreadLeak.
@AppModeFull(reason = "instant apps cannot be granted USAGE_STATS")
-@RunWith(AndroidJUnit4.class)
+@ConnectivityModuleTest
+@DevSdkIgnoreRunner.RestoreDefaultNetwork
+@RunWith(DevSdkIgnoreRunner.class)
public class NetworkStatsManagerTest {
- @Rule
+ @Rule(order = 1)
public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(Build.VERSION_CODES.Q);
+ @Rule(order = 2)
+ public final AutoReleaseNetworkCallbackRule
+ networkCallbackRule = new AutoReleaseNetworkCallbackRule();
+
private static final String LOG_TAG = "NetworkStatsManagerTest";
private static final String APPOPS_SET_SHELL_COMMAND = "appops set {0} {1} {2}";
@@ -119,12 +129,19 @@
private static final long LONG_TOLERANCE = MINUTE * 120;
private abstract class NetworkInterfaceToTest {
+
+ final TestableNetworkCallback mRequestNetworkCb = new TestableNetworkCallback();
private boolean mMetered;
private boolean mRoaming;
private boolean mIsDefault;
abstract int getNetworkType();
- abstract int getTransportType();
+
+ abstract Network requestNetwork();
+
+ void unrequestNetwork() {
+ networkCallbackRule.unregisterNetworkCallback(mRequestNetworkCb);
+ }
public boolean getMetered() {
return mMetered;
@@ -151,7 +168,13 @@
}
abstract String getSystemFeature();
- abstract String getErrorMessage();
+
+ @NonNull NetworkRequest buildRequestForTransport(int transport) {
+ return new NetworkRequest.Builder()
+ .addTransportType(transport)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ }
}
private final NetworkInterfaceToTest[] mNetworkInterfacesToTest =
@@ -163,19 +186,20 @@
}
@Override
- public int getTransportType() {
- return NetworkCapabilities.TRANSPORT_WIFI;
+ public Network requestNetwork() {
+ networkCallbackRule.requestNetwork(buildRequestForTransport(
+ NetworkCapabilities.TRANSPORT_WIFI),
+ mRequestNetworkCb, TIMEOUT_MILLIS);
+ return mRequestNetworkCb.expect(CallbackEntry.AVAILABLE,
+ "Wifi network not available. "
+ + "Please ensure the device has working wifi."
+ ).getNetwork();
}
@Override
public String getSystemFeature() {
return PackageManager.FEATURE_WIFI;
}
-
- @Override
- public String getErrorMessage() {
- return " Please make sure you are connected to a WiFi access point.";
- }
},
new NetworkInterfaceToTest() {
@Override
@@ -184,22 +208,20 @@
}
@Override
- public int getTransportType() {
- return NetworkCapabilities.TRANSPORT_CELLULAR;
+ public Network requestNetwork() {
+ networkCallbackRule.requestNetwork(buildRequestForTransport(
+ NetworkCapabilities.TRANSPORT_CELLULAR),
+ mRequestNetworkCb, TIMEOUT_MILLIS);
+ return mRequestNetworkCb.expect(CallbackEntry.AVAILABLE,
+ "Cell network not available. "
+ + "Please ensure the device has working mobile data."
+ ).getNetwork();
}
@Override
public String getSystemFeature() {
return PackageManager.FEATURE_TELEPHONY;
}
-
- @Override
- public String getErrorMessage() {
- return " Please make sure you have added a SIM card with data plan to"
- + " your phone, have enabled data over cellular and in case of"
- + " dual SIM devices, have selected the right SIM "
- + "for data connection.";
- }
}
};
@@ -215,7 +237,22 @@
private String mWriteSettingsMode;
private String mUsageStatsMode;
- private void exerciseRemoteHost(Network network, URL url) throws Exception {
+ // The test host only has IPv4. So on a dual-stack network where IPv6 connects before IPv4,
+ // we need to wait until IPv4 is available or the test will spuriously fail.
+ private static void waitForHostResolution(@NonNull Network network, @NonNull URL url) {
+ for (int i = 0; i < HOST_RESOLUTION_RETRIES; i++) {
+ try {
+ network.getAllByName(url.getHost());
+ return;
+ } catch (UnknownHostException e) {
+ SystemClock.sleep(HOST_RESOLUTION_INTERVAL_MS);
+ }
+ }
+ fail(String.format("%s could not be resolved on network %s (%d attempts %dms apart)",
+ url.getHost(), network, HOST_RESOLUTION_RETRIES, HOST_RESOLUTION_INTERVAL_MS));
+ }
+
+ private void exerciseRemoteHost(@NonNull Network network, @NonNull URL url) throws Exception {
NetworkInfo networkInfo = mCm.getNetworkInfo(network);
if (networkInfo == null) {
Log.w(LOG_TAG, "Network info is null");
@@ -311,97 +348,44 @@
return result.contains("FOREGROUND");
}
- private class NetworkCallback extends ConnectivityManager.NetworkCallback {
- private long mTolerance;
- private URL mUrl;
- public boolean success;
- public boolean metered;
- public boolean roaming;
- public boolean isDefault;
-
- NetworkCallback(long tolerance, URL url) {
- mTolerance = tolerance;
- mUrl = url;
- success = false;
- metered = false;
- roaming = false;
- isDefault = false;
- }
-
- // The test host only has IPv4. So on a dual-stack network where IPv6 connects before IPv4,
- // we need to wait until IPv4 is available or the test will spuriously fail.
- private void waitForHostResolution(Network network) {
- for (int i = 0; i < HOST_RESOLUTION_RETRIES; i++) {
- try {
- network.getAllByName(mUrl.getHost());
- return;
- } catch (UnknownHostException e) {
- SystemClock.sleep(HOST_RESOLUTION_INTERVAL_MS);
- }
- }
- fail(String.format("%s could not be resolved on network %s (%d attempts %dms apart)",
- mUrl.getHost(), network, HOST_RESOLUTION_RETRIES, HOST_RESOLUTION_INTERVAL_MS));
- }
-
- @Override
- public void onAvailable(Network network) {
- try {
- mStartTime = System.currentTimeMillis() - mTolerance;
- isDefault = network.equals(mCm.getActiveNetwork());
- waitForHostResolution(network);
- exerciseRemoteHost(network, mUrl);
- mEndTime = System.currentTimeMillis() + mTolerance;
- success = true;
- metered = !mCm.getNetworkCapabilities(network)
- .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- roaming = !mCm.getNetworkCapabilities(network)
- .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- synchronized (NetworkStatsManagerTest.this) {
- NetworkStatsManagerTest.this.notify();
- }
- } catch (Exception e) {
- Log.w(LOG_TAG, "exercising remote host failed.", e);
- success = false;
- }
- }
- }
-
private boolean shouldTestThisNetworkType(int networkTypeIndex) {
return mPm.hasSystemFeature(mNetworkInterfacesToTest[networkTypeIndex].getSystemFeature());
}
+ @NonNull
+ private Network requestNetworkAndSetAttributes(
+ @NonNull NetworkInterfaceToTest networkInterface) {
+ final Network network = networkInterface.requestNetwork();
+
+ // These attributes are needed when performing NetworkStats queries.
+ // Fetch caps from the first capabilities changed event since the
+ // interested attributes are not mutable, and not expected to be
+ // changed during the test.
+ final NetworkCapabilities caps = networkInterface.mRequestNetworkCb.expect(
+ CallbackEntry.NETWORK_CAPS_UPDATED, network).getCaps();
+ networkInterface.setMetered(!caps.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+ networkInterface.setRoaming(!caps.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING));
+ networkInterface.setIsDefault(network.equals(mCm.getActiveNetwork()));
+
+ return network;
+ }
+
private void requestNetworkAndGenerateTraffic(int networkTypeIndex, final long tolerance)
throws Exception {
final NetworkInterfaceToTest networkInterface = mNetworkInterfacesToTest[networkTypeIndex];
- final NetworkCallback callback = new NetworkCallback(tolerance,
- new URL(CHECK_CONNECTIVITY_URL));
- mCm.requestNetwork(new NetworkRequest.Builder()
- .addTransportType(networkInterface.getTransportType())
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build(), callback);
- synchronized (this) {
- long now = System.currentTimeMillis();
- final long deadline = (long) (now + TIMEOUT_MILLIS * 2.4);
- while (!callback.success && now < deadline) {
- try {
- wait(deadline - now);
- } catch (InterruptedException e) {
- }
- now = System.currentTimeMillis();
- }
- }
- mCm.unregisterNetworkCallback(callback);
- if (!callback.success) {
- fail(networkInterface.getSystemFeature()
- + " is a reported system feature, however no corresponding "
- + "connected network interface was found or the attempt "
- + "to connect and read has timed out (timeout = " + (TIMEOUT_MILLIS * 2.4)
- + "ms)." + networkInterface.getErrorMessage());
- }
+ final Network network = requestNetworkAndSetAttributes(networkInterface);
- networkInterface.setMetered(callback.metered);
- networkInterface.setRoaming(callback.roaming);
- networkInterface.setIsDefault(callback.isDefault);
+ mStartTime = System.currentTimeMillis() - tolerance;
+ waitForHostResolution(network, new URL(CHECK_CONNECTIVITY_URL));
+ exerciseRemoteHost(network, new URL(CHECK_CONNECTIVITY_URL));
+ mEndTime = System.currentTimeMillis() + tolerance;
+
+ // It is fine if the test fails and this line is not reached.
+ // The AutoReleaseNetworkCallbackRule will eventually release
+ // all unwanted callbacks.
+ networkInterface.unrequestNetwork();
}
private String getSubscriberId(int networkIndex) {
diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp
index 83818be..d9bc7f7 100644
--- a/tests/cts/tethering/Android.bp
+++ b/tests/cts/tethering/Android.bp
@@ -19,7 +19,10 @@
java_defaults {
name: "CtsTetheringTestDefaults",
- defaults: ["cts_defaults"],
+ defaults: [
+ "cts_defaults",
+ "framework-connectivity-test-defaults",
+ ],
libs: [
"android.test.base.stubs.system",
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 1454d9a..a07c9ea 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -32,6 +32,7 @@
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.cts.util.CtsTetheringUtils.isAnyIfaceMatch;
+import static android.os.Process.INVALID_UID;
import static com.android.testutils.TestPermissionUtil.runAsShell;
@@ -244,24 +245,35 @@
assertFalse(tr.isExemptFromEntitlementCheck());
assertTrue(tr.getShouldShowEntitlementUi());
assertEquals(softApConfiguration, tr.getSoftApConfiguration());
+ assertEquals(INVALID_UID, tr.getUid());
+ assertNull(tr.getPackageName());
final LinkAddress localAddr = new LinkAddress("192.168.24.5/24");
final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24");
final TetheringRequest tr2 = new TetheringRequest.Builder(TETHERING_USB)
.setStaticIpv4Addresses(localAddr, clientAddr)
.setExemptFromEntitlementCheck(true)
- .setShouldShowEntitlementUi(false).build();
+ .setShouldShowEntitlementUi(false)
+ .build();
+ int uid = 1000;
+ String packageName = "package";
+ tr2.setUid(uid);
+ tr2.setPackageName(packageName);
assertEquals(localAddr, tr2.getLocalIpv4Address());
assertEquals(clientAddr, tr2.getClientStaticIpv4Address());
assertEquals(TETHERING_USB, tr2.getTetheringType());
assertTrue(tr2.isExemptFromEntitlementCheck());
assertFalse(tr2.getShouldShowEntitlementUi());
+ assertEquals(uid, tr2.getUid());
+ assertEquals(packageName, tr2.getPackageName());
final TetheringRequest tr3 = new TetheringRequest.Builder(TETHERING_USB)
.setStaticIpv4Addresses(localAddr, clientAddr)
.setExemptFromEntitlementCheck(true)
.setShouldShowEntitlementUi(false).build();
+ tr3.setUid(uid);
+ tr3.setPackageName(packageName);
assertEquals(tr2, tr3);
}
diff --git a/tests/deflake/Android.bp b/tests/deflake/Android.bp
index 726e504..70a3655 100644
--- a/tests/deflake/Android.bp
+++ b/tests/deflake/Android.bp
@@ -40,7 +40,7 @@
"kotlin-test",
"net-host-tests-utils",
],
- data: [":FrameworksNetTests"],
+ device_common_data: [":FrameworksNetTests"],
test_suites: ["device-tests"],
// It will get build error if just set enabled to true. It fails with "windows_common"
// depends on some disabled modules that are used by this test and it looks like set
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 6892a42..9edf9bd 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -114,7 +114,7 @@
visibility: ["//packages/modules/Connectivity/tests:__subpackages__"],
}
-genrule {
+java_genrule {
name: "frameworks-net-tests-jarjar-rules",
defaults: ["jarjar-rules-combine-defaults"],
srcs: [
diff --git a/thread/demoapp/java/com/android/threadnetwork/demoapp/ThreadNetworkSettingsFragment.java b/thread/demoapp/java/com/android/threadnetwork/demoapp/ThreadNetworkSettingsFragment.java
index 2659d24..ea30e26 100644
--- a/thread/demoapp/java/com/android/threadnetwork/demoapp/ThreadNetworkSettingsFragment.java
+++ b/thread/demoapp/java/com/android/threadnetwork/demoapp/ThreadNetworkSettingsFragment.java
@@ -28,6 +28,7 @@
import android.net.thread.ActiveOperationalDataset;
import android.net.thread.OperationalDatasetTimestamp;
import android.net.thread.PendingOperationalDataset;
+import android.net.thread.ThreadConfiguration;
import android.net.thread.ThreadNetworkController;
import android.net.thread.ThreadNetworkException;
import android.net.thread.ThreadNetworkManager;
@@ -45,6 +46,8 @@
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
+import com.google.android.material.switchmaterial.SwitchMaterial;
+
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
@@ -63,6 +66,7 @@
private TextView mTextNetworkInfo;
private TextView mMigrateNetworkState;
private TextView mEphemeralKeyStateText;
+ private SwitchMaterial mNat64Switch;
private Executor mMainExecutor;
private int mDeviceRole;
@@ -72,6 +76,7 @@
private String mEphemeralKey;
private Instant mEphemeralKeyExpiry;
private Timer mEphemeralKeyLifetimeTimer;
+ private ThreadConfiguration mThreadConfiguration;
private static final byte[] DEFAULT_ACTIVE_DATASET_TLVS =
base16().lowerCase()
@@ -110,6 +115,10 @@
}
}
+ private static String booleanToEnabledOrDisabled(boolean enabled) {
+ return enabled ? "Enabled" : "Disabled";
+ }
+
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -181,11 +190,16 @@
this.mActiveDataset = newActiveDataset;
updateState();
});
+ mThreadController.registerConfigurationCallback(
+ mMainExecutor, this::updateConfiguration);
}
mTextState = (TextView) view.findViewById(R.id.text_state);
mTextNetworkInfo = (TextView) view.findViewById(R.id.text_network_info);
mEphemeralKeyStateText = (TextView) view.findViewById(R.id.text_ephemeral_key_state);
+ mNat64Switch = (SwitchMaterial) view.findViewById(R.id.switch_nat64);
+ mNat64Switch.setOnCheckedChangeListener(
+ (buttonView, isChecked) -> doSetNat64Enabled(isChecked));
if (mThreadController == null) {
mTextState.setText("Thread not supported!");
@@ -303,6 +317,34 @@
});
}
+ private void doSetNat64Enabled(boolean enabled) {
+ if (mThreadConfiguration == null) {
+ Log.e(TAG, "Thread configuration is not available");
+ return;
+ }
+ final ThreadConfiguration config =
+ new ThreadConfiguration.Builder(mThreadConfiguration)
+ .setNat64Enabled(enabled)
+ .build();
+ mThreadController.setConfiguration(
+ config,
+ mMainExecutor,
+ new OutcomeReceiver<>() {
+ @Override
+ public void onError(ThreadNetworkException error) {
+ Log.e(
+ TAG,
+ "Failed to set NAT64 " + booleanToEnabledOrDisabled(enabled),
+ error);
+ }
+
+ @Override
+ public void onResult(Void v) {
+ Log.i(TAG, "Successfully set NAT64 " + booleanToEnabledOrDisabled(enabled));
+ }
+ });
+ }
+
private void updateState() {
Log.i(
TAG,
@@ -368,4 +410,11 @@
}
mTextNetworkInfo.setText(sb.toString());
}
+
+ private void updateConfiguration(ThreadConfiguration config) {
+ Log.i(TAG, "Updating configuration: " + config);
+
+ mThreadConfiguration = config;
+ mNat64Switch.setChecked(config.isNat64Enabled());
+ }
}
diff --git a/thread/demoapp/res/layout/main_activity.xml b/thread/demoapp/res/layout/main_activity.xml
index 12072e5..d874db1 100644
--- a/thread/demoapp/res/layout/main_activity.xml
+++ b/thread/demoapp/res/layout/main_activity.xml
@@ -21,6 +21,7 @@
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
tools:context=".MainActivity">
<LinearLayout
diff --git a/thread/demoapp/res/layout/thread_network_settings_fragment.xml b/thread/demoapp/res/layout/thread_network_settings_fragment.xml
index 84d984b..47ce62a 100644
--- a/thread/demoapp/res/layout/thread_network_settings_fragment.xml
+++ b/thread/demoapp/res/layout/thread_network_settings_fragment.xml
@@ -19,11 +19,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="vertical"
tools:context=".ThreadNetworkSettingsFragment" >
@@ -40,28 +39,28 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="16dp"
+ android:textSize="16sp"
android:textStyle="bold"
android:text="State" />
<TextView
android:id="@+id/text_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="12dp"
+ android:textSize="12sp"
android:typeface="monospace" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:textSize="16dp"
+ android:textSize="16sp"
android:textStyle="bold"
android:text="Network Info" />
<TextView
android:id="@+id/text_network_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="12dp" />
+ android:textSize="12sp" />
<Button android:id="@+id/button_migrate_network"
android:layout_width="wrap_content"
@@ -71,7 +70,7 @@
android:id="@+id/text_migrate_network_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="12dp" />
+ android:textSize="12sp" />
<Button android:id="@+id/button_activate_ephemeral_key_mode"
android:layout_width="wrap_content"
@@ -86,14 +85,28 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
- android:textSize="16dp"
+ android:textSize="16sp"
android:textStyle="bold"
android:text="Ephemeral Key State" />
<TextView
android:id="@+id/text_ephemeral_key_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="50dp"
- android:textSize="12dp" />
+ android:textSize="12sp" />
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="Configuration"
+ android:textSize="16sp"
+ android:textStyle="bold" />
+ <com.google.android.material.switchmaterial.SwitchMaterial
+ android:id="@+id/switch_nat64"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:checked="false"
+ android:text="NAT64" />
+
</LinearLayout>
</ScrollView>
diff --git a/tools/Android.bp b/tools/Android.bp
index 2c2ed14..1351eb7 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -81,7 +81,7 @@
"gen_jarjar.py",
"gen_jarjar_test.py",
],
- data: [
+ device_common_data: [
"testdata/test-jarjar-excludes.txt",
// txt with Test classes to test they aren't included when added to jarjar excludes
"testdata/test-jarjar-excludes-testclass.txt",