diff --git a/common/thread_flags.aconfig b/common/thread_flags.aconfig index 14b70d0563..60120bcc54 100644 --- a/common/thread_flags.aconfig +++ b/common/thread_flags.aconfig @@ -35,3 +35,12 @@ flag { description: "Controls whether the Android Thread Ephemeral Key feature is enabled" bug: "348323500" } + +flag { + name: "set_nat64_configuration_enabled" + is_exported: true + is_fixed_read_only: true + namespace: "thread_network" + description: "Controls whether the setConfiguration API of NAT64 feature is enabled" + bug: "368456504" +} diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt index 09a3681f4e..08129eb8e3 100644 --- a/framework-t/api/system-current.txt +++ b/framework-t/api/system-current.txt @@ -506,6 +506,13 @@ package android.net.thread { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + @FlaggedApi("com.android.net.thread.flags.set_nat64_configuration_enabled") public static final class ThreadConfiguration.Builder { + ctor @FlaggedApi("com.android.net.thread.flags.set_nat64_configuration_enabled") public ThreadConfiguration.Builder(); + ctor @FlaggedApi("com.android.net.thread.flags.set_nat64_configuration_enabled") public ThreadConfiguration.Builder(@NonNull android.net.thread.ThreadConfiguration); + method @FlaggedApi("com.android.net.thread.flags.set_nat64_configuration_enabled") @NonNull public android.net.thread.ThreadConfiguration build(); + method @FlaggedApi("com.android.net.thread.flags.set_nat64_configuration_enabled") @NonNull public android.net.thread.ThreadConfiguration.Builder setNat64Enabled(boolean); + } + @FlaggedApi("com.android.net.thread.flags.thread_enabled") public final class ThreadNetworkController { method @FlaggedApi("com.android.net.thread.flags.epskc_enabled") @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void activateEphemeralKeyMode(@NonNull java.time.Duration, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void createRandomizedDataset(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); @@ -520,6 +527,7 @@ package android.net.thread { method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.thread.ThreadNetworkController.StateCallback); method @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void scheduleMigration(@NonNull android.net.thread.PendingOperationalDataset, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.net.thread.flags.channel_max_powers_enabled") @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void setChannelMaxPowers(@NonNull @Size(min=1) android.util.SparseIntArray, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); + method @FlaggedApi("com.android.net.thread.flags.set_nat64_configuration_enabled") @RequiresPermission(android.Manifest.permission.THREAD_NETWORK_PRIVILEGED) public void setConfiguration(@NonNull android.net.thread.ThreadConfiguration, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @RequiresPermission("android.permission.THREAD_NETWORK_PRIVILEGED") public void setEnabled(boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method @FlaggedApi("com.android.net.thread.flags.configuration_enabled") @RequiresPermission(android.Manifest.permission.THREAD_NETWORK_PRIVILEGED) public void unregisterConfigurationCallback(@NonNull java.util.function.Consumer); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_NETWORK_STATE, "android.permission.THREAD_NETWORK_PRIVILEGED"}) public void unregisterOperationalDatasetCallback(@NonNull android.net.thread.ThreadNetworkController.OperationalDatasetCallback); diff --git a/thread/framework/java/android/net/thread/ThreadConfiguration.java b/thread/framework/java/android/net/thread/ThreadConfiguration.java index 1c2553511a..e6fa1efd1e 100644 --- a/thread/framework/java/android/net/thread/ThreadConfiguration.java +++ b/thread/framework/java/android/net/thread/ThreadConfiguration.java @@ -126,18 +126,29 @@ public final class ThreadConfiguration implements Parcelable { * * @hide */ + @FlaggedApi(Flags.FLAG_SET_NAT64_CONFIGURATION_ENABLED) + @SystemApi public static final class Builder { private boolean mNat64Enabled = false; private boolean mDhcpv6PdEnabled = false; - /** Creates a new {@link Builder} object with all features disabled. */ + /** + * Creates a new {@link Builder} object with all features disabled. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_SET_NAT64_CONFIGURATION_ENABLED) + @SystemApi public Builder() {} /** * Creates a new {@link Builder} object from a {@link ThreadConfiguration} object. * * @param config the Border Router configurations to be copied + * @hide */ + @FlaggedApi(Flags.FLAG_SET_NAT64_CONFIGURATION_ENABLED) + @SystemApi public Builder(@NonNull ThreadConfiguration config) { Objects.requireNonNull(config); @@ -150,7 +161,11 @@ public final class ThreadConfiguration implements Parcelable { * *

Enabling this feature will allow Thread devices to connect to the internet/cloud over * IPv4. + * + * @hide */ + @FlaggedApi(Flags.FLAG_SET_NAT64_CONFIGURATION_ENABLED) + @SystemApi @NonNull public Builder setNat64Enabled(boolean enabled) { this.mNat64Enabled = enabled; @@ -162,6 +177,8 @@ public final class ThreadConfiguration implements Parcelable { * *

Enabling this feature will allow Thread devices to connect to the internet/cloud over * IPv6. + * + * @hide */ @NonNull public Builder setDhcpv6PdEnabled(boolean enabled) { @@ -169,7 +186,13 @@ public final class ThreadConfiguration implements Parcelable { return this; } - /** Creates a new {@link ThreadConfiguration} object. */ + /** + * Creates a new {@link ThreadConfiguration} object. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_SET_NAT64_CONFIGURATION_ENABLED) + @SystemApi @NonNull public ThreadConfiguration build() { return new ThreadConfiguration(this); diff --git a/thread/framework/java/android/net/thread/ThreadNetworkController.java b/thread/framework/java/android/net/thread/ThreadNetworkController.java index f716f9864d..6d20e13f5d 100644 --- a/thread/framework/java/android/net/thread/ThreadNetworkController.java +++ b/thread/framework/java/android/net/thread/ThreadNetworkController.java @@ -748,15 +748,19 @@ public final class ThreadNetworkController { * OutcomeReceiver#onResult} will be called, and the {@code configuration} will be applied and * persisted to the device; the configuration changes can be observed by {@link * #registerConfigurationCallback}. On failure, {@link OutcomeReceiver#onError} of {@code - * receiver} will be invoked with a specific error. + * receiver} will be invoked with a specific error: + * + *

    + *
  • {@link ThreadNetworkException#ERROR_UNSUPPORTED_FEATURE} the configuration enables a + * feature which is not supported by the platform. + *
* * @param configuration the configuration to set * @param executor the executor to execute {@code receiver} * @param receiver the receiver to receive result of this operation - * @hide */ - // @FlaggedApi(ThreadNetworkFlags.FLAG_CONFIGURATION_ENABLED) - // @RequiresPermission(permission.THREAD_NETWORK_PRIVILEGED) + @FlaggedApi(Flags.FLAG_SET_NAT64_CONFIGURATION_ENABLED) + @RequiresPermission(permission.THREAD_NETWORK_PRIVILEGED) public void setConfiguration( @NonNull ThreadConfiguration configuration, @NonNull @CallbackExecutor Executor executor, diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java index 3d854d7963..fa692b08c4 100644 --- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java +++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java @@ -220,7 +220,6 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub private boolean mUserRestricted; private boolean mForceStopOtDaemonEnabled; - private OtDaemonConfiguration mOtDaemonConfig; private InfraLinkState mInfraLinkState; @VisibleForTesting @@ -249,7 +248,6 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub // TODO: networkToLinkProperties should be shared with NsdPublisher, add a test/assert to // verify they are the same. mNetworkToLinkProperties = networkToLinkProperties; - mOtDaemonConfig = new OtDaemonConfiguration.Builder().build(); mInfraLinkState = new InfraLinkState.Builder().build(); mPersistentSettings = persistentSettings; mNsdPublisher = nsdPublisher; @@ -346,6 +344,7 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub otDaemon.initialize( mTunIfController.getTunFd(), shouldEnableThread(), + newOtDaemonConfig(mPersistentSettings.getConfiguration()), mNsdPublisher, getMeshcopTxtAttributes(mResources.get()), mOtDaemonCallbackProxy, @@ -556,22 +555,21 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub public void setConfiguration( @NonNull ThreadConfiguration configuration, @NonNull IOperationReceiver receiver) { enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED); - mHandler.post(() -> setConfigurationInternal(configuration, receiver)); + mHandler.post( + () -> + setConfigurationInternal( + configuration, new OperationReceiverWrapper(receiver))); } private void setConfigurationInternal( @NonNull ThreadConfiguration configuration, - @NonNull IOperationReceiver operationReceiver) { + @NonNull OperationReceiverWrapper receiver) { checkOnHandlerThread(); LOG.i("Set Thread configuration: " + configuration); final boolean changed = mPersistentSettings.putConfiguration(configuration); - try { - operationReceiver.onSuccess(); - } catch (RemoteException e) { - // do nothing if the client is dead - } + receiver.onSuccess(); if (changed) { for (IConfigurationReceiver configReceiver : mConfigurationReceivers.keySet()) { try { @@ -581,7 +579,22 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub } } } - // TODO: set the configuration at ot-daemon + try { + getOtDaemon() + .setConfiguration( + newOtDaemonConfig(configuration), + new LoggingOtStatusReceiver("setConfiguration")); + } catch (RemoteException | ThreadNetworkException e) { + LOG.e("otDaemon.setConfiguration failed. Config: " + configuration, e); + } + } + + private static OtDaemonConfiguration newOtDaemonConfig( + @NonNull ThreadConfiguration threadConfig) { + return new OtDaemonConfiguration.Builder() + .setNat64Enabled(threadConfig.isNat64Enabled()) + .setDhcpv6PdEnabled(threadConfig.isDhcpv6PdEnabled()) + .build(); } @Override @@ -1477,11 +1490,6 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub return builder.build(); } - private static OtDaemonConfiguration.Builder newOtDaemonConfigBuilder( - OtDaemonConfiguration config) { - return new OtDaemonConfiguration.Builder(); - } - private static InfraLinkState.Builder newInfraLinkStateBuilder() { return new InfraLinkState.Builder().setInterfaceName(""); } diff --git a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java index 1792bfb37a..07438e9a9c 100644 --- a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java +++ b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkControllerTest.java @@ -182,6 +182,7 @@ public class ThreadNetworkControllerTest { @After public void tearDown() throws Exception { dropAllPermissions(); + setEnabledAndWait(mController, true); leaveAndWait(mController); tearDownTestNetwork(); setConfigurationAndWait(mController, DEFAULT_CONFIG); @@ -1148,15 +1149,9 @@ public class ThreadNetworkControllerTest { CompletableFuture setFuture2 = new CompletableFuture<>(); ConfigurationListener listener = new ConfigurationListener(mController); ThreadConfiguration config1 = - new ThreadConfiguration.Builder() - .setNat64Enabled(true) - .setDhcpv6PdEnabled(true) - .build(); + new ThreadConfiguration.Builder().setNat64Enabled(true).build(); ThreadConfiguration config2 = - new ThreadConfiguration.Builder() - .setNat64Enabled(false) - .setDhcpv6PdEnabled(true) - .build(); + new ThreadConfiguration.Builder().setNat64Enabled(false).build(); try { runAsShell( 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 b97e2b79c9..7ac404fc1d 100644 --- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java +++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java @@ -741,10 +741,7 @@ public final class ThreadNetworkControllerServiceTest { .setDhcpv6PdEnabled(false) .build(); ThreadConfiguration config2 = - new ThreadConfiguration.Builder() - .setNat64Enabled(true) - .setDhcpv6PdEnabled(true) - .build(); + new ThreadConfiguration.Builder().setNat64Enabled(true).build(); ThreadConfiguration config3 = new ThreadConfiguration.Builder(config2).build(); // Same as config2