set the country code when initializing the ot-daemon
The country code is lost after the ot-daemon is restarted. This
CL stores the country code to persistent settings and reads
out the previously stored country code to set the country code
when the ot-daemon is initialized.
Bug: b/326021472
Test: atest ThreadNetworkUnitTests
Change-Id: I6982a57ba4845f5a45f3366400c531398e82339e
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
index 155296d..706c446 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
@@ -182,6 +182,7 @@
private final NsdPublisher mNsdPublisher;
private final OtDaemonCallbackProxy mOtDaemonCallbackProxy = new OtDaemonCallbackProxy();
private final ConnectivityResources mResources;
+ private final Supplier<String> mCountryCodeSupplier;
// This should not be directly used for calling IOtDaemon APIs because ot-daemon may die and
// {@code mOtDaemon} will be set to {@code null}. Instead, use {@code getOtDaemon()}
@@ -215,7 +216,8 @@
ThreadPersistentSettings persistentSettings,
NsdPublisher nsdPublisher,
UserManager userManager,
- ConnectivityResources resources) {
+ ConnectivityResources resources,
+ Supplier<String> countryCodeSupplier) {
mContext = context;
mHandler = handler;
mNetworkProvider = networkProvider;
@@ -230,10 +232,13 @@
mNsdPublisher = nsdPublisher;
mUserManager = userManager;
mResources = resources;
+ mCountryCodeSupplier = countryCodeSupplier;
}
public static ThreadNetworkControllerService newInstance(
- Context context, ThreadPersistentSettings persistentSettings) {
+ Context context,
+ ThreadPersistentSettings persistentSettings,
+ Supplier<String> countryCodeSupplier) {
HandlerThread handlerThread = new HandlerThread("ThreadHandlerThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
@@ -251,7 +256,8 @@
persistentSettings,
NsdPublisher.newInstance(context, handler),
context.getSystemService(UserManager.class),
- new ConnectivityResources(context));
+ new ConnectivityResources(context),
+ countryCodeSupplier);
}
private static Inet6Address bytesToInet6Address(byte[] addressBytes) {
@@ -347,7 +353,8 @@
isEnabled(),
mNsdPublisher,
getMeshcopTxtAttributes(mResources.get()),
- mOtDaemonCallbackProxy);
+ mOtDaemonCallbackProxy,
+ mCountryCodeSupplier.get());
otDaemon.asBinder().linkToDeath(() -> mHandler.post(this::onOtDaemonDied), 0);
mOtDaemon = otDaemon;
return mOtDaemon;
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java b/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java
index ffa7b44..a194114 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkCountryCode.java
@@ -16,6 +16,8 @@
package com.android.server.thread;
+import static com.android.server.thread.ThreadPersistentSettings.THREAD_COUNTRY_CODE;
+
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.annotation.TargetApi;
@@ -83,6 +85,7 @@
COUNTRY_CODE_SOURCE_TELEPHONY,
COUNTRY_CODE_SOURCE_TELEPHONY_LAST,
COUNTRY_CODE_SOURCE_WIFI,
+ COUNTRY_CODE_SOURCE_SETTINGS,
})
private @interface CountryCodeSource {}
@@ -93,6 +96,7 @@
private static final String COUNTRY_CODE_SOURCE_TELEPHONY = "Telephony";
private static final String COUNTRY_CODE_SOURCE_TELEPHONY_LAST = "TelephonyLast";
private static final String COUNTRY_CODE_SOURCE_WIFI = "Wifi";
+ private static final String COUNTRY_CODE_SOURCE_SETTINGS = "Settings";
private static final CountryCodeInfo DEFAULT_COUNTRY_CODE_INFO =
new CountryCodeInfo(DEFAULT_COUNTRY_CODE, COUNTRY_CODE_SOURCE_DEFAULT);
@@ -107,6 +111,7 @@
private final SubscriptionManager mSubscriptionManager;
private final Map<Integer, TelephonyCountryCodeSlotInfo> mTelephonyCountryCodeSlotInfoMap =
new ArrayMap();
+ private final ThreadPersistentSettings mPersistentSettings;
@Nullable private CountryCodeInfo mCurrentCountryCodeInfo;
@Nullable private CountryCodeInfo mLocationCountryCodeInfo;
@@ -215,7 +220,8 @@
Context context,
TelephonyManager telephonyManager,
SubscriptionManager subscriptionManager,
- @Nullable String oemCountryCode) {
+ @Nullable String oemCountryCode,
+ ThreadPersistentSettings persistentSettings) {
mLocationManager = locationManager;
mThreadNetworkControllerService = threadNetworkControllerService;
mGeocoder = geocoder;
@@ -224,14 +230,19 @@
mContext = context;
mTelephonyManager = telephonyManager;
mSubscriptionManager = subscriptionManager;
+ mPersistentSettings = persistentSettings;
if (oemCountryCode != null) {
mOemCountryCodeInfo = new CountryCodeInfo(oemCountryCode, COUNTRY_CODE_SOURCE_OEM);
}
+
+ mCurrentCountryCodeInfo = pickCountryCode();
}
public static ThreadNetworkCountryCode newInstance(
- Context context, ThreadNetworkControllerService controllerService) {
+ Context context,
+ ThreadNetworkControllerService controllerService,
+ ThreadPersistentSettings persistentSettings) {
return new ThreadNetworkCountryCode(
context.getSystemService(LocationManager.class),
controllerService,
@@ -241,7 +252,8 @@
context,
context.getSystemService(TelephonyManager.class),
context.getSystemService(SubscriptionManager.class),
- ThreadNetworkProperties.country_code().orElse(null));
+ ThreadNetworkProperties.country_code().orElse(null),
+ persistentSettings);
}
/** Sets up this country code module to listen to location country code changes. */
@@ -485,6 +497,11 @@
return mLocationCountryCodeInfo;
}
+ String settingsCountryCode = mPersistentSettings.get(THREAD_COUNTRY_CODE);
+ if (settingsCountryCode != null) {
+ return new CountryCodeInfo(settingsCountryCode, COUNTRY_CODE_SOURCE_SETTINGS);
+ }
+
if (mOemCountryCodeInfo != null) {
return mOemCountryCodeInfo;
}
@@ -498,6 +515,8 @@
public void onSuccess() {
synchronized ("ThreadNetworkCountryCode.this") {
mCurrentCountryCodeInfo = countryCodeInfo;
+ mPersistentSettings.put(
+ THREAD_COUNTRY_CODE.key, countryCodeInfo.getCountryCode());
}
}
@@ -536,10 +555,9 @@
newOperationReceiver(countryCodeInfo));
}
- /** Returns the current country code or {@code null} if no country code is set. */
- @Nullable
+ /** Returns the current country code. */
public synchronized String getCountryCode() {
- return (mCurrentCountryCodeInfo != null) ? mCurrentCountryCodeInfo.getCountryCode() : null;
+ return mCurrentCountryCodeInfo.getCountryCode();
}
/**
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkService.java b/thread/service/java/com/android/server/thread/ThreadNetworkService.java
index 37c1cf1..30c67ca 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkService.java
@@ -60,13 +60,16 @@
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mPersistentSettings.initialize();
mControllerService =
- ThreadNetworkControllerService.newInstance(mContext, mPersistentSettings);
+ ThreadNetworkControllerService.newInstance(
+ mContext, mPersistentSettings, () -> mCountryCode.getCountryCode());
+ mCountryCode =
+ ThreadNetworkCountryCode.newInstance(
+ mContext, mControllerService, mPersistentSettings);
mControllerService.initialize();
} else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
// Country code initialization is delayed to the BOOT_COMPLETED phase because it will
// call into Wi-Fi and Telephony service whose country code module is ready after
// PHASE_ACTIVITY_MANAGER_READY and PHASE_THIRD_PARTY_APPS_CAN_START
- mCountryCode = ThreadNetworkCountryCode.newInstance(mContext, mControllerService);
mCountryCode.initialize();
mShellCommand =
new ThreadNetworkShellCommand(requireNonNull(mControllerService), mCountryCode);
diff --git a/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java b/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java
index 5cb53fe..3df2b6b 100644
--- a/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java
+++ b/thread/service/java/com/android/server/thread/ThreadPersistentSettings.java
@@ -63,6 +63,9 @@
/** Stores the Thread feature toggle state, true for enabled and false for disabled. */
public static final Key<Boolean> THREAD_ENABLED = new Key<>("Thread_enabled", true);
+ /** Stores the Thread country code, null if no country code is stored. */
+ public static final Key<String> THREAD_COUNTRY_CODE = new Key<>("thread_country_code", null);
+
/******** Thread persistent setting keys ***************/
@GuardedBy("mLock")
@@ -123,7 +126,9 @@
private <T> T getObject(String key, T defaultValue) {
Object value;
synchronized (mLock) {
- if (defaultValue instanceof Boolean) {
+ if (defaultValue == null) {
+ value = mSettings.getString(key, null);
+ } else if (defaultValue instanceof Boolean) {
value = mSettings.getBoolean(key, (Boolean) defaultValue);
} else if (defaultValue instanceof Integer) {
value = mSettings.getInt(key, (Integer) defaultValue);
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index bfded1d..c70f3af 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -23,6 +23,7 @@
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat;
@@ -140,6 +141,22 @@
}
}
+ @Test
+ public void otDaemonRestart_latestCountryCodeIsSetToOtDaemon() throws Exception {
+ runThreadCommand("force-country-code enabled CN");
+
+ runShellCommand("stop ot-daemon");
+ // TODO(b/323331973): the sleep is needed to workaround the race conditions
+ SystemClock.sleep(200);
+ mController.waitForRole(DEVICE_ROLE_STOPPED, CALLBACK_TIMEOUT);
+
+ assertThat(mOtCtl.getCountryCode()).isEqualTo("CN");
+ }
+
+ private static String runThreadCommand(String cmd) {
+ return runShellCommandOrThrow("cmd thread_network " + cmd);
+ }
+
// TODO (b/323300829): add more tests for integration with linux platform and
// ConnectivityService
}
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 ade0669..f39a064 100644
--- a/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
+++ b/thread/tests/integration/src/android/net/thread/utils/OtDaemonController.java
@@ -74,6 +74,12 @@
return (Inet6Address) InetAddresses.parseNumericAddress(addressStr);
}
+ /** Returns the country code on ot-daemon. */
+ public String getCountryCode() {
+ String countryCodeStr = executeCommand("region").split("\n")[0].trim();
+ return countryCodeStr;
+ }
+
public String executeCommand(String cmd) {
return SystemUtil.runShellCommand(OT_CTL + " " + cmd);
}
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
index 0c7d086..85b6873 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
@@ -25,6 +25,7 @@
import static android.net.thread.ThreadNetworkManager.DISALLOW_THREAD_NETWORK;
import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
+import static com.android.server.thread.ThreadNetworkCountryCode.DEFAULT_COUNTRY_CODE;
import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_INVALID_STATE;
import static com.google.common.io.BaseEncoding.base16;
@@ -182,7 +183,8 @@
mMockPersistentSettings,
mMockNsdPublisher,
mMockUserManager,
- mConnectivityResources);
+ mConnectivityResources,
+ () -> DEFAULT_COUNTRY_CODE);
mService.setTestNetworkAgent(mMockNetworkAgent);
}
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java
index 5ca6511..ca9741d 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkCountryCodeTest.java
@@ -19,6 +19,7 @@
import static android.net.thread.ThreadNetworkException.ERROR_INTERNAL_ERROR;
import static com.android.server.thread.ThreadNetworkCountryCode.DEFAULT_COUNTRY_CODE;
+import static com.android.server.thread.ThreadPersistentSettings.THREAD_COUNTRY_CODE;
import static com.google.common.truth.Truth.assertThat;
@@ -104,6 +105,7 @@
@Mock List<SubscriptionInfo> mSubscriptionInfoList;
@Mock SubscriptionInfo mSubscriptionInfo0;
@Mock SubscriptionInfo mSubscriptionInfo1;
+ @Mock ThreadPersistentSettings mPersistentSettings;
private ThreadNetworkCountryCode mThreadNetworkCountryCode;
private boolean mErrorSetCountryCode;
@@ -164,7 +166,8 @@
mContext,
mTelephonyManager,
mSubscriptionManager,
- oemCountryCode);
+ oemCountryCode,
+ mPersistentSettings);
}
private static Address newAddress(String countryCode) {
@@ -450,6 +453,14 @@
}
@Test
+ public void settingsCountryCode_settingsCountryCodeIsActive_settingsCountryCodeIsUsed() {
+ when(mPersistentSettings.get(THREAD_COUNTRY_CODE)).thenReturn(TEST_COUNTRY_CODE_CN);
+ mThreadNetworkCountryCode.initialize();
+
+ assertThat(mThreadNetworkCountryCode.getCountryCode()).isEqualTo(TEST_COUNTRY_CODE_CN);
+ }
+
+ @Test
public void dump_allCountryCodeInfoAreDumped() {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java
index 9406a2f..7d2fe91 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadPersistentSettingsTest.java
@@ -16,6 +16,7 @@
package com.android.server.thread;
+import static com.android.server.thread.ThreadPersistentSettings.THREAD_COUNTRY_CODE;
import static com.android.server.thread.ThreadPersistentSettings.THREAD_ENABLED;
import static com.google.common.truth.Truth.assertThat;
@@ -54,6 +55,8 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class ThreadPersistentSettingsTest {
+ private static final String TEST_COUNTRY_CODE = "CN";
+
@Mock private AtomicFile mAtomicFile;
@Mock Resources mResources;
@Mock ConnectivityResources mConnectivityResources;
@@ -131,6 +134,28 @@
verify(mAtomicFile).finishWrite(any());
}
+ @Test
+ public void put_ThreadCountryCodeString_returnsString() throws Exception {
+ mThreadPersistentSettings.put(THREAD_COUNTRY_CODE.key, TEST_COUNTRY_CODE);
+
+ assertThat(mThreadPersistentSettings.get(THREAD_COUNTRY_CODE)).isEqualTo(TEST_COUNTRY_CODE);
+
+ // Confirm that file writes have been triggered.
+ verify(mAtomicFile).startWrite();
+ verify(mAtomicFile).finishWrite(any());
+ }
+
+ @Test
+ public void put_ThreadCountryCodeNull_returnsNull() throws Exception {
+ mThreadPersistentSettings.put(THREAD_COUNTRY_CODE.key, null);
+
+ assertThat(mThreadPersistentSettings.get(THREAD_COUNTRY_CODE)).isNull();
+
+ // Confirm that file writes have been triggered.
+ verify(mAtomicFile).startWrite();
+ verify(mAtomicFile).finishWrite(any());
+ }
+
private byte[] createXmlForParsing(String key, Boolean value) throws Exception {
PersistableBundle bundle = new PersistableBundle();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();