1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.android.server.thread;
16 
17 import static android.Manifest.permission.NETWORK_SETTINGS;
18 import static android.net.MulticastRoutingConfig.CONFIG_FORWARD_NONE;
19 import static android.net.MulticastRoutingConfig.FORWARD_SELECTED;
20 import static android.net.MulticastRoutingConfig.FORWARD_WITH_MIN_SCOPE;
21 import static android.net.thread.ActiveOperationalDataset.CHANNEL_PAGE_24_GHZ;
22 import static android.net.thread.ActiveOperationalDataset.LENGTH_EXTENDED_PAN_ID;
23 import static android.net.thread.ActiveOperationalDataset.LENGTH_MESH_LOCAL_PREFIX_BITS;
24 import static android.net.thread.ActiveOperationalDataset.LENGTH_NETWORK_KEY;
25 import static android.net.thread.ActiveOperationalDataset.LENGTH_PSKC;
26 import static android.net.thread.ActiveOperationalDataset.MESH_LOCAL_PREFIX_FIRST_BYTE;
27 import static android.net.thread.ActiveOperationalDataset.SecurityPolicy.DEFAULT_ROTATION_TIME_HOURS;
28 import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_DETACHED;
29 import static android.net.thread.ThreadNetworkController.STATE_DISABLED;
30 import static android.net.thread.ThreadNetworkController.STATE_DISABLING;
31 import static android.net.thread.ThreadNetworkController.STATE_ENABLED;
32 import static android.net.thread.ThreadNetworkController.THREAD_VERSION_1_3;
33 import static android.net.thread.ThreadNetworkException.ERROR_ABORTED;
34 import static android.net.thread.ThreadNetworkException.ERROR_BUSY;
35 import static android.net.thread.ThreadNetworkException.ERROR_FAILED_PRECONDITION;
36 import static android.net.thread.ThreadNetworkException.ERROR_INTERNAL_ERROR;
37 import static android.net.thread.ThreadNetworkException.ERROR_REJECTED_BY_PEER;
38 import static android.net.thread.ThreadNetworkException.ERROR_RESOURCE_EXHAUSTED;
39 import static android.net.thread.ThreadNetworkException.ERROR_RESPONSE_BAD_FORMAT;
40 import static android.net.thread.ThreadNetworkException.ERROR_THREAD_DISABLED;
41 import static android.net.thread.ThreadNetworkException.ERROR_TIMEOUT;
42 import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_CHANNEL;
43 import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_OPERATION;
44 import static android.net.thread.ThreadNetworkManager.DISALLOW_THREAD_NETWORK;
45 import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
46 
47 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_ABORT;
48 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_BUSY;
49 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_FAILED_PRECONDITION;
50 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_INVALID_STATE;
51 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_NOT_IMPLEMENTED;
52 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_NO_BUFS;
53 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_PARSE;
54 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_REASSEMBLY_TIMEOUT;
55 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_REJECTED;
56 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_RESPONSE_TIMEOUT;
57 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_THREAD_DISABLED;
58 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_UNSUPPORTED_CHANNEL;
59 import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_DISABLED;
60 import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_DISABLING;
61 import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_ENABLED;
62 import static com.android.server.thread.openthread.IOtDaemon.TUN_IF_NAME;
63 
64 import static java.nio.charset.StandardCharsets.UTF_8;
65 
66 import android.Manifest.permission;
67 import android.annotation.NonNull;
68 import android.annotation.Nullable;
69 import android.annotation.RequiresPermission;
70 import android.annotation.TargetApi;
71 import android.content.BroadcastReceiver;
72 import android.content.Context;
73 import android.content.Intent;
74 import android.content.IntentFilter;
75 import android.content.res.Resources;
76 import android.net.ConnectivityManager;
77 import android.net.InetAddresses;
78 import android.net.LinkProperties;
79 import android.net.LocalNetworkConfig;
80 import android.net.LocalNetworkInfo;
81 import android.net.MulticastRoutingConfig;
82 import android.net.Network;
83 import android.net.NetworkAgent;
84 import android.net.NetworkAgentConfig;
85 import android.net.NetworkCapabilities;
86 import android.net.NetworkProvider;
87 import android.net.NetworkRequest;
88 import android.net.NetworkScore;
89 import android.net.TestNetworkSpecifier;
90 import android.net.thread.ActiveOperationalDataset;
91 import android.net.thread.ActiveOperationalDataset.SecurityPolicy;
92 import android.net.thread.ChannelMaxPower;
93 import android.net.thread.IActiveOperationalDatasetReceiver;
94 import android.net.thread.IOperationReceiver;
95 import android.net.thread.IOperationalDatasetCallback;
96 import android.net.thread.IStateCallback;
97 import android.net.thread.IThreadNetworkController;
98 import android.net.thread.OperationalDatasetTimestamp;
99 import android.net.thread.PendingOperationalDataset;
100 import android.net.thread.ThreadNetworkController;
101 import android.net.thread.ThreadNetworkController.DeviceRole;
102 import android.net.thread.ThreadNetworkException;
103 import android.net.thread.ThreadNetworkException.ErrorCode;
104 import android.os.Build;
105 import android.os.Handler;
106 import android.os.HandlerThread;
107 import android.os.IBinder;
108 import android.os.Looper;
109 import android.os.RemoteException;
110 import android.os.SystemClock;
111 import android.os.UserManager;
112 import android.provider.Settings;
113 import android.util.Log;
114 import android.util.SparseArray;
115 
116 import com.android.connectivity.resources.R;
117 import com.android.internal.annotations.VisibleForTesting;
118 import com.android.server.ServiceManagerWrapper;
119 import com.android.server.connectivity.ConnectivityResources;
120 import com.android.server.thread.openthread.BackboneRouterState;
121 import com.android.server.thread.openthread.BorderRouterConfigurationParcel;
122 import com.android.server.thread.openthread.DnsTxtAttribute;
123 import com.android.server.thread.openthread.IChannelMasksReceiver;
124 import com.android.server.thread.openthread.IOtDaemon;
125 import com.android.server.thread.openthread.IOtDaemonCallback;
126 import com.android.server.thread.openthread.IOtStatusReceiver;
127 import com.android.server.thread.openthread.Ipv6AddressInfo;
128 import com.android.server.thread.openthread.MeshcopTxtAttributes;
129 import com.android.server.thread.openthread.OnMeshPrefixConfig;
130 import com.android.server.thread.openthread.OtDaemonState;
131 
132 import libcore.util.HexEncoding;
133 
134 import java.io.IOException;
135 import java.net.Inet6Address;
136 import java.security.SecureRandom;
137 import java.time.Clock;
138 import java.time.DateTimeException;
139 import java.time.Instant;
140 import java.util.HashMap;
141 import java.util.List;
142 import java.util.Map;
143 import java.util.Objects;
144 import java.util.Random;
145 import java.util.function.Supplier;
146 import java.util.regex.Pattern;
147 
148 /**
149  * Implementation of the {@link ThreadNetworkController} API.
150  *
151  * <p>Threading model: This class is not Thread-safe and should only be accessed from the
152  * ThreadNetworkService class. Additional attention should be paid to handle the threading code
153  * correctly: 1. All member fields other than `mHandler` and `mContext` MUST be accessed from the
154  * thread of `mHandler` 2. In the @Override methods, the actual work MUST be dispatched to the
155  * HandlerThread except for arguments or permissions checking
156  */
157 @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
158 final class ThreadNetworkControllerService extends IThreadNetworkController.Stub {
159     private static final String TAG = "ThreadNetworkService";
160 
161     // The model name length in utf-8 bytes
162     private static final int MAX_MODEL_NAME_UTF8_BYTES = 24;
163 
164     // The max vendor name length in utf-8 bytes
165     private static final int MAX_VENDOR_NAME_UTF8_BYTES = 24;
166 
167     // This regex pattern allows "XXXXXX", "XX:XX:XX" and "XX-XX-XX" OUI formats.
168     // Note that this regex allows "XX:XX-XX" as well but we don't need to be a strict checker
169     private static final String OUI_REGEX = "^([0-9A-Fa-f]{2}[:-]?){2}([0-9A-Fa-f]{2})$";
170 
171     // The channel mask that indicates all channels from channel 11 to channel 24
172     private static final int CHANNEL_MASK_11_TO_24 = 0x1FFF800;
173 
174     // Below member fields can be accessed from both the binder and handler threads
175 
176     private final Context mContext;
177     private final Handler mHandler;
178 
179     // Below member fields can only be accessed from the handler thread (`mHandler`). In
180     // particular, the constructor does not run on the handler thread, so it must not touch any of
181     // the non-final fields, nor must it mutate any of the non-final fields inside these objects.
182 
183     private final NetworkProvider mNetworkProvider;
184     private final Supplier<IOtDaemon> mOtDaemonSupplier;
185     private final ConnectivityManager mConnectivityManager;
186     private final TunInterfaceController mTunIfController;
187     private final InfraInterfaceController mInfraIfController;
188     private final NsdPublisher mNsdPublisher;
189     private final OtDaemonCallbackProxy mOtDaemonCallbackProxy = new OtDaemonCallbackProxy();
190     private final ConnectivityResources mResources;
191     private final Supplier<String> mCountryCodeSupplier;
192 
193     // This should not be directly used for calling IOtDaemon APIs because ot-daemon may die and
194     // {@code mOtDaemon} will be set to {@code null}. Instead, use {@code getOtDaemon()}
195     @Nullable private IOtDaemon mOtDaemon;
196     @Nullable private NetworkAgent mNetworkAgent;
197     @Nullable private NetworkAgent mTestNetworkAgent;
198 
199     private MulticastRoutingConfig mUpstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
200     private MulticastRoutingConfig mDownstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
201     private Network mUpstreamNetwork;
202     private NetworkRequest mUpstreamNetworkRequest;
203     private UpstreamNetworkCallback mUpstreamNetworkCallback;
204     private TestNetworkSpecifier mUpstreamTestNetworkSpecifier;
205     private final HashMap<Network, String> mNetworkToInterface;
206     private final ThreadPersistentSettings mPersistentSettings;
207     private final UserManager mUserManager;
208     private boolean mUserRestricted;
209     private boolean mAirplaneModeOn;
210     private boolean mForceStopOtDaemonEnabled;
211 
212     private BorderRouterConfigurationParcel mBorderRouterConfig;
213 
214     @VisibleForTesting
ThreadNetworkControllerService( Context context, Handler handler, NetworkProvider networkProvider, Supplier<IOtDaemon> otDaemonSupplier, ConnectivityManager connectivityManager, TunInterfaceController tunIfController, InfraInterfaceController infraIfController, ThreadPersistentSettings persistentSettings, NsdPublisher nsdPublisher, UserManager userManager, ConnectivityResources resources, Supplier<String> countryCodeSupplier)215     ThreadNetworkControllerService(
216             Context context,
217             Handler handler,
218             NetworkProvider networkProvider,
219             Supplier<IOtDaemon> otDaemonSupplier,
220             ConnectivityManager connectivityManager,
221             TunInterfaceController tunIfController,
222             InfraInterfaceController infraIfController,
223             ThreadPersistentSettings persistentSettings,
224             NsdPublisher nsdPublisher,
225             UserManager userManager,
226             ConnectivityResources resources,
227             Supplier<String> countryCodeSupplier) {
228         mContext = context;
229         mHandler = handler;
230         mNetworkProvider = networkProvider;
231         mOtDaemonSupplier = otDaemonSupplier;
232         mConnectivityManager = connectivityManager;
233         mTunIfController = tunIfController;
234         mInfraIfController = infraIfController;
235         mUpstreamNetworkRequest = newUpstreamNetworkRequest();
236         mNetworkToInterface = new HashMap<Network, String>();
237         mBorderRouterConfig = new BorderRouterConfigurationParcel();
238         mPersistentSettings = persistentSettings;
239         mNsdPublisher = nsdPublisher;
240         mUserManager = userManager;
241         mResources = resources;
242         mCountryCodeSupplier = countryCodeSupplier;
243     }
244 
newInstance( Context context, ThreadPersistentSettings persistentSettings, Supplier<String> countryCodeSupplier)245     public static ThreadNetworkControllerService newInstance(
246             Context context,
247             ThreadPersistentSettings persistentSettings,
248             Supplier<String> countryCodeSupplier) {
249         HandlerThread handlerThread = new HandlerThread("ThreadHandlerThread");
250         handlerThread.start();
251         Handler handler = new Handler(handlerThread.getLooper());
252         NetworkProvider networkProvider =
253                 new NetworkProvider(context, handlerThread.getLooper(), "ThreadNetworkProvider");
254 
255         return new ThreadNetworkControllerService(
256                 context,
257                 handler,
258                 networkProvider,
259                 () -> IOtDaemon.Stub.asInterface(ServiceManagerWrapper.waitForService("ot_daemon")),
260                 context.getSystemService(ConnectivityManager.class),
261                 new TunInterfaceController(TUN_IF_NAME),
262                 new InfraInterfaceController(),
263                 persistentSettings,
264                 NsdPublisher.newInstance(context, handler),
265                 context.getSystemService(UserManager.class),
266                 new ConnectivityResources(context),
267                 countryCodeSupplier);
268     }
269 
newUpstreamNetworkRequest()270     private NetworkRequest newUpstreamNetworkRequest() {
271         NetworkRequest.Builder builder = new NetworkRequest.Builder().clearCapabilities();
272 
273         if (mUpstreamTestNetworkSpecifier != null) {
274             return builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
275                     .setNetworkSpecifier(mUpstreamTestNetworkSpecifier)
276                     .build();
277         }
278         return builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
279                 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
280                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
281                 .build();
282     }
283 
newLocalNetworkConfig()284     private LocalNetworkConfig newLocalNetworkConfig() {
285         return new LocalNetworkConfig.Builder()
286                 .setUpstreamMulticastRoutingConfig(mUpstreamMulticastRoutingConfig)
287                 .setDownstreamMulticastRoutingConfig(mDownstreamMulticastRoutingConfig)
288                 .setUpstreamSelector(mUpstreamNetworkRequest)
289                 .build();
290     }
291 
maybeInitializeOtDaemon()292     private void maybeInitializeOtDaemon() {
293         if (!shouldEnableThread()) {
294             return;
295         }
296 
297         Log.i(TAG, "Starting OT daemon...");
298 
299         try {
300             getOtDaemon();
301         } catch (RemoteException e) {
302             Log.e(TAG, "Failed to initialize ot-daemon", e);
303         } catch (ThreadNetworkException e) {
304             // no ThreadNetworkException.ERROR_THREAD_DISABLED error should be thrown
305             throw new AssertionError(e);
306         }
307     }
308 
getOtDaemon()309     private IOtDaemon getOtDaemon() throws RemoteException, ThreadNetworkException {
310         checkOnHandlerThread();
311 
312         if (mForceStopOtDaemonEnabled) {
313             throw new ThreadNetworkException(
314                     ERROR_THREAD_DISABLED, "ot-daemon is forcibly stopped");
315         }
316 
317         if (mOtDaemon != null) {
318             return mOtDaemon;
319         }
320 
321         IOtDaemon otDaemon = mOtDaemonSupplier.get();
322         if (otDaemon == null) {
323             throw new RemoteException("Internal error: failed to start OT daemon");
324         }
325 
326         otDaemon.initialize(
327                 mTunIfController.getTunFd(),
328                 shouldEnableThread(),
329                 mNsdPublisher,
330                 getMeshcopTxtAttributes(mResources.get()),
331                 mOtDaemonCallbackProxy,
332                 mCountryCodeSupplier.get());
333         otDaemon.asBinder().linkToDeath(() -> mHandler.post(this::onOtDaemonDied), 0);
334         mOtDaemon = otDaemon;
335         return mOtDaemon;
336     }
337 
338     @VisibleForTesting
getMeshcopTxtAttributes(Resources resources)339     static MeshcopTxtAttributes getMeshcopTxtAttributes(Resources resources) {
340         final String modelName = resources.getString(R.string.config_thread_model_name);
341         final String vendorName = resources.getString(R.string.config_thread_vendor_name);
342         final String vendorOui = resources.getString(R.string.config_thread_vendor_oui);
343         final boolean managedByGoogle =
344                 resources.getBoolean(R.bool.config_thread_managed_by_google_home);
345 
346         if (!modelName.isEmpty()) {
347             if (modelName.getBytes(UTF_8).length > MAX_MODEL_NAME_UTF8_BYTES) {
348                 throw new IllegalStateException(
349                         "Model name is longer than "
350                                 + MAX_MODEL_NAME_UTF8_BYTES
351                                 + "utf-8 bytes: "
352                                 + modelName);
353             }
354         }
355 
356         if (!vendorName.isEmpty()) {
357             if (vendorName.getBytes(UTF_8).length > MAX_VENDOR_NAME_UTF8_BYTES) {
358                 throw new IllegalStateException(
359                         "Vendor name is longer than "
360                                 + MAX_VENDOR_NAME_UTF8_BYTES
361                                 + " utf-8 bytes: "
362                                 + vendorName);
363             }
364         }
365 
366         if (!vendorOui.isEmpty() && !Pattern.compile(OUI_REGEX).matcher(vendorOui).matches()) {
367             throw new IllegalStateException("Vendor OUI is invalid: " + vendorOui);
368         }
369 
370         MeshcopTxtAttributes meshcopTxts = new MeshcopTxtAttributes();
371         meshcopTxts.modelName = modelName;
372         meshcopTxts.vendorName = vendorName;
373         meshcopTxts.vendorOui = HexEncoding.decode(vendorOui.replace("-", "").replace(":", ""));
374         meshcopTxts.nonStandardTxtEntries = List.of(makeManagedByGoogleTxtAttr(managedByGoogle));
375 
376         return meshcopTxts;
377     }
378 
379     /**
380      * Creates a DNS-SD TXT entry for indicating whether Thread on this device is managed by Google.
381      *
382      * @return TXT entry "vgh=1" if {@code managedByGoogle} is {@code true}; otherwise, "vgh=0"
383      */
makeManagedByGoogleTxtAttr(boolean managedByGoogle)384     private static DnsTxtAttribute makeManagedByGoogleTxtAttr(boolean managedByGoogle) {
385         final byte[] value = (managedByGoogle ? "1" : "0").getBytes(UTF_8);
386         return new DnsTxtAttribute("vgh", value);
387     }
388 
onOtDaemonDied()389     private void onOtDaemonDied() {
390         checkOnHandlerThread();
391         Log.w(TAG, "OT daemon is dead, clean up...");
392 
393         OperationReceiverWrapper.onOtDaemonDied();
394         mOtDaemonCallbackProxy.onOtDaemonDied();
395         mTunIfController.onOtDaemonDied();
396         mNsdPublisher.onOtDaemonDied();
397         mOtDaemon = null;
398         maybeInitializeOtDaemon();
399     }
400 
initialize()401     public void initialize() {
402         mHandler.post(
403                 () -> {
404                     Log.d(
405                             TAG,
406                             "Initializing Thread system service: Thread is "
407                                     + (shouldEnableThread() ? "enabled" : "disabled"));
408                     try {
409                         mTunIfController.createTunInterface();
410                     } catch (IOException e) {
411                         throw new IllegalStateException(
412                                 "Failed to create Thread tunnel interface", e);
413                     }
414                     mConnectivityManager.registerNetworkProvider(mNetworkProvider);
415                     requestUpstreamNetwork();
416                     requestThreadNetwork();
417                     mUserRestricted = isThreadUserRestricted();
418                     registerUserRestrictionsReceiver();
419                     mAirplaneModeOn = isAirplaneModeOn();
420                     registerAirplaneModeReceiver();
421                     maybeInitializeOtDaemon();
422                 });
423     }
424 
425     /**
426      * Force stops ot-daemon immediately and prevents ot-daemon from being restarted by
427      * system_server again.
428      *
429      * <p>This is for VTS testing only.
430      */
431     @RequiresPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
forceStopOtDaemonForTest(boolean enabled, @NonNull IOperationReceiver receiver)432     void forceStopOtDaemonForTest(boolean enabled, @NonNull IOperationReceiver receiver) {
433         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
434 
435         mHandler.post(
436                 () ->
437                         forceStopOtDaemonForTestInternal(
438                                 enabled,
439                                 new OperationReceiverWrapper(
440                                         receiver, true /* expectOtDaemonDied */)));
441     }
442 
forceStopOtDaemonForTestInternal( boolean enabled, @NonNull OperationReceiverWrapper receiver)443     private void forceStopOtDaemonForTestInternal(
444             boolean enabled, @NonNull OperationReceiverWrapper receiver) {
445         checkOnHandlerThread();
446         if (enabled == mForceStopOtDaemonEnabled) {
447             receiver.onSuccess();
448             return;
449         }
450 
451         if (!enabled) {
452             mForceStopOtDaemonEnabled = false;
453             maybeInitializeOtDaemon();
454             receiver.onSuccess();
455             return;
456         }
457 
458         try {
459             getOtDaemon().terminate();
460             // Do not invoke the {@code receiver} callback here but wait for ot-daemon to
461             // become dead, so that it's guaranteed that ot-daemon is stopped when {@code
462             // receiver} is completed
463         } catch (RemoteException e) {
464             Log.e(TAG, "otDaemon.terminate failed", e);
465             receiver.onError(ERROR_INTERNAL_ERROR, "Thread stack error");
466         } catch (ThreadNetworkException e) {
467             // No ThreadNetworkException.ERROR_THREAD_DISABLED error will be thrown
468             throw new AssertionError(e);
469         } finally {
470             mForceStopOtDaemonEnabled = true;
471         }
472     }
473 
setEnabled(boolean isEnabled, @NonNull IOperationReceiver receiver)474     public void setEnabled(boolean isEnabled, @NonNull IOperationReceiver receiver) {
475         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
476 
477         mHandler.post(
478                 () ->
479                         setEnabledInternal(
480                                 isEnabled,
481                                 true /* persist */,
482                                 new OperationReceiverWrapper(receiver)));
483     }
484 
setEnabledInternal( boolean isEnabled, boolean persist, @NonNull OperationReceiverWrapper receiver)485     private void setEnabledInternal(
486             boolean isEnabled, boolean persist, @NonNull OperationReceiverWrapper receiver) {
487         checkOnHandlerThread();
488         if (isEnabled && isThreadUserRestricted()) {
489             receiver.onError(
490                     ERROR_FAILED_PRECONDITION,
491                     "Cannot enable Thread: forbidden by user restriction");
492             return;
493         }
494 
495         Log.i(TAG, "Set Thread enabled: " + isEnabled + ", persist: " + persist);
496 
497         if (persist) {
498             // The persistent setting keeps the desired enabled state, thus it's set regardless
499             // the otDaemon set enabled state operation succeeded or not, so that it can recover
500             // to the desired value after reboot.
501             mPersistentSettings.put(ThreadPersistentSettings.THREAD_ENABLED.key, isEnabled);
502 
503             // Remember whether the user wanted to keep Thread enabled in airplane mode. If once
504             // the user disabled Thread again in airplane mode, the persistent settings state is
505             // reset (so that Thread will be auto-disabled again when airplane mode is turned on).
506             // This behavior is consistent with Wi-Fi and bluetooth.
507             if (mAirplaneModeOn) {
508                 mPersistentSettings.put(
509                         ThreadPersistentSettings.THREAD_ENABLED_IN_AIRPLANE_MODE.key, isEnabled);
510             }
511         }
512 
513         try {
514             getOtDaemon().setThreadEnabled(isEnabled, newOtStatusReceiver(receiver));
515         } catch (RemoteException | ThreadNetworkException e) {
516             Log.e(TAG, "otDaemon.setThreadEnabled failed", e);
517             receiver.onError(e);
518         }
519     }
520 
registerUserRestrictionsReceiver()521     private void registerUserRestrictionsReceiver() {
522         mContext.registerReceiver(
523                 new BroadcastReceiver() {
524                     @Override
525                     public void onReceive(Context context, Intent intent) {
526                         onUserRestrictionsChanged(isThreadUserRestricted());
527                     }
528                 },
529                 new IntentFilter(UserManager.ACTION_USER_RESTRICTIONS_CHANGED),
530                 null /* broadcastPermission */,
531                 mHandler);
532     }
533 
onUserRestrictionsChanged(boolean newUserRestrictedState)534     private void onUserRestrictionsChanged(boolean newUserRestrictedState) {
535         checkOnHandlerThread();
536         if (mUserRestricted == newUserRestrictedState) {
537             return;
538         }
539         Log.i(
540                 TAG,
541                 "Thread user restriction changed: "
542                         + mUserRestricted
543                         + " -> "
544                         + newUserRestrictedState);
545         mUserRestricted = newUserRestrictedState;
546 
547         final boolean shouldEnableThread = shouldEnableThread();
548         final IOperationReceiver receiver =
549                 new IOperationReceiver.Stub() {
550                     @Override
551                     public void onSuccess() {
552                         Log.d(
553                                 TAG,
554                                 (shouldEnableThread ? "Enabled" : "Disabled")
555                                         + " Thread due to user restriction change");
556                     }
557 
558                     @Override
559                     public void onError(int errorCode, String errorMessage) {
560                         Log.e(
561                                 TAG,
562                                 "Failed to "
563                                         + (shouldEnableThread ? "enable" : "disable")
564                                         + " Thread for user restriction change");
565                     }
566                 };
567         // Do not save the user restriction state to persistent settings so that the user
568         // configuration won't be overwritten
569         setEnabledInternal(
570                 shouldEnableThread, false /* persist */, new OperationReceiverWrapper(receiver));
571     }
572 
573     /** Returns {@code true} if Thread has been restricted for the user. */
isThreadUserRestricted()574     private boolean isThreadUserRestricted() {
575         return mUserManager.hasUserRestriction(DISALLOW_THREAD_NETWORK);
576     }
577 
registerAirplaneModeReceiver()578     private void registerAirplaneModeReceiver() {
579         mContext.registerReceiver(
580                 new BroadcastReceiver() {
581                     @Override
582                     public void onReceive(Context context, Intent intent) {
583                         onAirplaneModeChanged(isAirplaneModeOn());
584                     }
585                 },
586                 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED),
587                 null /* broadcastPermission */,
588                 mHandler);
589     }
590 
onAirplaneModeChanged(boolean newAirplaneModeOn)591     private void onAirplaneModeChanged(boolean newAirplaneModeOn) {
592         checkOnHandlerThread();
593         if (mAirplaneModeOn == newAirplaneModeOn) {
594             return;
595         }
596         Log.i(TAG, "Airplane mode changed: " + mAirplaneModeOn + " -> " + newAirplaneModeOn);
597         mAirplaneModeOn = newAirplaneModeOn;
598 
599         final boolean shouldEnableThread = shouldEnableThread();
600         final IOperationReceiver receiver =
601                 new IOperationReceiver.Stub() {
602                     @Override
603                     public void onSuccess() {
604                         Log.d(
605                                 TAG,
606                                 (shouldEnableThread ? "Enabled" : "Disabled")
607                                         + " Thread due to airplane mode change");
608                     }
609 
610                     @Override
611                     public void onError(int errorCode, String errorMessage) {
612                         Log.e(
613                                 TAG,
614                                 "Failed to "
615                                         + (shouldEnableThread ? "enable" : "disable")
616                                         + " Thread for airplane mode change");
617                     }
618                 };
619         // Do not save the user restriction state to persistent settings so that the user
620         // configuration won't be overwritten
621         setEnabledInternal(
622                 shouldEnableThread, false /* persist */, new OperationReceiverWrapper(receiver));
623     }
624 
625     /** Returns {@code true} if Airplane mode has been turned on. */
isAirplaneModeOn()626     private boolean isAirplaneModeOn() {
627         return Settings.Global.getInt(
628                         mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0)
629                 == 1;
630     }
631 
632     /**
633      * Returns {@code true} if Thread should be enabled based on current settings, runtime user
634      * restriction and airplane mode state.
635      */
shouldEnableThread()636     private boolean shouldEnableThread() {
637         final boolean enabledInAirplaneMode =
638                 mPersistentSettings.get(ThreadPersistentSettings.THREAD_ENABLED_IN_AIRPLANE_MODE);
639 
640         return !mForceStopOtDaemonEnabled
641                 && !mUserRestricted
642                 // FIXME(b/340744397): Note that here we need to call `isAirplaneModeOn()` to get
643                 // the latest state of airplane mode but can't use `mIsAirplaneMode`. This is for
644                 // avoiding the race conditions described in b/340744397
645                 && (!isAirplaneModeOn() || enabledInAirplaneMode)
646                 && mPersistentSettings.get(ThreadPersistentSettings.THREAD_ENABLED);
647     }
648 
requestUpstreamNetwork()649     private void requestUpstreamNetwork() {
650         if (mUpstreamNetworkCallback != null) {
651             throw new AssertionError("The upstream network request is already there.");
652         }
653         mUpstreamNetworkCallback = new UpstreamNetworkCallback();
654         mConnectivityManager.registerNetworkCallback(
655                 mUpstreamNetworkRequest, mUpstreamNetworkCallback, mHandler);
656     }
657 
cancelRequestUpstreamNetwork()658     private void cancelRequestUpstreamNetwork() {
659         if (mUpstreamNetworkCallback == null) {
660             throw new AssertionError("The upstream network request null.");
661         }
662         mNetworkToInterface.clear();
663         mConnectivityManager.unregisterNetworkCallback(mUpstreamNetworkCallback);
664         mUpstreamNetworkCallback = null;
665     }
666 
667     private final class UpstreamNetworkCallback extends ConnectivityManager.NetworkCallback {
668         @Override
onAvailable(@onNull Network network)669         public void onAvailable(@NonNull Network network) {
670             checkOnHandlerThread();
671             Log.i(TAG, "Upstream network available: " + network);
672         }
673 
674         @Override
onLost(@onNull Network network)675         public void onLost(@NonNull Network network) {
676             checkOnHandlerThread();
677             Log.i(TAG, "Upstream network lost: " + network);
678 
679             // TODO: disable border routing when upsteam network disconnected
680         }
681 
682         @Override
onLinkPropertiesChanged( @onNull Network network, @NonNull LinkProperties linkProperties)683         public void onLinkPropertiesChanged(
684                 @NonNull Network network, @NonNull LinkProperties linkProperties) {
685             checkOnHandlerThread();
686 
687             String existingIfName = mNetworkToInterface.get(network);
688             String newIfName = linkProperties.getInterfaceName();
689             if (Objects.equals(existingIfName, newIfName)) {
690                 return;
691             }
692             Log.i(TAG, "Upstream network changed: " + existingIfName + " -> " + newIfName);
693             mNetworkToInterface.put(network, newIfName);
694 
695             // TODO: disable border routing if netIfName is null
696             if (network.equals(mUpstreamNetwork)) {
697                 enableBorderRouting(mNetworkToInterface.get(mUpstreamNetwork));
698             }
699         }
700     }
701 
702     private final class ThreadNetworkCallback extends ConnectivityManager.NetworkCallback {
703         @Override
onAvailable(@onNull Network network)704         public void onAvailable(@NonNull Network network) {
705             checkOnHandlerThread();
706             Log.i(TAG, "Thread network is available: " + network);
707         }
708 
709         @Override
onLost(@onNull Network network)710         public void onLost(@NonNull Network network) {
711             checkOnHandlerThread();
712             Log.i(TAG, "Thread network is lost: " + network);
713             disableBorderRouting();
714         }
715 
716         @Override
onLocalNetworkInfoChanged( @onNull Network network, @NonNull LocalNetworkInfo localNetworkInfo)717         public void onLocalNetworkInfoChanged(
718                 @NonNull Network network, @NonNull LocalNetworkInfo localNetworkInfo) {
719             checkOnHandlerThread();
720             Log.i(
721                     TAG,
722                     "LocalNetworkInfo of Thread network changed: {threadNetwork: "
723                             + network
724                             + ", localNetworkInfo: "
725                             + localNetworkInfo
726                             + "}");
727             if (localNetworkInfo.getUpstreamNetwork() == null) {
728                 disableBorderRouting();
729                 return;
730             }
731             if (!localNetworkInfo.getUpstreamNetwork().equals(mUpstreamNetwork)) {
732                 mUpstreamNetwork = localNetworkInfo.getUpstreamNetwork();
733                 if (mNetworkToInterface.containsKey(mUpstreamNetwork)) {
734                     enableBorderRouting(mNetworkToInterface.get(mUpstreamNetwork));
735                 }
736                 mNsdPublisher.setNetworkForHostResolution(mUpstreamNetwork);
737             }
738         }
739     }
740 
requestThreadNetwork()741     private void requestThreadNetwork() {
742         mConnectivityManager.registerNetworkCallback(
743                 new NetworkRequest.Builder()
744                         // clearCapabilities() is needed to remove forbidden capabilities and UID
745                         // requirement.
746                         .clearCapabilities()
747                         .addTransportType(NetworkCapabilities.TRANSPORT_THREAD)
748                         .addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)
749                         .build(),
750                 new ThreadNetworkCallback(),
751                 mHandler);
752     }
753 
754     /** Injects a {@link NetworkAgent} for testing. */
755     @VisibleForTesting
setTestNetworkAgent(@ullable NetworkAgent testNetworkAgent)756     void setTestNetworkAgent(@Nullable NetworkAgent testNetworkAgent) {
757         mTestNetworkAgent = testNetworkAgent;
758     }
759 
newNetworkAgent()760     private NetworkAgent newNetworkAgent() {
761         if (mTestNetworkAgent != null) {
762             return mTestNetworkAgent;
763         }
764 
765         final NetworkCapabilities netCaps =
766                 new NetworkCapabilities.Builder()
767                         .addTransportType(NetworkCapabilities.TRANSPORT_THREAD)
768                         .addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)
769                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
770                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
771                         .build();
772         final NetworkScore score =
773                 new NetworkScore.Builder()
774                         .setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_LOCAL_NETWORK)
775                         .build();
776         return new NetworkAgent(
777                 mContext,
778                 mHandler.getLooper(),
779                 TAG,
780                 netCaps,
781                 mTunIfController.getLinkProperties(),
782                 newLocalNetworkConfig(),
783                 score,
784                 new NetworkAgentConfig.Builder().build(),
785                 mNetworkProvider) {};
786     }
787 
registerThreadNetwork()788     private void registerThreadNetwork() {
789         if (mNetworkAgent != null) {
790             return;
791         }
792 
793         mNetworkAgent = newNetworkAgent();
794         mNetworkAgent.register();
795         mNetworkAgent.markConnected();
796         Log.i(TAG, "Registered Thread network");
797     }
798 
unregisterThreadNetwork()799     private void unregisterThreadNetwork() {
800         if (mNetworkAgent == null) {
801             // unregisterThreadNetwork can be called every time this device becomes detached or
802             // disabled and the mNetworkAgent may not be created in this cases
803             return;
804         }
805 
806         Log.d(TAG, "Unregistering Thread network agent");
807 
808         mNetworkAgent.unregister();
809         mNetworkAgent = null;
810     }
811 
812     @Override
getThreadVersion()813     public int getThreadVersion() {
814         return THREAD_VERSION_1_3;
815     }
816 
817     @Override
createRandomizedDataset( String networkName, IActiveOperationalDatasetReceiver receiver)818     public void createRandomizedDataset(
819             String networkName, IActiveOperationalDatasetReceiver receiver) {
820         ActiveOperationalDatasetReceiverWrapper receiverWrapper =
821                 new ActiveOperationalDatasetReceiverWrapper(receiver);
822         mHandler.post(() -> createRandomizedDatasetInternal(networkName, receiverWrapper));
823     }
824 
createRandomizedDatasetInternal( String networkName, @NonNull ActiveOperationalDatasetReceiverWrapper receiver)825     private void createRandomizedDatasetInternal(
826             String networkName, @NonNull ActiveOperationalDatasetReceiverWrapper receiver) {
827         checkOnHandlerThread();
828 
829         try {
830             getOtDaemon().getChannelMasks(newChannelMasksReceiver(networkName, receiver));
831         } catch (RemoteException | ThreadNetworkException e) {
832             Log.e(TAG, "otDaemon.getChannelMasks failed", e);
833             receiver.onError(e);
834         }
835     }
836 
newChannelMasksReceiver( String networkName, ActiveOperationalDatasetReceiverWrapper receiver)837     private IChannelMasksReceiver newChannelMasksReceiver(
838             String networkName, ActiveOperationalDatasetReceiverWrapper receiver) {
839         return new IChannelMasksReceiver.Stub() {
840             @Override
841             public void onSuccess(int supportedChannelMask, int preferredChannelMask) {
842                 ActiveOperationalDataset dataset =
843                         createRandomizedDataset(
844                                 networkName,
845                                 supportedChannelMask,
846                                 preferredChannelMask,
847                                 new Random(),
848                                 new SecureRandom());
849 
850                 receiver.onSuccess(dataset);
851             }
852 
853             @Override
854             public void onError(int errorCode, String errorMessage) {
855                 receiver.onError(otErrorToAndroidError(errorCode), errorMessage);
856             }
857         };
858     }
859 
860     private static ActiveOperationalDataset createRandomizedDataset(
861             String networkName,
862             int supportedChannelMask,
863             int preferredChannelMask,
864             Random random,
865             SecureRandom secureRandom) {
866         boolean authoritative = false;
867         Instant now = Instant.now();
868         try {
869             Clock clock = SystemClock.currentNetworkTimeClock();
870             now = clock.instant();
871             authoritative = true;
872         } catch (DateTimeException e) {
873             Log.w(TAG, "Failed to get authoritative time", e);
874         }
875 
876         int panId = random.nextInt(/* bound= */ 0xffff);
877         final byte[] meshLocalPrefix = newRandomBytes(random, LENGTH_MESH_LOCAL_PREFIX_BITS / 8);
878         meshLocalPrefix[0] = MESH_LOCAL_PREFIX_FIRST_BYTE;
879 
880         final SparseArray<byte[]> channelMask = new SparseArray<>(1);
881         channelMask.put(CHANNEL_PAGE_24_GHZ, channelMaskToByteArray(supportedChannelMask));
882         final int channel = selectChannel(supportedChannelMask, preferredChannelMask, random);
883 
884         final byte[] securityFlags = new byte[] {(byte) 0xff, (byte) 0xf8};
885 
886         return new ActiveOperationalDataset.Builder()
887                 .setActiveTimestamp(
888                         new OperationalDatasetTimestamp(
889                                 now.getEpochSecond() & 0xffffffffffffL, 0, authoritative))
890                 .setExtendedPanId(newRandomBytes(random, LENGTH_EXTENDED_PAN_ID))
891                 .setPanId(panId)
892                 .setNetworkName(networkName)
893                 .setChannel(CHANNEL_PAGE_24_GHZ, channel)
894                 .setChannelMask(channelMask)
895                 .setPskc(newRandomBytes(secureRandom, LENGTH_PSKC))
896                 .setNetworkKey(newRandomBytes(secureRandom, LENGTH_NETWORK_KEY))
897                 .setMeshLocalPrefix(meshLocalPrefix)
898                 .setSecurityPolicy(new SecurityPolicy(DEFAULT_ROTATION_TIME_HOURS, securityFlags))
899                 .build();
900     }
901 
902     private static int selectChannel(
903             int supportedChannelMask, int preferredChannelMask, Random random) {
904         // Due to radio hardware performance reasons, many Thread radio chips need to reduce their
905         // transmit power on edge channels to pass regulatory RF certification. Thread edge channel
906         // 25 and 26 are not preferred here.
907         //
908         // If users want to use channel 25 or 26, they can change the channel via the method
909         // ActiveOperationalDataset.Builder(activeOperationalDataset).setChannel(channel).build().
910         preferredChannelMask = preferredChannelMask & CHANNEL_MASK_11_TO_24;
911 
912         // If the preferred channel mask is not empty, select a random channel from it, otherwise
913         // choose one from the supported channel mask.
914         preferredChannelMask = preferredChannelMask & supportedChannelMask;
915         if (preferredChannelMask == 0) {
916             preferredChannelMask = supportedChannelMask;
917         }
918 
919         return selectRandomChannel(preferredChannelMask, random);
920     }
921 
922     private static byte[] newRandomBytes(Random random, int length) {
923         byte[] result = new byte[length];
924         random.nextBytes(result);
925         return result;
926     }
927 
928     private static byte[] channelMaskToByteArray(int channelMask) {
929         // Per Thread spec, a Channel Mask is:
930         // A variable-length bit mask that identifies the channels within the channel page
931         // (1 = selected, 0 = unselected). The channels are represented in most significant bit
932         // order. For example, the most significant bit of the left-most byte indicates channel 0.
933         // If channel 0 and channel 10 are selected, the mask would be: 80 20 00 00. For IEEE
934         // 802.15.4-2006 2.4 GHz PHY, the ChannelMask is 27 bits and MaskLength is 4.
935         //
936         // The pass-in channelMask represents a channel K by (channelMask & (1 << K)), so here
937         // needs to do bit-wise reverse to convert it to the Thread spec format in bytes.
938         channelMask = Integer.reverse(channelMask);
939         return new byte[] {
940             (byte) (channelMask >>> 24),
941             (byte) (channelMask >>> 16),
942             (byte) (channelMask >>> 8),
943             (byte) channelMask
944         };
945     }
946 
947     private static int selectRandomChannel(int supportedChannelMask, Random random) {
948         int num = random.nextInt(Integer.bitCount(supportedChannelMask));
949         for (int i = 0; i < 32; i++) {
950             if ((supportedChannelMask & 1) == 1 && (num--) == 0) {
951                 return i;
952             }
953             supportedChannelMask >>>= 1;
954         }
955         return -1;
956     }
957 
958     private void enforceAllPermissionsGranted(String... permissions) {
959         for (String permission : permissions) {
960             mContext.enforceCallingOrSelfPermission(
961                     permission, "Permission " + permission + " is missing");
962         }
963     }
964 
965     @Override
966     public void registerStateCallback(IStateCallback stateCallback) throws RemoteException {
967         enforceAllPermissionsGranted(permission.ACCESS_NETWORK_STATE);
968         mHandler.post(() -> mOtDaemonCallbackProxy.registerStateCallback(stateCallback));
969     }
970 
971     @Override
972     public void unregisterStateCallback(IStateCallback stateCallback) throws RemoteException {
973         enforceAllPermissionsGranted(permission.ACCESS_NETWORK_STATE);
974         mHandler.post(() -> mOtDaemonCallbackProxy.unregisterStateCallback(stateCallback));
975     }
976 
977     @Override
978     public void registerOperationalDatasetCallback(IOperationalDatasetCallback callback)
979             throws RemoteException {
980         enforceAllPermissionsGranted(
981                 permission.ACCESS_NETWORK_STATE, PERMISSION_THREAD_NETWORK_PRIVILEGED);
982         mHandler.post(() -> mOtDaemonCallbackProxy.registerDatasetCallback(callback));
983     }
984 
985     @Override
986     public void unregisterOperationalDatasetCallback(IOperationalDatasetCallback callback)
987             throws RemoteException {
988         enforceAllPermissionsGranted(
989                 permission.ACCESS_NETWORK_STATE, PERMISSION_THREAD_NETWORK_PRIVILEGED);
990         mHandler.post(() -> mOtDaemonCallbackProxy.unregisterDatasetCallback(callback));
991     }
992 
993     private void checkOnHandlerThread() {
994         if (Looper.myLooper() != mHandler.getLooper()) {
995             throw new IllegalStateException(
996                     "Not running on ThreadNetworkControllerService thread ("
997                             + mHandler.getLooper()
998                             + ") : "
999                             + Looper.myLooper());
1000         }
1001     }
1002 
1003     private IOtStatusReceiver newOtStatusReceiver(OperationReceiverWrapper receiver) {
1004         return new IOtStatusReceiver.Stub() {
1005             @Override
1006             public void onSuccess() {
1007                 receiver.onSuccess();
1008             }
1009 
1010             @Override
1011             public void onError(int otError, String message) {
1012                 receiver.onError(otErrorToAndroidError(otError), message);
1013             }
1014         };
1015     }
1016 
1017     @ErrorCode
1018     private static int otErrorToAndroidError(int otError) {
1019         // See external/openthread/include/openthread/error.h for OT error definition
1020         switch (otError) {
1021             case OT_ERROR_ABORT:
1022                 return ERROR_ABORTED;
1023             case OT_ERROR_BUSY:
1024                 return ERROR_BUSY;
1025             case OT_ERROR_NOT_IMPLEMENTED:
1026                 return ERROR_UNSUPPORTED_OPERATION;
1027             case OT_ERROR_NO_BUFS:
1028                 return ERROR_RESOURCE_EXHAUSTED;
1029             case OT_ERROR_PARSE:
1030                 return ERROR_RESPONSE_BAD_FORMAT;
1031             case OT_ERROR_REASSEMBLY_TIMEOUT:
1032             case OT_ERROR_RESPONSE_TIMEOUT:
1033                 return ERROR_TIMEOUT;
1034             case OT_ERROR_REJECTED:
1035                 return ERROR_REJECTED_BY_PEER;
1036             case OT_ERROR_UNSUPPORTED_CHANNEL:
1037                 return ERROR_UNSUPPORTED_CHANNEL;
1038             case OT_ERROR_THREAD_DISABLED:
1039                 return ERROR_THREAD_DISABLED;
1040             case OT_ERROR_FAILED_PRECONDITION:
1041                 return ERROR_FAILED_PRECONDITION;
1042             case OT_ERROR_INVALID_STATE:
1043             default:
1044                 return ERROR_INTERNAL_ERROR;
1045         }
1046     }
1047 
1048     @Override
1049     public void join(
1050             @NonNull ActiveOperationalDataset activeDataset, @NonNull IOperationReceiver receiver) {
1051         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1052 
1053         OperationReceiverWrapper receiverWrapper = new OperationReceiverWrapper(receiver);
1054         mHandler.post(() -> joinInternal(activeDataset, receiverWrapper));
1055     }
1056 
1057     private void joinInternal(
1058             @NonNull ActiveOperationalDataset activeDataset,
1059             @NonNull OperationReceiverWrapper receiver) {
1060         checkOnHandlerThread();
1061 
1062         try {
1063             // The otDaemon.join() will leave first if this device is currently attached
1064             getOtDaemon().join(activeDataset.toThreadTlvs(), newOtStatusReceiver(receiver));
1065         } catch (RemoteException | ThreadNetworkException e) {
1066             Log.e(TAG, "otDaemon.join failed", e);
1067             receiver.onError(e);
1068         }
1069     }
1070 
1071     @Override
1072     public void scheduleMigration(
1073             @NonNull PendingOperationalDataset pendingDataset,
1074             @NonNull IOperationReceiver receiver) {
1075         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1076 
1077         OperationReceiverWrapper receiverWrapper = new OperationReceiverWrapper(receiver);
1078         mHandler.post(() -> scheduleMigrationInternal(pendingDataset, receiverWrapper));
1079     }
1080 
1081     public void scheduleMigrationInternal(
1082             @NonNull PendingOperationalDataset pendingDataset,
1083             @NonNull OperationReceiverWrapper receiver) {
1084         checkOnHandlerThread();
1085 
1086         try {
1087             getOtDaemon()
1088                     .scheduleMigration(
1089                             pendingDataset.toThreadTlvs(), newOtStatusReceiver(receiver));
1090         } catch (RemoteException | ThreadNetworkException e) {
1091             Log.e(TAG, "otDaemon.scheduleMigration failed", e);
1092             receiver.onError(e);
1093         }
1094     }
1095 
1096     @Override
1097     public void leave(@NonNull IOperationReceiver receiver) {
1098         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1099 
1100         mHandler.post(() -> leaveInternal(new OperationReceiverWrapper(receiver)));
1101     }
1102 
1103     private void leaveInternal(@NonNull OperationReceiverWrapper receiver) {
1104         checkOnHandlerThread();
1105 
1106         try {
1107             getOtDaemon().leave(newOtStatusReceiver(receiver));
1108         } catch (RemoteException | ThreadNetworkException e) {
1109             Log.e(TAG, "otDaemon.leave failed", e);
1110             receiver.onError(e);
1111         }
1112     }
1113 
1114     /**
1115      * Sets the country code.
1116      *
1117      * @param countryCode 2 characters string country code (as defined in ISO 3166) to set.
1118      * @param receiver the receiver to receive result of this operation
1119      */
1120     @RequiresPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
1121     public void setCountryCode(@NonNull String countryCode, @NonNull IOperationReceiver receiver) {
1122         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1123 
1124         OperationReceiverWrapper receiverWrapper = new OperationReceiverWrapper(receiver);
1125         mHandler.post(() -> setCountryCodeInternal(countryCode, receiverWrapper));
1126     }
1127 
1128     private void setCountryCodeInternal(
1129             String countryCode, @NonNull OperationReceiverWrapper receiver) {
1130         checkOnHandlerThread();
1131 
1132         // Fails early to avoid waking up ot-daemon by the ThreadNetworkCountryCode class
1133         if (!shouldEnableThread()) {
1134             receiver.onError(
1135                     ERROR_THREAD_DISABLED, "Can't set country code when Thread is disabled");
1136             return;
1137         }
1138 
1139         try {
1140             getOtDaemon().setCountryCode(countryCode, newOtStatusReceiver(receiver));
1141         } catch (RemoteException | ThreadNetworkException e) {
1142             Log.e(TAG, "otDaemon.setCountryCode failed", e);
1143             receiver.onError(e);
1144         }
1145     }
1146 
1147     @Override
1148     public void setTestNetworkAsUpstream(
1149             @Nullable String testNetworkInterfaceName, @NonNull IOperationReceiver receiver) {
1150         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED, NETWORK_SETTINGS);
1151 
1152         Log.i(TAG, "setTestNetworkAsUpstream: " + testNetworkInterfaceName);
1153         mHandler.post(() -> setTestNetworkAsUpstreamInternal(testNetworkInterfaceName, receiver));
1154     }
1155 
1156     private void setTestNetworkAsUpstreamInternal(
1157             @Nullable String testNetworkInterfaceName, @NonNull IOperationReceiver receiver) {
1158         checkOnHandlerThread();
1159 
1160         TestNetworkSpecifier testNetworkSpecifier = null;
1161         if (testNetworkInterfaceName != null) {
1162             testNetworkSpecifier = new TestNetworkSpecifier(testNetworkInterfaceName);
1163         }
1164 
1165         if (!Objects.equals(mUpstreamTestNetworkSpecifier, testNetworkSpecifier)) {
1166             cancelRequestUpstreamNetwork();
1167             mUpstreamTestNetworkSpecifier = testNetworkSpecifier;
1168             mUpstreamNetworkRequest = newUpstreamNetworkRequest();
1169             requestUpstreamNetwork();
1170             sendLocalNetworkConfig();
1171         }
1172         try {
1173             receiver.onSuccess();
1174         } catch (RemoteException ignored) {
1175             // do nothing if the client is dead
1176         }
1177     }
1178 
1179     @RequiresPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
1180     public void setChannelMaxPowers(
1181             @NonNull ChannelMaxPower[] channelMaxPowers, @NonNull IOperationReceiver receiver) {
1182         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1183 
1184         mHandler.post(
1185                 () ->
1186                         setChannelMaxPowersInternal(
1187                                 channelMaxPowers, new OperationReceiverWrapper(receiver)));
1188     }
1189 
1190     private void setChannelMaxPowersInternal(
1191             @NonNull ChannelMaxPower[] channelMaxPowers,
1192             @NonNull OperationReceiverWrapper receiver) {
1193         checkOnHandlerThread();
1194 
1195         try {
1196             getOtDaemon().setChannelMaxPowers(channelMaxPowers, newOtStatusReceiver(receiver));
1197         } catch (RemoteException | ThreadNetworkException e) {
1198             Log.e(TAG, "otDaemon.setChannelMaxPowers failed", e);
1199             receiver.onError(ERROR_INTERNAL_ERROR, "Thread stack error");
1200         }
1201     }
1202 
1203     private void enableBorderRouting(String infraIfName) {
1204         if (mBorderRouterConfig.isBorderRoutingEnabled
1205                 && infraIfName.equals(mBorderRouterConfig.infraInterfaceName)) {
1206             return;
1207         }
1208         Log.i(TAG, "Enable border routing on AIL: " + infraIfName);
1209         try {
1210             mBorderRouterConfig.infraInterfaceName = infraIfName;
1211             mBorderRouterConfig.infraInterfaceIcmp6Socket =
1212                     mInfraIfController.createIcmp6Socket(infraIfName);
1213             mBorderRouterConfig.isBorderRoutingEnabled = true;
1214 
1215             getOtDaemon()
1216                     .configureBorderRouter(
1217                             mBorderRouterConfig, new ConfigureBorderRouterStatusReceiver());
1218         } catch (RemoteException | IOException | ThreadNetworkException e) {
1219             Log.w(TAG, "Failed to enable border routing", e);
1220         }
1221     }
1222 
1223     private void disableBorderRouting() {
1224         mUpstreamNetwork = null;
1225         mBorderRouterConfig.infraInterfaceName = null;
1226         mBorderRouterConfig.infraInterfaceIcmp6Socket = null;
1227         mBorderRouterConfig.isBorderRoutingEnabled = false;
1228         try {
1229             getOtDaemon()
1230                     .configureBorderRouter(
1231                             mBorderRouterConfig, new ConfigureBorderRouterStatusReceiver());
1232         } catch (RemoteException | ThreadNetworkException e) {
1233             Log.w(TAG, "Failed to disable border routing", e);
1234         }
1235     }
1236 
1237     private void handleThreadInterfaceStateChanged(boolean isUp) {
1238         try {
1239             mTunIfController.setInterfaceUp(isUp);
1240             Log.i(TAG, "Thread TUN interface becomes " + (isUp ? "up" : "down"));
1241         } catch (IOException e) {
1242             Log.e(TAG, "Failed to handle Thread interface state changes", e);
1243         }
1244     }
1245 
1246     private void handleDeviceRoleChanged(@DeviceRole int deviceRole) {
1247         if (ThreadNetworkController.isAttached(deviceRole)) {
1248             Log.i(TAG, "Attached to the Thread network");
1249 
1250             // This is an idempotent method which can be called for multiple times when the device
1251             // is already attached (e.g. going from Child to Router)
1252             registerThreadNetwork();
1253         } else {
1254             Log.i(TAG, "Detached from the Thread network");
1255 
1256             // This is an idempotent method which can be called for multiple times when the device
1257             // is already detached or stopped
1258             unregisterThreadNetwork();
1259         }
1260     }
1261 
1262     private void handleAddressChanged(List<Ipv6AddressInfo> addressInfoList) {
1263         checkOnHandlerThread();
1264 
1265         mTunIfController.updateAddresses(addressInfoList);
1266 
1267         // The OT daemon can send link property updates before the networkAgent is
1268         // registered
1269         if (mNetworkAgent != null) {
1270             mNetworkAgent.sendLinkProperties(mTunIfController.getLinkProperties());
1271         }
1272     }
1273 
1274     private void handlePrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
1275         checkOnHandlerThread();
1276 
1277         mTunIfController.updatePrefixes(onMeshPrefixConfigList);
1278 
1279         // The OT daemon can send link property updates before the networkAgent is
1280         // registered
1281         if (mNetworkAgent != null) {
1282             mNetworkAgent.sendLinkProperties(mTunIfController.getLinkProperties());
1283         }
1284     }
1285 
1286     private void sendLocalNetworkConfig() {
1287         if (mNetworkAgent == null) {
1288             return;
1289         }
1290         final LocalNetworkConfig localNetworkConfig = newLocalNetworkConfig();
1291         mNetworkAgent.sendLocalNetworkConfig(localNetworkConfig);
1292         Log.d(TAG, "Sent localNetworkConfig: " + localNetworkConfig);
1293     }
1294 
1295     private void handleMulticastForwardingChanged(BackboneRouterState state) {
1296         MulticastRoutingConfig upstreamMulticastRoutingConfig;
1297         MulticastRoutingConfig downstreamMulticastRoutingConfig;
1298 
1299         if (state.multicastForwardingEnabled) {
1300             // When multicast forwarding is enabled, setup upstream forwarding to any address
1301             // with minimal scope 4
1302             // setup downstream forwarding with addresses subscribed from Thread network
1303             upstreamMulticastRoutingConfig =
1304                     new MulticastRoutingConfig.Builder(FORWARD_WITH_MIN_SCOPE, 4).build();
1305             downstreamMulticastRoutingConfig =
1306                     buildDownstreamMulticastRoutingConfigSelected(state.listeningAddresses);
1307         } else {
1308             // When multicast forwarding is disabled, set both upstream and downstream
1309             // forwarding config to FORWARD_NONE.
1310             upstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
1311             downstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
1312         }
1313 
1314         if (upstreamMulticastRoutingConfig.equals(mUpstreamMulticastRoutingConfig)
1315                 && downstreamMulticastRoutingConfig.equals(mDownstreamMulticastRoutingConfig)) {
1316             return;
1317         }
1318 
1319         mUpstreamMulticastRoutingConfig = upstreamMulticastRoutingConfig;
1320         mDownstreamMulticastRoutingConfig = downstreamMulticastRoutingConfig;
1321         sendLocalNetworkConfig();
1322     }
1323 
1324     private MulticastRoutingConfig buildDownstreamMulticastRoutingConfigSelected(
1325             List<String> listeningAddresses) {
1326         MulticastRoutingConfig.Builder builder =
1327                 new MulticastRoutingConfig.Builder(FORWARD_SELECTED);
1328         for (String addressStr : listeningAddresses) {
1329             Inet6Address address = (Inet6Address) InetAddresses.parseNumericAddress(addressStr);
1330             builder.addListeningAddress(address);
1331         }
1332         return builder.build();
1333     }
1334 
1335     private static final class CallbackMetadata {
1336         private static long gId = 0;
1337 
1338         // The unique ID
1339         final long id;
1340 
1341         final IBinder.DeathRecipient deathRecipient;
1342 
1343         CallbackMetadata(IBinder.DeathRecipient deathRecipient) {
1344             this.id = allocId();
1345             this.deathRecipient = deathRecipient;
1346         }
1347 
1348         private static long allocId() {
1349             if (gId == Long.MAX_VALUE) {
1350                 gId = 0;
1351             }
1352             return gId++;
1353         }
1354     }
1355 
1356     private static final class ConfigureBorderRouterStatusReceiver extends IOtStatusReceiver.Stub {
1357         public ConfigureBorderRouterStatusReceiver() {}
1358 
1359         @Override
1360         public void onSuccess() {
1361             Log.i(TAG, "Configured border router successfully");
1362         }
1363 
1364         @Override
1365         public void onError(int i, String s) {
1366             Log.w(TAG, String.format("Failed to configure border router: %d %s", i, s));
1367         }
1368     }
1369 
1370     /**
1371      * Handles and forwards Thread daemon callbacks. This class must be accessed from the thread of
1372      * {@code mHandler}.
1373      */
1374     private final class OtDaemonCallbackProxy extends IOtDaemonCallback.Stub {
1375         private final Map<IStateCallback, CallbackMetadata> mStateCallbacks = new HashMap<>();
1376         private final Map<IOperationalDatasetCallback, CallbackMetadata> mOpDatasetCallbacks =
1377                 new HashMap<>();
1378 
1379         private OtDaemonState mState;
1380         private ActiveOperationalDataset mActiveDataset;
1381         private PendingOperationalDataset mPendingDataset;
1382 
1383         public void registerStateCallback(IStateCallback callback) {
1384             checkOnHandlerThread();
1385             if (mStateCallbacks.containsKey(callback)) {
1386                 throw new IllegalStateException("Registering the same IStateCallback twice");
1387             }
1388 
1389             IBinder.DeathRecipient deathRecipient =
1390                     () -> mHandler.post(() -> unregisterStateCallback(callback));
1391             CallbackMetadata callbackMetadata = new CallbackMetadata(deathRecipient);
1392             mStateCallbacks.put(callback, callbackMetadata);
1393             try {
1394                 callback.asBinder().linkToDeath(deathRecipient, 0);
1395             } catch (RemoteException e) {
1396                 mStateCallbacks.remove(callback);
1397                 // This is thrown when the client is dead, do nothing
1398             }
1399 
1400             try {
1401                 getOtDaemon().registerStateCallback(this, callbackMetadata.id);
1402             } catch (RemoteException | ThreadNetworkException e) {
1403                 Log.e(TAG, "otDaemon.registerStateCallback failed", e);
1404             }
1405         }
1406 
1407         public void unregisterStateCallback(IStateCallback callback) {
1408             checkOnHandlerThread();
1409             if (!mStateCallbacks.containsKey(callback)) {
1410                 return;
1411             }
1412             callback.asBinder().unlinkToDeath(mStateCallbacks.remove(callback).deathRecipient, 0);
1413         }
1414 
1415         public void registerDatasetCallback(IOperationalDatasetCallback callback) {
1416             checkOnHandlerThread();
1417             if (mOpDatasetCallbacks.containsKey(callback)) {
1418                 throw new IllegalStateException(
1419                         "Registering the same IOperationalDatasetCallback twice");
1420             }
1421 
1422             IBinder.DeathRecipient deathRecipient =
1423                     () -> mHandler.post(() -> unregisterDatasetCallback(callback));
1424             CallbackMetadata callbackMetadata = new CallbackMetadata(deathRecipient);
1425             mOpDatasetCallbacks.put(callback, callbackMetadata);
1426             try {
1427                 callback.asBinder().linkToDeath(deathRecipient, 0);
1428             } catch (RemoteException e) {
1429                 mOpDatasetCallbacks.remove(callback);
1430             }
1431 
1432             try {
1433                 getOtDaemon().registerStateCallback(this, callbackMetadata.id);
1434             } catch (RemoteException | ThreadNetworkException e) {
1435                 Log.e(TAG, "otDaemon.registerStateCallback failed", e);
1436             }
1437         }
1438 
1439         public void unregisterDatasetCallback(IOperationalDatasetCallback callback) {
1440             checkOnHandlerThread();
1441             if (!mOpDatasetCallbacks.containsKey(callback)) {
1442                 return;
1443             }
1444             callback.asBinder()
1445                     .unlinkToDeath(mOpDatasetCallbacks.remove(callback).deathRecipient, 0);
1446         }
1447 
1448         public void onOtDaemonDied() {
1449             checkOnHandlerThread();
1450             if (mState == null) {
1451                 return;
1452             }
1453 
1454             final int deviceRole = mState.deviceRole;
1455             mState = null;
1456 
1457             // If this device is already STOPPED or DETACHED, do nothing
1458             if (!ThreadNetworkController.isAttached(deviceRole)) {
1459                 return;
1460             }
1461 
1462             // The Thread device role is considered DETACHED when the OT daemon process is dead
1463             handleDeviceRoleChanged(DEVICE_ROLE_DETACHED);
1464             for (IStateCallback callback : mStateCallbacks.keySet()) {
1465                 try {
1466                     callback.onDeviceRoleChanged(DEVICE_ROLE_DETACHED);
1467                 } catch (RemoteException ignored) {
1468                     // do nothing if the client is dead
1469                 }
1470             }
1471         }
1472 
1473         private void onThreadEnabledChanged(int state, long listenerId) {
1474             checkOnHandlerThread();
1475             boolean stateChanged = (mState == null || mState.threadEnabled != state);
1476 
1477             for (var callbackEntry : mStateCallbacks.entrySet()) {
1478                 if (!stateChanged && callbackEntry.getValue().id != listenerId) {
1479                     continue;
1480                 }
1481                 try {
1482                     callbackEntry.getKey().onThreadEnableStateChanged(otStateToAndroidState(state));
1483                 } catch (RemoteException ignored) {
1484                     // do nothing if the client is dead
1485                 }
1486             }
1487         }
1488 
1489         private static int otStateToAndroidState(int state) {
1490             switch (state) {
1491                 case OT_STATE_ENABLED:
1492                     return STATE_ENABLED;
1493                 case OT_STATE_DISABLED:
1494                     return STATE_DISABLED;
1495                 case OT_STATE_DISABLING:
1496                     return STATE_DISABLING;
1497                 default:
1498                     throw new IllegalArgumentException("Unknown ot state " + state);
1499             }
1500         }
1501 
1502         @Override
1503         public void onStateChanged(OtDaemonState newState, long listenerId) {
1504             mHandler.post(() -> onStateChangedInternal(newState, listenerId));
1505         }
1506 
1507         private void onStateChangedInternal(OtDaemonState newState, long listenerId) {
1508             checkOnHandlerThread();
1509             onInterfaceStateChanged(newState.isInterfaceUp);
1510             onDeviceRoleChanged(newState.deviceRole, listenerId);
1511             onPartitionIdChanged(newState.partitionId, listenerId);
1512             onThreadEnabledChanged(newState.threadEnabled, listenerId);
1513             mState = newState;
1514 
1515             ActiveOperationalDataset newActiveDataset;
1516             try {
1517                 if (newState.activeDatasetTlvs.length != 0) {
1518                     newActiveDataset =
1519                             ActiveOperationalDataset.fromThreadTlvs(newState.activeDatasetTlvs);
1520                 } else {
1521                     newActiveDataset = null;
1522                 }
1523                 onActiveOperationalDatasetChanged(newActiveDataset, listenerId);
1524                 mActiveDataset = newActiveDataset;
1525             } catch (IllegalArgumentException e) {
1526                 // Is unlikely that OT will generate invalid Operational Dataset
1527                 Log.wtf(TAG, "Invalid Active Operational Dataset from OpenThread", e);
1528             }
1529 
1530             PendingOperationalDataset newPendingDataset;
1531             try {
1532                 if (newState.pendingDatasetTlvs.length != 0) {
1533                     newPendingDataset =
1534                             PendingOperationalDataset.fromThreadTlvs(newState.pendingDatasetTlvs);
1535                 } else {
1536                     newPendingDataset = null;
1537                 }
1538                 onPendingOperationalDatasetChanged(newPendingDataset, listenerId);
1539                 mPendingDataset = newPendingDataset;
1540             } catch (IllegalArgumentException e) {
1541                 // Is unlikely that OT will generate invalid Operational Dataset
1542                 Log.wtf(TAG, "Invalid Pending Operational Dataset from OpenThread", e);
1543             }
1544         }
1545 
1546         private void onInterfaceStateChanged(boolean isUp) {
1547             checkOnHandlerThread();
1548             if (mState == null || mState.isInterfaceUp != isUp) {
1549                 handleThreadInterfaceStateChanged(isUp);
1550             }
1551         }
1552 
1553         private void onDeviceRoleChanged(@DeviceRole int deviceRole, long listenerId) {
1554             checkOnHandlerThread();
1555             boolean hasChange = (mState == null || mState.deviceRole != deviceRole);
1556             if (hasChange) {
1557                 handleDeviceRoleChanged(deviceRole);
1558             }
1559 
1560             for (var callbackEntry : mStateCallbacks.entrySet()) {
1561                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1562                     continue;
1563                 }
1564                 try {
1565                     callbackEntry.getKey().onDeviceRoleChanged(deviceRole);
1566                 } catch (RemoteException ignored) {
1567                     // do nothing if the client is dead
1568                 }
1569             }
1570         }
1571 
1572         private void onPartitionIdChanged(long partitionId, long listenerId) {
1573             checkOnHandlerThread();
1574             boolean hasChange = (mState == null || mState.partitionId != partitionId);
1575 
1576             for (var callbackEntry : mStateCallbacks.entrySet()) {
1577                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1578                     continue;
1579                 }
1580                 try {
1581                     callbackEntry.getKey().onPartitionIdChanged(partitionId);
1582                 } catch (RemoteException ignored) {
1583                     // do nothing if the client is dead
1584                 }
1585             }
1586         }
1587 
1588         private void onActiveOperationalDatasetChanged(
1589                 ActiveOperationalDataset activeDataset, long listenerId) {
1590             checkOnHandlerThread();
1591             boolean hasChange = !Objects.equals(mActiveDataset, activeDataset);
1592 
1593             for (var callbackEntry : mOpDatasetCallbacks.entrySet()) {
1594                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1595                     continue;
1596                 }
1597                 try {
1598                     callbackEntry.getKey().onActiveOperationalDatasetChanged(activeDataset);
1599                 } catch (RemoteException ignored) {
1600                     // do nothing if the client is dead
1601                 }
1602             }
1603         }
1604 
1605         private void onPendingOperationalDatasetChanged(
1606                 PendingOperationalDataset pendingDataset, long listenerId) {
1607             checkOnHandlerThread();
1608             boolean hasChange = !Objects.equals(mPendingDataset, pendingDataset);
1609             for (var callbackEntry : mOpDatasetCallbacks.entrySet()) {
1610                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1611                     continue;
1612                 }
1613                 try {
1614                     callbackEntry.getKey().onPendingOperationalDatasetChanged(pendingDataset);
1615                 } catch (RemoteException ignored) {
1616                     // do nothing if the client is dead
1617                 }
1618             }
1619         }
1620 
1621         @Override
1622         public void onAddressChanged(List<Ipv6AddressInfo> addressInfoList) {
1623             mHandler.post(() -> handleAddressChanged(addressInfoList));
1624         }
1625 
1626         @Override
1627         public void onBackboneRouterStateChanged(BackboneRouterState state) {
1628             mHandler.post(() -> handleMulticastForwardingChanged(state));
1629         }
1630 
1631         @Override
1632         public void onPrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
1633             mHandler.post(() -> handlePrefixChanged(onMeshPrefixConfigList));
1634         }
1635     }
1636 }
1637