[Thread] add support for configuration at ThreadNetworkController
This CL adds methods for setting the ThreadConfiguration and subscribing/unsubscribing to Configuration changes. The ThreadConfiguration is used for controlling Thread features for the device. Bug: 342519412 Change-Id: I9e20391eb3b2f20312a2cb0b587cc5bdf200d24d
This commit is contained in:
parent
22db590580
commit
7520abf333
6 changed files with 343 additions and 1 deletions
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.thread;
|
||||
|
||||
import android.net.thread.ThreadConfiguration;
|
||||
|
||||
/** Receives the result of a Thread Configuration change. @hide */
|
||||
oneway interface IConfigurationReceiver {
|
||||
void onConfigurationChanged(in ThreadConfiguration configuration);
|
||||
}
|
||||
|
|
@ -19,11 +19,13 @@ package android.net.thread;
|
|||
import android.net.thread.ActiveOperationalDataset;
|
||||
import android.net.thread.ChannelMaxPower;
|
||||
import android.net.thread.IActiveOperationalDatasetReceiver;
|
||||
import android.net.thread.IOperationalDatasetCallback;
|
||||
import android.net.thread.IConfigurationReceiver;
|
||||
import android.net.thread.IOperationReceiver;
|
||||
import android.net.thread.IOperationalDatasetCallback;
|
||||
import android.net.thread.IScheduleMigrationReceiver;
|
||||
import android.net.thread.IStateCallback;
|
||||
import android.net.thread.PendingOperationalDataset;
|
||||
import android.net.thread.ThreadConfiguration;
|
||||
|
||||
/**
|
||||
* Interface for communicating with ThreadNetworkControllerService.
|
||||
|
|
@ -46,4 +48,7 @@ interface IThreadNetworkController {
|
|||
void createRandomizedDataset(String networkName, IActiveOperationalDatasetReceiver receiver);
|
||||
|
||||
void setEnabled(boolean enabled, in IOperationReceiver receiver);
|
||||
void setConfiguration(in ThreadConfiguration config, in IOperationReceiver receiver);
|
||||
void registerConfigurationCallback(in IConfigurationReceiver receiver);
|
||||
void unregisterConfigurationCallback(in IConfigurationReceiver receiver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.thread;
|
||||
|
||||
parcelable ThreadConfiguration;
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net.thread;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Data interface for Thread device configuration.
|
||||
*
|
||||
* <p>An example usage of creating a {@link ThreadConfiguration} that turns on NAT64 feature based
|
||||
* on an existing {@link ThreadConfiguration}:
|
||||
*
|
||||
* <pre>{@code
|
||||
* ThreadConfiguration config =
|
||||
* new ThreadConfiguration.Builder(existingConfig).setNat64Enabled(true).build();
|
||||
* }</pre>
|
||||
*
|
||||
* @see ThreadNetworkController#setConfiguration
|
||||
* @see ThreadNetworkController#registerConfigurationCallback
|
||||
* @see ThreadNetworkController#unregisterConfigurationCallback
|
||||
* @hide
|
||||
*/
|
||||
// @FlaggedApi(ThreadNetworkFlags.FLAG_CONFIGURATION_ENABLED)
|
||||
// @SystemApi
|
||||
public final class ThreadConfiguration implements Parcelable {
|
||||
private final boolean mNat64Enabled;
|
||||
private final boolean mDhcp6PdEnabled;
|
||||
|
||||
private ThreadConfiguration(Builder builder) {
|
||||
this(builder.mNat64Enabled, builder.mDhcp6PdEnabled);
|
||||
}
|
||||
|
||||
private ThreadConfiguration(boolean nat64Enabled, boolean dhcp6PdEnabled) {
|
||||
this.mNat64Enabled = nat64Enabled;
|
||||
this.mDhcp6PdEnabled = dhcp6PdEnabled;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if NAT64 is enabled. */
|
||||
public boolean isNat64Enabled() {
|
||||
return mNat64Enabled;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if DHCPv6 Prefix Delegation is enabled. */
|
||||
public boolean isDhcp6PdEnabled() {
|
||||
return mDhcp6PdEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
} else if (!(other instanceof ThreadConfiguration)) {
|
||||
return false;
|
||||
} else {
|
||||
ThreadConfiguration otherConfig = (ThreadConfiguration) other;
|
||||
return mNat64Enabled == otherConfig.mNat64Enabled
|
||||
&& mDhcp6PdEnabled == otherConfig.mDhcp6PdEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mNat64Enabled, mDhcp6PdEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('{');
|
||||
sb.append("Nat64Enabled=").append(mNat64Enabled);
|
||||
sb.append(", Dhcp6PdEnabled=").append(mDhcp6PdEnabled);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeBoolean(mNat64Enabled);
|
||||
dest.writeBoolean(mDhcp6PdEnabled);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<ThreadConfiguration> CREATOR =
|
||||
new Creator<>() {
|
||||
@Override
|
||||
public ThreadConfiguration createFromParcel(Parcel in) {
|
||||
ThreadConfiguration.Builder builder = new ThreadConfiguration.Builder();
|
||||
builder.setNat64Enabled(in.readBoolean());
|
||||
builder.setDhcp6PdEnabled(in.readBoolean());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadConfiguration[] newArray(int size) {
|
||||
return new ThreadConfiguration[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** The builder for creating {@link ThreadConfiguration} objects. */
|
||||
public static final class Builder {
|
||||
private boolean mNat64Enabled = false;
|
||||
private boolean mDhcp6PdEnabled = false;
|
||||
|
||||
/** Creates a new {@link Builder} object with all features disabled. */
|
||||
public Builder() {}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Builder} object from a {@link ThreadConfiguration} object.
|
||||
*
|
||||
* @param config the Border Router configurations to be copied
|
||||
*/
|
||||
public Builder(@NonNull ThreadConfiguration config) {
|
||||
Objects.requireNonNull(config);
|
||||
|
||||
mNat64Enabled = config.mNat64Enabled;
|
||||
mDhcp6PdEnabled = config.mDhcp6PdEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables NAT64 for the device.
|
||||
*
|
||||
* <p>Enabling this feature will allow Thread devices to connect to the internet/cloud over
|
||||
* IPv4.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setNat64Enabled(boolean enabled) {
|
||||
this.mNat64Enabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables Prefix Delegation for the device.
|
||||
*
|
||||
* <p>Enabling this feature will allow Thread devices to connect to the internet/cloud over
|
||||
* IPv6.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDhcp6PdEnabled(boolean enabled) {
|
||||
this.mDhcp6PdEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Creates a new {@link ThreadConfiguration} object. */
|
||||
@NonNull
|
||||
public ThreadConfiguration build() {
|
||||
return new ThreadConfiguration(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ import java.time.Duration;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Provides the primary APIs for controlling all aspects of a Thread network.
|
||||
|
|
@ -124,6 +125,12 @@ public final class ThreadNetworkController {
|
|||
private final Map<OperationalDatasetCallback, OperationalDatasetCallbackProxy>
|
||||
mOpDatasetCallbackMap = new HashMap<>();
|
||||
|
||||
private final Object mConfigurationCallbackMapLock = new Object();
|
||||
|
||||
@GuardedBy("mConfigurationCallbackMapLock")
|
||||
private final Map<Consumer<ThreadConfiguration>, ConfigurationCallbackProxy>
|
||||
mConfigurationCallbackMap = new HashMap<>();
|
||||
|
||||
/** @hide */
|
||||
public ThreadNetworkController(@NonNull IThreadNetworkController controllerService) {
|
||||
requireNonNull(controllerService, "controllerService cannot be null");
|
||||
|
|
@ -578,6 +585,97 @@ public final class ThreadNetworkController {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Thread features for this device.
|
||||
*
|
||||
* <p>This method sets the {@link ThreadConfiguration} for this device. On success, the {@link
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
public void setConfiguration(
|
||||
@NonNull ThreadConfiguration configuration,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull OutcomeReceiver<Void, ThreadNetworkException> receiver) {
|
||||
requireNonNull(configuration, "Configuration cannot be null");
|
||||
requireNonNull(executor, "executor cannot be null");
|
||||
requireNonNull(receiver, "receiver cannot be null");
|
||||
try {
|
||||
mControllerService.setConfiguration(
|
||||
configuration, new OperationReceiverProxy(executor, receiver));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback to be called when the configuration is changed.
|
||||
*
|
||||
* <p>Upon return of this method, {@code callback} will be invoked immediately with the new
|
||||
* {@link ThreadConfiguration}.
|
||||
*
|
||||
* @param executor the executor to execute the {@code callback}
|
||||
* @param callback the callback to receive Thread configuration changes
|
||||
* @throws IllegalArgumentException if {@code callback} has already been registered
|
||||
* @hide
|
||||
*/
|
||||
// @FlaggedApi(ThreadNetworkFlags.FLAG_CONFIGURATION_ENABLED)
|
||||
// @RequiresPermission(permission.THREAD_NETWORK_PRIVILEGED)
|
||||
public void registerConfigurationCallback(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<ThreadConfiguration> callback) {
|
||||
requireNonNull(executor, "executor cannot be null");
|
||||
requireNonNull(callback, "callback cannot be null");
|
||||
synchronized (mConfigurationCallbackMapLock) {
|
||||
if (mConfigurationCallbackMap.containsKey(callback)) {
|
||||
throw new IllegalArgumentException("callback has already been registered");
|
||||
}
|
||||
ConfigurationCallbackProxy callbackProxy =
|
||||
new ConfigurationCallbackProxy(executor, callback);
|
||||
mConfigurationCallbackMap.put(callback, callbackProxy);
|
||||
try {
|
||||
mControllerService.registerConfigurationCallback(callbackProxy);
|
||||
} catch (RemoteException e) {
|
||||
mConfigurationCallbackMap.remove(callback);
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the configuration callback.
|
||||
*
|
||||
* @param callback the callback which has been registered with {@link
|
||||
* #registerConfigurationCallback}
|
||||
* @throws IllegalArgumentException if {@code callback} hasn't been registered
|
||||
* @hide
|
||||
*/
|
||||
// @FlaggedApi(ThreadNetworkFlags.FLAG_CONFIGURATION_ENABLED)
|
||||
// @RequiresPermission(permission.THREAD_NETWORK_PRIVILEGED)
|
||||
public void unregisterConfigurationCallback(@NonNull Consumer<ThreadConfiguration> callback) {
|
||||
requireNonNull(callback, "callback cannot be null");
|
||||
synchronized (mConfigurationCallbackMapLock) {
|
||||
ConfigurationCallbackProxy callbackProxy = mConfigurationCallbackMap.get(callback);
|
||||
if (callbackProxy == null) {
|
||||
throw new IllegalArgumentException("callback hasn't been registered");
|
||||
}
|
||||
try {
|
||||
mControllerService.unregisterConfigurationCallback(callbackProxy);
|
||||
mConfigurationCallbackMap.remove(callbackProxy.mConfigurationConsumer);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to use a specified test network as the upstream.
|
||||
*
|
||||
|
|
@ -764,4 +862,26 @@ public final class ThreadNetworkController {
|
|||
propagateError(mExecutor, mResultReceiver, errorCode, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConfigurationCallbackProxy extends IConfigurationReceiver.Stub {
|
||||
final Executor mExecutor;
|
||||
final Consumer<ThreadConfiguration> mConfigurationConsumer;
|
||||
|
||||
ConfigurationCallbackProxy(
|
||||
@CallbackExecutor Executor executor,
|
||||
Consumer<ThreadConfiguration> ConfigurationConsumer) {
|
||||
this.mExecutor = executor;
|
||||
this.mConfigurationConsumer = ConfigurationConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(ThreadConfiguration configuration) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> mConfigurationConsumer.accept(configuration));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,5 +27,9 @@ public final class ThreadNetworkFlags {
|
|||
/** @hide */
|
||||
public static final String FLAG_THREAD_ENABLED = "com.android.net.thread.flags.thread_enabled";
|
||||
|
||||
/** @hide */
|
||||
public static final String FLAG_CONFIGURATION_ENABLED =
|
||||
"com.android.net.thread.flags.configuration_enabled";
|
||||
|
||||
private ThreadNetworkFlags() {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue