Merge "Fix TetheringTest.failureEnablingIpForwarding verification count" into main
diff --git a/OWNERS_core_networking_xts b/OWNERS_core_networking_xts
index 9e4e4a1..60ca885 100644
--- a/OWNERS_core_networking_xts
+++ b/OWNERS_core_networking_xts
@@ -10,3 +10,5 @@
# In addition to cherry-picks, flaky test fixes and no-op refactors, also for
# NsdManager tests
reminv@google.com #{LAST_RESORT_SUGGESTION}
+# Only for APF firmware tests (to verify correct behaviour of the wifi APF interpreter)
+yuyanghuang@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 2878f79..531489d 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -47,15 +47,6 @@
// as the above target may have different "enabled" values
// depending on the branch
-apex_defaults {
- name: "CronetInTetheringApexDefaults",
- jni_libs: [
- "cronet_aml_components_cronet_android_cronet",
- "//external/cronet/third_party/boringssl:libcrypto",
- "//external/cronet/third_party/boringssl:libssl",
- ],
-}
-
apex {
name: "com.android.tethering",
defaults: [
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 5d99b74..3d7ea69 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1242,6 +1242,22 @@
@ConnectivityManagerFeature
private Long mEnabledConnectivityManagerFeatures = null;
+ /**
+ * A class to help with mocking ConnectivityManager.
+ * @hide
+ */
+ public static class MockHelpers {
+ /**
+ * Produce an instance of the class returned by
+ * {@link ConnectivityManager#registerNetworkAgent}
+ * @hide
+ */
+ public static Network registerNetworkAgentResult(
+ @Nullable final Network network, @Nullable final INetworkAgentRegistry registry) {
+ return network;
+ }
+ }
+
private TetheringManager getTetheringManager() {
synchronized (mTetheringEventCallbacks) {
if (mTetheringManager == null) {
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
index fb42c03..41b58fa 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
@@ -33,8 +33,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
import java.util.Optional;
/** Helper class to download certificate transparency log files. */
@@ -48,28 +47,21 @@
private final DownloadHelper mDownloadHelper;
private final SignatureVerifier mSignatureVerifier;
private final CertificateTransparencyLogger mLogger;
-
- private final List<CompatibilityVersion> mCompatVersions = new ArrayList<>();
+ private final Collection<CompatibilityVersion> mCompatVersions;
CertificateTransparencyDownloader(
Context context,
DataStore dataStore,
DownloadHelper downloadHelper,
SignatureVerifier signatureVerifier,
- CertificateTransparencyLogger logger) {
+ CertificateTransparencyLogger logger,
+ Collection<CompatibilityVersion> compatVersions) {
mContext = context;
mSignatureVerifier = signatureVerifier;
mDataStore = dataStore;
mDownloadHelper = downloadHelper;
mLogger = logger;
- }
-
- void addCompatibilityVersion(CompatibilityVersion compatVersion) {
- mCompatVersions.add(compatVersion);
- }
-
- void clearCompatibilityVersions() {
- mCompatVersions.clear();
+ mCompatVersions = compatVersions;
}
long startPublicKeyDownload() {
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
index f1b9a4f..286f326 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
@@ -28,6 +28,8 @@
import android.os.SystemClock;
import android.util.Log;
+import java.util.Collection;
+
/** Implementation of the Certificate Transparency job */
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
public class CertificateTransparencyJob extends BroadcastReceiver {
@@ -37,8 +39,8 @@
private final Context mContext;
private final DataStore mDataStore;
private final CertificateTransparencyDownloader mCertificateTransparencyDownloader;
- private final CompatibilityVersion mCompatVersion;
private final SignatureVerifier mSignatureVerifier;
+ private final Collection<CompatibilityVersion> mCompatVersions;
private final AlarmManager mAlarmManager;
private final PendingIntent mPendingIntent;
@@ -50,13 +52,13 @@
Context context,
DataStore dataStore,
CertificateTransparencyDownloader certificateTransparencyDownloader,
- CompatibilityVersion compatVersion,
- SignatureVerifier signatureVerifier) {
+ SignatureVerifier signatureVerifier,
+ Collection<CompatibilityVersion> compatVersions) {
mContext = context;
mDataStore = dataStore;
mCertificateTransparencyDownloader = certificateTransparencyDownloader;
- mCompatVersion = compatVersion;
mSignatureVerifier = signatureVerifier;
+ mCompatVersions = compatVersions;
mAlarmManager = context.getSystemService(AlarmManager.class);
mPendingIntent =
@@ -99,7 +101,9 @@
}
mDependenciesReady = false;
- mCompatVersion.delete();
+ for (CompatibilityVersion compatVersion : mCompatVersions) {
+ compatVersion.delete();
+ }
if (Config.DEBUG) {
Log.d(TAG, "CertificateTransparencyJob canceled.");
@@ -129,7 +133,6 @@
private void startDependencies() {
mDataStore.load();
- mCertificateTransparencyDownloader.addCompatibilityVersion(mCompatVersion);
mSignatureVerifier.loadAllowedKeys();
mContext.registerReceiver(
mCertificateTransparencyDownloader,
@@ -144,7 +147,6 @@
private void stopDependencies() {
mContext.unregisterReceiver(mCertificateTransparencyDownloader);
mSignatureVerifier.clearAllowedKeys();
- mCertificateTransparencyDownloader.clearCompatibilityVersions();
mDataStore.delete();
if (Config.DEBUG) {
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
index 2e910b2..5e530c7 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
@@ -30,6 +30,8 @@
import com.android.server.SystemService;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.concurrent.Executors;
/** Implementation of the Certificate Transparency service. */
@@ -51,8 +53,18 @@
/** Creates a new {@link CertificateTransparencyService} object. */
public CertificateTransparencyService(Context context) {
DataStore dataStore = new DataStore(Config.PREFERENCES_FILE);
-
SignatureVerifier signatureVerifier = new SignatureVerifier(context);
+ Collection<CompatibilityVersion> compatVersions =
+ Arrays.asList(
+ new CompatibilityVersion(
+ Config.COMPATIBILITY_VERSION_V1,
+ Config.URL_SIGNATURE_V1,
+ Config.URL_LOG_LIST_V1),
+ new CompatibilityVersion(
+ Config.COMPATIBILITY_VERSION_V2,
+ Config.URL_SIGNATURE_V2,
+ Config.URL_LOG_LIST_V2));
+
mCertificateTransparencyJob =
new CertificateTransparencyJob(
context,
@@ -62,13 +74,10 @@
dataStore,
new DownloadHelper(context),
signatureVerifier,
- new CertificateTransparencyLoggerImpl(dataStore)),
- new CompatibilityVersion(
- Config.COMPATIBILITY_VERSION,
- Config.URL_SIGNATURE,
- Config.URL_LOG_LIST,
- Config.CT_ROOT_DIRECTORY_PATH),
- signatureVerifier);
+ new CertificateTransparencyLoggerImpl(dataStore),
+ compatVersions),
+ signatureVerifier,
+ compatVersions);
}
/**
diff --git a/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java b/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
index e8a6e64..0a91963 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
@@ -23,6 +23,8 @@
import android.system.Os;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
import com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState;
import org.json.JSONException;
@@ -40,6 +42,8 @@
private static final String TAG = "CompatibilityVersion";
+ private static File sRootDirectory = new File(Config.CT_ROOT_DIRECTORY_PATH);
+
static final String LOGS_DIR_PREFIX = "logs-";
static final String LOGS_LIST_FILE_NAME = "log_list.json";
static final String CURRENT_LOGS_DIR_SYMLINK_NAME = "current";
@@ -48,23 +52,21 @@
private final String mMetadataUrl;
private final String mContentUrl;
- private final File mRootDirectory;
private final File mVersionDirectory;
private final File mCurrentLogsDirSymlink;
CompatibilityVersion(
- String compatVersion, String metadataUrl, String contentUrl, File rootDirectory) {
+ String compatVersion, String metadataUrl, String contentUrl) {
mCompatVersion = compatVersion;
mMetadataUrl = metadataUrl;
mContentUrl = contentUrl;
- mRootDirectory = rootDirectory;
- mVersionDirectory = new File(rootDirectory, compatVersion);
+ mVersionDirectory = new File(sRootDirectory, compatVersion);
mCurrentLogsDirSymlink = new File(mVersionDirectory, CURRENT_LOGS_DIR_SYMLINK_NAME);
}
- CompatibilityVersion(
- String compatVersion, String metadataUrl, String contentUrl, String rootDirectoryPath) {
- this(compatVersion, metadataUrl, contentUrl, new File(rootDirectoryPath));
+ @VisibleForTesting
+ static void setRootDirectoryForTesting(File rootDirectory) {
+ sRootDirectory = rootDirectory;
}
/**
@@ -75,8 +77,8 @@
* @return true if the log list was installed successfully, false otherwise.
* @throws IOException if the list cannot be saved in the CT directory.
*/
- LogListUpdateStatus install(
- InputStream newContent, LogListUpdateStatus.Builder statusBuilder) throws IOException {
+ LogListUpdateStatus install(InputStream newContent, LogListUpdateStatus.Builder statusBuilder)
+ throws IOException {
String content = new String(newContent.readAllBytes(), UTF_8);
try {
JSONObject contentJson = new JSONObject(content);
@@ -98,7 +100,7 @@
// there's a bunch of steps. We create a new directory with the logs and then do
// an atomic update of the current symlink to point to the new directory.
// 1. Ensure the path to the root and version directories exist and are readable.
- DirectoryUtils.makeDir(mRootDirectory);
+ DirectoryUtils.makeDir(sRootDirectory);
DirectoryUtils.makeDir(mVersionDirectory);
File newLogsDir = new File(mVersionDirectory, LOGS_DIR_PREFIX + version);
diff --git a/networksecurity/service/src/com/android/server/net/ct/Config.java b/networksecurity/service/src/com/android/server/net/ct/Config.java
index 5fdba09..72b715a 100644
--- a/networksecurity/service/src/com/android/server/net/ct/Config.java
+++ b/networksecurity/service/src/com/android/server/net/ct/Config.java
@@ -33,18 +33,14 @@
private static final String PREFERENCES_FILE_NAME = "ct.preferences";
static final File PREFERENCES_FILE = new File(DEVICE_PROTECTED_DATA_DIR, PREFERENCES_FILE_NAME);
- // CT directory
+ // CT paths
static final String CT_ROOT_DIRECTORY_PATH = "/data/misc/keychain/ct/";
- static final String COMPATIBILITY_VERSION = "v1";
+ static final String URL_PREFIX = "https://www.gstatic.com/android/certificate_transparency/";
// Phenotype flags
static final String NAMESPACE_NETWORK_SECURITY = "network_security";
private static final String FLAGS_PREFIX = "CertificateTransparencyLogList__";
static final String FLAG_SERVICE_ENABLED = FLAGS_PREFIX + "service_enabled";
- static final String FLAG_CONTENT_URL = FLAGS_PREFIX + "content_url";
- static final String FLAG_METADATA_URL = FLAGS_PREFIX + "metadata_url";
- static final String FLAG_VERSION = FLAGS_PREFIX + "version";
- static final String FLAG_PUBLIC_KEY = FLAGS_PREFIX + "public_key";
// properties
static final String VERSION = "version";
@@ -53,9 +49,18 @@
static final String PUBLIC_KEY_DOWNLOAD_ID = "public_key_download_id";
static final String LOG_LIST_UPDATE_FAILURE_COUNT = "log_list_update_failure_count";
- // URLs
- static final String URL_PREFIX = "https://www.gstatic.com/android/certificate_transparency/";
- static final String URL_LOG_LIST = URL_PREFIX + "log_list.json";
- static final String URL_SIGNATURE = URL_PREFIX + "log_list.sig";
+ // Public Key URLs
static final String URL_PUBLIC_KEY = URL_PREFIX + "log_list.pub";
+
+ // Compatibility Version v1
+ static final String COMPATIBILITY_VERSION_V1 = "v1";
+ static final String URL_PREFIX_V1 = URL_PREFIX;
+ static final String URL_LOG_LIST_V1 = URL_PREFIX_V1 + "log_list.json";
+ static final String URL_SIGNATURE_V1 = URL_PREFIX_V1 + "log_list.sig";
+
+ // Compatibility Version v2
+ static final String COMPATIBILITY_VERSION_V2 = "v2";
+ static final String URL_PREFIX_V2 = URL_PREFIX + COMPATIBILITY_VERSION_V2 + "/";
+ static final String URL_LOG_LIST_V2 = URL_PREFIX_V2 + "log_list.json";
+ static final String URL_SIGNATURE_V2 = URL_PREFIX_V2 + "log_list.sig";
}
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 22dc6ab..956bad5 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -60,6 +60,7 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
+import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;
@@ -94,24 +95,25 @@
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mDataStore = new DataStore(File.createTempFile("datastore-test", ".properties"));
mSignatureVerifier = new SignatureVerifier(mContext);
+
+ CompatibilityVersion.setRootDirectoryForTesting(mContext.getFilesDir());
+ mCompatVersion =
+ new CompatibilityVersion(
+ /* compatVersion= */ "v666",
+ Config.URL_SIGNATURE_V1,
+ Config.URL_LOG_LIST_V1);
mCertificateTransparencyDownloader =
new CertificateTransparencyDownloader(
mContext,
mDataStore,
new DownloadHelper(mDownloadManager),
mSignatureVerifier,
- mLogger);
- mCompatVersion =
- new CompatibilityVersion(
- /* compatVersion= */ "v666",
- Config.URL_SIGNATURE,
- Config.URL_LOG_LIST,
- mContext.getFilesDir());
+ mLogger,
+ Arrays.asList(mCompatVersion));
prepareDownloadManager();
mSignatureVerifier.addAllowedKey(mPublicKey);
mDataStore.load();
- mCertificateTransparencyDownloader.addCompatibilityVersion(mCompatVersion);
}
@After
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java
index 2b8b3cd..0d15183 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CompatibilityVersionTest.java
@@ -27,6 +27,7 @@
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -47,9 +48,16 @@
private final File mTestDir =
InstrumentationRegistry.getInstrumentation().getContext().getFilesDir();
- private final CompatibilityVersion mCompatVersion =
- new CompatibilityVersion(
- TEST_VERSION, Config.URL_SIGNATURE, Config.URL_LOG_LIST, mTestDir);
+
+ private CompatibilityVersion mCompatVersion;
+
+ @Before
+ public void setUp() {
+ CompatibilityVersion.setRootDirectoryForTesting(mTestDir);
+ mCompatVersion =
+ new CompatibilityVersion(
+ TEST_VERSION, Config.URL_SIGNATURE_V1, Config.URL_LOG_LIST_V1);
+ }
@After
public void tearDown() {
@@ -111,9 +119,7 @@
JSONObject logList = makeLogList(version, "i_am_content");
try (InputStream inputStream = asStream(logList)) {
- assertThat(
- mCompatVersion.install(
- inputStream, LogListUpdateStatus.builder()))
+ assertThat(mCompatVersion.install(inputStream, LogListUpdateStatus.builder()))
.isEqualTo(getSuccessfulUpdateStatus());
}
@@ -142,9 +148,7 @@
@Test
public void testCompatibilityVersion_deleteSuccessfully() throws Exception {
try (InputStream inputStream = asStream(makeLogList(/* version= */ "123"))) {
- assertThat(
- mCompatVersion.install(
- inputStream, LogListUpdateStatus.builder()))
+ assertThat(mCompatVersion.install(inputStream, LogListUpdateStatus.builder()))
.isEqualTo(getSuccessfulUpdateStatus());
}
@@ -156,9 +160,7 @@
@Test
public void testCompatibilityVersion_invalidLogList() throws Exception {
try (InputStream inputStream = new ByteArrayInputStream(("not_a_valid_list".getBytes()))) {
- assertThat(
- mCompatVersion.install(
- inputStream, LogListUpdateStatus.builder()))
+ assertThat(mCompatVersion.install(inputStream, LogListUpdateStatus.builder()))
.isEqualTo(LogListUpdateStatus.builder().setState(LOG_LIST_INVALID).build());
}
@@ -179,9 +181,7 @@
JSONObject newLogList = makeLogList(existingVersion, "i_am_the_real_content");
try (InputStream inputStream = asStream(newLogList)) {
- assertThat(
- mCompatVersion.install(
- inputStream, LogListUpdateStatus.builder()))
+ assertThat(mCompatVersion.install(inputStream, LogListUpdateStatus.builder()))
.isEqualTo(getSuccessfulUpdateStatus());
}
@@ -193,16 +193,12 @@
String existingVersion = "666";
JSONObject existingLogList = makeLogList(existingVersion, "i_was_installed_successfully");
try (InputStream inputStream = asStream(existingLogList)) {
- assertThat(
- mCompatVersion.install(
- inputStream, LogListUpdateStatus.builder()))
+ assertThat(mCompatVersion.install(inputStream, LogListUpdateStatus.builder()))
.isEqualTo(getSuccessfulUpdateStatus());
}
try (InputStream inputStream = asStream(makeLogList(existingVersion, "i_am_ignored"))) {
- assertThat(
- mCompatVersion.install(
- inputStream, LogListUpdateStatus.builder()))
+ assertThat(mCompatVersion.install(inputStream, LogListUpdateStatus.builder()))
.isEqualTo(
LogListUpdateStatus.builder()
.setState(VERSION_ALREADY_EXISTS)
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 8fcc703..5e035a2 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -172,6 +172,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.argThat
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.doReturn
@@ -1066,7 +1067,20 @@
fun testAgentStartsInConnecting() {
val mockContext = mock(Context::class.java)
val mockCm = mock(ConnectivityManager::class.java)
+ val mockedResult = ConnectivityManager.MockHelpers.registerNetworkAgentResult(
+ mock(Network::class.java),
+ mock(INetworkAgentRegistry::class.java)
+ )
doReturn(mockCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+ doReturn(mockedResult).`when`(mockCm).registerNetworkAgent(
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ anyInt()
+ )
val agent = createNetworkAgent(mockContext)
agent.register()
verify(mockCm).registerNetworkAgent(
diff --git a/thread/service/java/com/android/server/thread/TunInterfaceController.java b/thread/service/java/com/android/server/thread/TunInterfaceController.java
index 520a434..2f2a5d1 100644
--- a/thread/service/java/com/android/server/thread/TunInterfaceController.java
+++ b/thread/service/java/com/android/server/thread/TunInterfaceController.java
@@ -326,12 +326,13 @@
private static LinkAddress newLinkAddress(
Ipv6AddressInfo addressInfo, boolean hasActiveOmrAddress) {
// Mesh-local addresses and OMR address have the same scope, to distinguish them we set
- // mesh-local addresses as deprecated when there is an active OMR address.
+ // mesh-local addresses as deprecated when there is an active OMR address. If OMR address
+ // is missing, only ML-EID in mesh-local addresses will be set preferred.
// For OMR address and link-local address we only use the value isPreferred set by
// ot-daemon.
boolean isPreferred = addressInfo.isPreferred;
- if (addressInfo.isMeshLocal && hasActiveOmrAddress) {
- isPreferred = false;
+ if (addressInfo.isMeshLocal) {
+ isPreferred = (!hasActiveOmrAddress && addressInfo.isMeshLocalEid);
}
final long deprecationTimeMillis =
diff --git a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
index 5ba76b8..5be8f49 100644
--- a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
+++ b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
@@ -19,12 +19,10 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.net.thread.ThreadNetworkController;
import android.net.thread.ThreadNetworkManager;
import android.os.Build;
@@ -41,8 +39,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-
/** Tests for {@link ThreadNetworkManager}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index 195f6d2..5b07e0a 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -22,12 +22,14 @@
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_STOPPED;
import static android.net.thread.utils.IntegrationTestUtils.CALLBACK_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
+import static android.net.thread.utils.IntegrationTestUtils.getIpv6Addresses;
import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
import static android.net.thread.utils.IntegrationTestUtils.getPrefixesFromNetData;
import static android.net.thread.utils.IntegrationTestUtils.getThreadNetwork;
import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
import static android.net.thread.utils.ThreadNetworkControllerWrapper.JOIN_TIMEOUT;
+import static android.os.SystemClock.elapsedRealtime;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
@@ -38,6 +40,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -46,23 +49,26 @@
import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
-import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.thread.utils.FullThreadDevice;
import android.net.thread.utils.OtDaemonController;
+import android.net.thread.utils.TapTestNetworkTracker;
import android.net.thread.utils.ThreadFeatureCheckerRule;
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresSimulationThreadDevice;
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
import android.net.thread.utils.ThreadNetworkControllerWrapper;
import android.net.thread.utils.ThreadStateListener;
+import android.os.HandlerThread;
import android.os.SystemClock;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.LargeTest;
+import com.google.common.collect.FluentIterable;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -102,6 +108,12 @@
private static final Duration NETWORK_CALLBACK_TIMEOUT = Duration.ofSeconds(10);
+ // The duration between attached and OMR address shows up on thread-wpan
+ private static final Duration OMR_LINK_ADDR_TIMEOUT = Duration.ofSeconds(30);
+
+ // The duration between attached and addresses show up on thread-wpan
+ private static final Duration LINK_ADDR_TIMEOUT = Duration.ofSeconds(2);
+
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset init new".
private static final byte[] DEFAULT_DATASET_TLVS =
base16().decode(
@@ -128,6 +140,8 @@
ThreadNetworkControllerWrapper.newInstance(mContext);
private OtDaemonController mOtCtl;
private FullThreadDevice mFtd;
+ private HandlerThread mHandlerThread;
+ private TapTestNetworkTracker mTestNetworkTracker;
public final boolean mIsBorderRouterEnabled;
private final ThreadConfiguration mConfig;
@@ -152,6 +166,14 @@
mController.setEnabledAndWait(true);
mController.setConfigurationAndWait(mConfig);
mController.leaveAndWait();
+
+ mHandlerThread = new HandlerThread("ThreadIntegrationTest");
+ mHandlerThread.start();
+
+ mTestNetworkTracker = new TapTestNetworkTracker(mContext, mHandlerThread.getLooper());
+ assertThat(mTestNetworkTracker).isNotNull();
+ mController.setTestNetworkAsUpstreamAndWait(mTestNetworkTracker.getInterfaceName());
+
mFtd = new FullThreadDevice(10 /* nodeId */);
}
@@ -159,6 +181,13 @@
public void tearDown() throws Exception {
ThreadStateListener.stopAllListeners();
+ if (mTestNetworkTracker != null) {
+ mTestNetworkTracker.tearDown();
+ }
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ mHandlerThread.join();
+ }
mController.setTestNetworkAsUpstreamAndWait(null);
mController.leaveAndWait();
@@ -265,23 +294,51 @@
}
@Test
- public void joinNetworkWithBrDisabled_meshLocalAddressesArePreferred() throws Exception {
- // When BR feature is disabled, there is no OMR address, so the mesh-local addresses are
- // expected to be preferred.
- mOtCtl.executeCommand("br disable");
+ public void joinNetwork_borderRouterEnabled_allMlAddrAreNotPreferredAndOmrIsPreferred()
+ throws Exception {
+ assumeTrue(mConfig.isBorderRouterEnabled());
+
+ mController.setTestNetworkAsUpstreamAndWait(mTestNetworkTracker.getInterfaceName());
mController.joinAndWait(DEFAULT_DATASET);
+ waitFor(
+ () -> getIpv6Addresses("thread-wpan").contains(mOtCtl.getOmrAddress()),
+ OMR_LINK_ADDR_TIMEOUT);
IpPrefix meshLocalPrefix = DEFAULT_DATASET.getMeshLocalPrefix();
- List<LinkAddress> linkAddresses = getIpv6LinkAddresses("thread-wpan");
- for (LinkAddress address : linkAddresses) {
- if (meshLocalPrefix.contains(address.getAddress())) {
- assertThat(address.getDeprecationTime())
- .isGreaterThan(SystemClock.elapsedRealtime());
- assertThat(address.isPreferred()).isTrue();
- }
- }
+ var linkAddrs = FluentIterable.from(getIpv6LinkAddresses("thread-wpan"));
+ var meshLocalAddrs = linkAddrs.filter(addr -> meshLocalPrefix.contains(addr.getAddress()));
+ assertThat(meshLocalAddrs).isNotEmpty();
+ assertThat(meshLocalAddrs.allMatch(addr -> !addr.isPreferred())).isTrue();
+ assertThat(meshLocalAddrs.allMatch(addr -> addr.getDeprecationTime() <= elapsedRealtime()))
+ .isTrue();
+ var omrAddrs = linkAddrs.filter(addr -> addr.getAddress().equals(mOtCtl.getOmrAddress()));
+ assertThat(omrAddrs).hasSize(1);
+ assertThat(omrAddrs.get(0).isPreferred()).isTrue();
+ assertThat(omrAddrs.get(0).getDeprecationTime() > elapsedRealtime()).isTrue();
+ }
- mOtCtl.executeCommand("br enable");
+ @Test
+ public void joinNetwork_borderRouterDisabled_onlyMlEidIsPreferred() throws Exception {
+ assumeFalse(mConfig.isBorderRouterEnabled());
+
+ mController.joinAndWait(DEFAULT_DATASET);
+ waitFor(
+ () -> getIpv6Addresses("thread-wpan").contains(mOtCtl.getMlEid()),
+ LINK_ADDR_TIMEOUT);
+
+ IpPrefix meshLocalPrefix = DEFAULT_DATASET.getMeshLocalPrefix();
+ var linkAddrs = FluentIterable.from(getIpv6LinkAddresses("thread-wpan"));
+ var meshLocalAddrs = linkAddrs.filter(addr -> meshLocalPrefix.contains(addr.getAddress()));
+ var mlEidAddrs = meshLocalAddrs.filter(addr -> addr.getAddress().equals(mOtCtl.getMlEid()));
+ var nonMlEidAddrs = meshLocalAddrs.filter(addr -> !mlEidAddrs.contains(addr));
+ assertThat(mlEidAddrs).hasSize(1);
+ assertThat(mlEidAddrs.allMatch(addr -> addr.isPreferred())).isTrue();
+ assertThat(mlEidAddrs.allMatch(addr -> addr.getDeprecationTime() > elapsedRealtime()))
+ .isTrue();
+ assertThat(nonMlEidAddrs).isNotEmpty();
+ assertThat(nonMlEidAddrs.allMatch(addr -> !addr.isPreferred())).isTrue();
+ assertThat(nonMlEidAddrs.allMatch(addr -> addr.getDeprecationTime() <= elapsedRealtime()))
+ .isTrue();
}
@Test
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
index f41e903..f7b4d19 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.kt
@@ -479,6 +479,12 @@
return addresses
}
+ /** Returns the list of [InetAddress] of the given network. */
+ @JvmStatic
+ fun getIpv6Addresses(interfaceName: String): List<InetAddress> {
+ return getIpv6LinkAddresses(interfaceName).map { it.address }
+ }
+
/** Return the first discovered service of `serviceType`. */
@JvmStatic
@Throws(Exception::class)
diff --git a/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java b/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
index 272685f..d35b94e 100644
--- a/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
+++ b/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
@@ -24,9 +24,11 @@
import com.android.compatibility.common.util.SystemUtil;
import java.net.Inet6Address;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Wrapper of the "/system/bin/ot-ctl" which can be used to send CLI commands to ot-daemon to
@@ -72,6 +74,25 @@
.toList();
}
+ /** Returns the OMR address of this device or {@code null} if it doesn't exist. */
+ @Nullable
+ public Inet6Address getOmrAddress() {
+ List<Inet6Address> allAddresses = new ArrayList<>(getAddresses());
+ allAddresses.removeAll(getMeshLocalAddresses());
+
+ List<Inet6Address> omrAddresses =
+ allAddresses.stream()
+ .filter(addr -> !addr.isLinkLocalAddress())
+ .collect(Collectors.toList());
+ if (omrAddresses.isEmpty()) {
+ return null;
+ } else if (omrAddresses.size() > 1) {
+ throw new IllegalStateException();
+ }
+
+ return omrAddresses.getFirst();
+ }
+
/** Returns {@code true} if the Thread interface is up. */
public boolean isInterfaceUp() {
String output = executeCommand("ifconfig");