• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.pm.PackageManager.PERMISSION_GRANTED;
19 import static android.net.MulticastRoutingConfig.CONFIG_FORWARD_NONE;
20 import static android.net.MulticastRoutingConfig.FORWARD_SELECTED;
21 import static android.net.MulticastRoutingConfig.FORWARD_WITH_MIN_SCOPE;
22 import static android.net.NetworkCapabilities.TRANSPORT_THREAD;
23 import static android.net.thread.ActiveOperationalDataset.CHANNEL_PAGE_24_GHZ;
24 import static android.net.thread.ActiveOperationalDataset.LENGTH_EXTENDED_PAN_ID;
25 import static android.net.thread.ActiveOperationalDataset.LENGTH_MESH_LOCAL_PREFIX_BITS;
26 import static android.net.thread.ActiveOperationalDataset.LENGTH_NETWORK_KEY;
27 import static android.net.thread.ActiveOperationalDataset.LENGTH_PSKC;
28 import static android.net.thread.ActiveOperationalDataset.MESH_LOCAL_PREFIX_FIRST_BYTE;
29 import static android.net.thread.ActiveOperationalDataset.SecurityPolicy.DEFAULT_ROTATION_TIME_HOURS;
30 import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_DETACHED;
31 import static android.net.thread.ThreadNetworkController.EPHEMERAL_KEY_DISABLED;
32 import static android.net.thread.ThreadNetworkController.STATE_DISABLED;
33 import static android.net.thread.ThreadNetworkController.STATE_DISABLING;
34 import static android.net.thread.ThreadNetworkController.STATE_ENABLED;
35 import static android.net.thread.ThreadNetworkController.THREAD_VERSION_1_3;
36 import static android.net.thread.ThreadNetworkException.ERROR_ABORTED;
37 import static android.net.thread.ThreadNetworkException.ERROR_BUSY;
38 import static android.net.thread.ThreadNetworkException.ERROR_FAILED_PRECONDITION;
39 import static android.net.thread.ThreadNetworkException.ERROR_INTERNAL_ERROR;
40 import static android.net.thread.ThreadNetworkException.ERROR_REJECTED_BY_PEER;
41 import static android.net.thread.ThreadNetworkException.ERROR_RESOURCE_EXHAUSTED;
42 import static android.net.thread.ThreadNetworkException.ERROR_RESPONSE_BAD_FORMAT;
43 import static android.net.thread.ThreadNetworkException.ERROR_THREAD_DISABLED;
44 import static android.net.thread.ThreadNetworkException.ERROR_TIMEOUT;
45 import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_CHANNEL;
46 import static android.net.thread.ThreadNetworkException.ERROR_UNSUPPORTED_FEATURE;
47 import static android.net.thread.ThreadNetworkManager.DISALLOW_THREAD_NETWORK;
48 import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
49 import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_TESTING;
50 
51 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_ABORT;
52 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_BUSY;
53 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_FAILED_PRECONDITION;
54 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_INVALID_STATE;
55 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_NOT_IMPLEMENTED;
56 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_NO_BUFS;
57 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_PARSE;
58 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_REASSEMBLY_TIMEOUT;
59 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_REJECTED;
60 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_RESPONSE_TIMEOUT;
61 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_THREAD_DISABLED;
62 import static com.android.server.thread.openthread.IOtDaemon.ErrorCode.OT_ERROR_UNSUPPORTED_CHANNEL;
63 import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_DISABLED;
64 import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_DISABLING;
65 import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_ENABLED;
66 import static com.android.server.thread.openthread.IOtDaemon.TUN_IF_NAME;
67 
68 import static java.nio.charset.StandardCharsets.UTF_8;
69 
70 import android.Manifest.permission;
71 import android.annotation.NonNull;
72 import android.annotation.Nullable;
73 import android.annotation.RequiresPermission;
74 import android.annotation.TargetApi;
75 import android.content.BroadcastReceiver;
76 import android.content.Context;
77 import android.content.Intent;
78 import android.content.IntentFilter;
79 import android.content.res.Resources;
80 import android.net.ConnectivityManager;
81 import android.net.InetAddresses;
82 import android.net.IpPrefix;
83 import android.net.LinkAddress;
84 import android.net.LinkProperties;
85 import android.net.LocalNetworkConfig;
86 import android.net.LocalNetworkInfo;
87 import android.net.MulticastRoutingConfig;
88 import android.net.Network;
89 import android.net.NetworkAgent;
90 import android.net.NetworkAgentConfig;
91 import android.net.NetworkCapabilities;
92 import android.net.NetworkProvider;
93 import android.net.NetworkRequest;
94 import android.net.NetworkScore;
95 import android.net.TestNetworkSpecifier;
96 import android.net.thread.ActiveOperationalDataset;
97 import android.net.thread.ActiveOperationalDataset.SecurityPolicy;
98 import android.net.thread.ChannelMaxPower;
99 import android.net.thread.IActiveOperationalDatasetReceiver;
100 import android.net.thread.IConfigurationReceiver;
101 import android.net.thread.IOperationReceiver;
102 import android.net.thread.IOperationalDatasetCallback;
103 import android.net.thread.IOutputReceiver;
104 import android.net.thread.IStateCallback;
105 import android.net.thread.IThreadNetworkController;
106 import android.net.thread.OperationalDatasetTimestamp;
107 import android.net.thread.PendingOperationalDataset;
108 import android.net.thread.ThreadConfiguration;
109 import android.net.thread.ThreadNetworkController;
110 import android.net.thread.ThreadNetworkController.DeviceRole;
111 import android.net.thread.ThreadNetworkException;
112 import android.net.thread.ThreadNetworkException.ErrorCode;
113 import android.os.Build;
114 import android.os.Handler;
115 import android.os.HandlerThread;
116 import android.os.IBinder;
117 import android.os.Looper;
118 import android.os.ParcelFileDescriptor;
119 import android.os.RemoteException;
120 import android.os.SystemClock;
121 import android.os.UserManager;
122 import android.util.SparseArray;
123 
124 import com.android.connectivity.resources.R;
125 import com.android.internal.annotations.VisibleForTesting;
126 import com.android.net.module.util.IIpv4PrefixRequest;
127 import com.android.net.module.util.RoutingCoordinatorManager;
128 import com.android.net.module.util.SharedLog;
129 import com.android.server.ServiceManagerWrapper;
130 import com.android.server.connectivity.ConnectivityResources;
131 import com.android.server.connectivity.MockableSystemProperties;
132 import com.android.server.thread.openthread.BackboneRouterState;
133 import com.android.server.thread.openthread.DnsTxtAttribute;
134 import com.android.server.thread.openthread.IChannelMasksReceiver;
135 import com.android.server.thread.openthread.IOtDaemon;
136 import com.android.server.thread.openthread.IOtDaemonCallback;
137 import com.android.server.thread.openthread.IOtOutputReceiver;
138 import com.android.server.thread.openthread.IOtStatusReceiver;
139 import com.android.server.thread.openthread.InfraLinkState;
140 import com.android.server.thread.openthread.Ipv6AddressInfo;
141 import com.android.server.thread.openthread.MeshcopTxtAttributes;
142 import com.android.server.thread.openthread.OnMeshPrefixConfig;
143 import com.android.server.thread.openthread.OtDaemonConfiguration;
144 import com.android.server.thread.openthread.OtDaemonState;
145 
146 import libcore.util.HexEncoding;
147 
148 import java.io.IOException;
149 import java.net.Inet6Address;
150 import java.net.InetAddress;
151 import java.security.SecureRandom;
152 import java.time.Clock;
153 import java.time.DateTimeException;
154 import java.time.Instant;
155 import java.util.ArrayList;
156 import java.util.HashMap;
157 import java.util.List;
158 import java.util.Map;
159 import java.util.Objects;
160 import java.util.Random;
161 import java.util.function.Supplier;
162 import java.util.regex.Pattern;
163 
164 /**
165  * Implementation of the {@link ThreadNetworkController} API.
166  *
167  * <p>Threading model: This class is not Thread-safe and should only be accessed from the
168  * ThreadNetworkService class. Additional attention should be paid to handle the threading code
169  * correctly: 1. All member fields other than `mHandler` and `mContext` MUST be accessed from the
170  * thread of `mHandler` 2. In the @Override methods, the actual work MUST be dispatched to the
171  * HandlerThread except for arguments or permissions checking
172  */
173 @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
174 final class ThreadNetworkControllerService extends IThreadNetworkController.Stub {
175     private static final String TAG = "ControllerService";
176     private static final SharedLog LOG = ThreadNetworkLogger.forSubComponent(TAG);
177 
178     // The model name length in utf-8 bytes
179     private static final int MAX_MODEL_NAME_UTF8_BYTES = 24;
180 
181     // The max vendor name length in utf-8 bytes
182     private static final int MAX_VENDOR_NAME_UTF8_BYTES = 24;
183 
184     // This regex pattern allows "XXXXXX", "XX:XX:XX" and "XX-XX-XX" OUI formats.
185     // Note that this regex allows "XX:XX-XX" as well but we don't need to be a strict checker
186     private static final String OUI_REGEX = "^([0-9A-Fa-f]{2}[:-]?){2}([0-9A-Fa-f]{2})$";
187 
188     // The channel mask that indicates all channels from channel 11 to channel 24
189     private static final int CHANNEL_MASK_11_TO_24 = 0x1FFF800;
190 
191     // Below member fields can be accessed from both the binder and handler threads
192 
193     private final Context mContext;
194     private final Handler mHandler;
195     private final MockableSystemProperties mSystemProperties;
196 
197     // Below member fields can only be accessed from the handler thread (`mHandler`). In
198     // particular, the constructor does not run on the handler thread, so it must not touch any of
199     // the non-final fields, nor must it mutate any of the non-final fields inside these objects.
200 
201     private final NetworkProvider mNetworkProvider;
202     private final Supplier<IOtDaemon> mOtDaemonSupplier;
203     private final ConnectivityManager mConnectivityManager;
204     private final RoutingCoordinatorManager mRoutingCoordinatorManager;
205     private final TunInterfaceController mTunIfController;
206     private final InfraInterfaceController mInfraIfController;
207     private final NsdPublisher mNsdPublisher;
208     private final OtDaemonCallbackProxy mOtDaemonCallbackProxy = new OtDaemonCallbackProxy();
209     private final Nat64CidrController mNat64CidrController = new Nat64CidrController();
210     private final ConnectivityResources mResources;
211     private final Supplier<String> mCountryCodeSupplier;
212     private final Map<IConfigurationReceiver, IBinder.DeathRecipient> mConfigurationReceivers =
213             new HashMap<>();
214 
215     // This should not be directly used for calling IOtDaemon APIs because ot-daemon may die and
216     // {@code mOtDaemon} will be set to {@code null}. Instead, use {@code getOtDaemon()}
217     @Nullable private IOtDaemon mOtDaemon;
218     @Nullable private NetworkAgent mNetworkAgent;
219     @Nullable private NetworkAgent mTestNetworkAgent;
220 
221     private MulticastRoutingConfig mUpstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
222     private MulticastRoutingConfig mDownstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
223     private Network mUpstreamNetwork;
224     private NetworkRequest mUpstreamNetworkRequest;
225     private UpstreamNetworkCallback mUpstreamNetworkCallback;
226     private TestNetworkSpecifier mUpstreamTestNetworkSpecifier;
227     private ThreadNetworkCallback mThreadNetworkCallback;
228     private final Map<Network, LinkProperties> mNetworkToLinkProperties;
229     private final ThreadPersistentSettings mPersistentSettings;
230     private final UserManager mUserManager;
231     private boolean mUserRestricted;
232     private boolean mForceStopOtDaemonEnabled;
233 
234     private InfraLinkState mInfraLinkState;
235 
236     @VisibleForTesting
ThreadNetworkControllerService( Context context, Handler handler, MockableSystemProperties systemProperties, NetworkProvider networkProvider, Supplier<IOtDaemon> otDaemonSupplier, ConnectivityManager connectivityManager, RoutingCoordinatorManager routingCoordinatorManager, TunInterfaceController tunIfController, InfraInterfaceController infraIfController, ThreadPersistentSettings persistentSettings, NsdPublisher nsdPublisher, UserManager userManager, ConnectivityResources resources, Supplier<String> countryCodeSupplier, Map<Network, LinkProperties> networkToLinkProperties)237     ThreadNetworkControllerService(
238             Context context,
239             Handler handler,
240             MockableSystemProperties systemProperties,
241             NetworkProvider networkProvider,
242             Supplier<IOtDaemon> otDaemonSupplier,
243             ConnectivityManager connectivityManager,
244             RoutingCoordinatorManager routingCoordinatorManager,
245             TunInterfaceController tunIfController,
246             InfraInterfaceController infraIfController,
247             ThreadPersistentSettings persistentSettings,
248             NsdPublisher nsdPublisher,
249             UserManager userManager,
250             ConnectivityResources resources,
251             Supplier<String> countryCodeSupplier,
252             Map<Network, LinkProperties> networkToLinkProperties) {
253         mContext = context;
254         mHandler = handler;
255         mSystemProperties = systemProperties;
256         mNetworkProvider = networkProvider;
257         mOtDaemonSupplier = otDaemonSupplier;
258         mConnectivityManager = connectivityManager;
259         mRoutingCoordinatorManager = routingCoordinatorManager;
260         mTunIfController = tunIfController;
261         mInfraIfController = infraIfController;
262         mUpstreamNetworkRequest = newUpstreamNetworkRequest();
263         // TODO: networkToLinkProperties should be shared with NsdPublisher, add a test/assert to
264         // verify they are the same.
265         mNetworkToLinkProperties = networkToLinkProperties;
266         mInfraLinkState = new InfraLinkState.Builder().build();
267         mPersistentSettings = persistentSettings;
268         mNsdPublisher = nsdPublisher;
269         mUserManager = userManager;
270         mResources = resources;
271         mCountryCodeSupplier = countryCodeSupplier;
272     }
273 
newInstance( Context context, ThreadPersistentSettings persistentSettings, Supplier<String> countryCodeSupplier)274     public static ThreadNetworkControllerService newInstance(
275             Context context,
276             ThreadPersistentSettings persistentSettings,
277             Supplier<String> countryCodeSupplier) {
278         HandlerThread handlerThread = new HandlerThread("ThreadHandlerThread");
279         handlerThread.start();
280         Handler handler = new Handler(handlerThread.getLooper());
281         NetworkProvider networkProvider =
282                 new NetworkProvider(context, handlerThread.getLooper(), "ThreadNetworkProvider");
283         Map<Network, LinkProperties> networkToLinkProperties = new HashMap<>();
284         final ConnectivityManager connectivityManager =
285                 context.getSystemService(ConnectivityManager.class);
286         final RoutingCoordinatorManager routingCoordinatorManager =
287                 new RoutingCoordinatorManager(
288                         context, connectivityManager.getRoutingCoordinatorService());
289 
290         return new ThreadNetworkControllerService(
291                 context,
292                 handler,
293                 new MockableSystemProperties(),
294                 networkProvider,
295                 () -> IOtDaemon.Stub.asInterface(ServiceManagerWrapper.waitForService("ot_daemon")),
296                 connectivityManager,
297                 routingCoordinatorManager,
298                 new TunInterfaceController(TUN_IF_NAME),
299                 new InfraInterfaceController(),
300                 persistentSettings,
301                 NsdPublisher.newInstance(context, handler, networkToLinkProperties),
302                 context.getSystemService(UserManager.class),
303                 new ConnectivityResources(context),
304                 countryCodeSupplier,
305                 networkToLinkProperties);
306     }
307 
newUpstreamNetworkRequest()308     private NetworkRequest newUpstreamNetworkRequest() {
309         NetworkRequest.Builder builder = new NetworkRequest.Builder();
310 
311         if (mUpstreamTestNetworkSpecifier != null) {
312             // Test networks don't have NET_CAPABILITY_TRUSTED
313             return builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
314                     .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
315                     .setNetworkSpecifier(mUpstreamTestNetworkSpecifier)
316                     .build();
317         }
318         return builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
319                 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
320                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
321                 .build();
322     }
323 
maybeInitializeOtDaemon()324     private void maybeInitializeOtDaemon() {
325         if (!shouldEnableThread()) {
326             return;
327         }
328 
329         LOG.i("Starting OT daemon...");
330 
331         try {
332             getOtDaemon();
333         } catch (RemoteException e) {
334             LOG.e("Failed to initialize ot-daemon", e);
335         } catch (ThreadNetworkException e) {
336             // no ThreadNetworkException.ERROR_THREAD_DISABLED error should be thrown
337             throw new AssertionError(e);
338         }
339     }
340 
getOtDaemon()341     private IOtDaemon getOtDaemon() throws RemoteException, ThreadNetworkException {
342         checkOnHandlerThread();
343 
344         if (mForceStopOtDaemonEnabled) {
345             throw new ThreadNetworkException(
346                     ERROR_THREAD_DISABLED, "ot-daemon is forcibly stopped");
347         }
348 
349         if (mOtDaemon != null) {
350             return mOtDaemon;
351         }
352 
353         IOtDaemon otDaemon = mOtDaemonSupplier.get();
354         if (otDaemon == null) {
355             throw new RemoteException("Internal error: failed to start OT daemon");
356         }
357 
358         otDaemon.initialize(
359                 shouldEnableThread(),
360                 newOtDaemonConfig(mPersistentSettings.getConfiguration()),
361                 mTunIfController.getTunFd(),
362                 mNsdPublisher,
363                 getMeshcopTxtAttributes(mResources.get(), mSystemProperties),
364                 mCountryCodeSupplier.get(),
365                 FeatureFlags.isTrelEnabled(),
366                 mOtDaemonCallbackProxy);
367         otDaemon.asBinder().linkToDeath(() -> mHandler.post(this::onOtDaemonDied), 0);
368         mOtDaemon = otDaemon;
369         mHandler.post(mNat64CidrController::maybeUpdateNat64Cidr);
370         return mOtDaemon;
371     }
372 
getVendorName(Resources resources, MockableSystemProperties systemProperties)373     static String getVendorName(Resources resources, MockableSystemProperties systemProperties) {
374         final String PROP_MANUFACTURER = "ro.product.manufacturer";
375         String vendorName = resources.getString(R.string.config_thread_vendor_name);
376         if (vendorName.equalsIgnoreCase(PROP_MANUFACTURER)) {
377             vendorName = systemProperties.get(PROP_MANUFACTURER);
378             // Assume it's always ASCII chars in ro.product.manufacturer
379             if (vendorName.length() > MAX_VENDOR_NAME_UTF8_BYTES) {
380                 vendorName = vendorName.substring(0, MAX_VENDOR_NAME_UTF8_BYTES);
381             }
382         }
383         return vendorName;
384     }
385 
getModelName(Resources resources, MockableSystemProperties systemProperties)386     static String getModelName(Resources resources, MockableSystemProperties systemProperties) {
387         final String PROP_MODEL = "ro.product.model";
388         String modelName = resources.getString(R.string.config_thread_model_name);
389         if (modelName.equalsIgnoreCase(PROP_MODEL)) {
390             modelName = systemProperties.get(PROP_MODEL);
391             // Assume it's always ASCII chars in ro.product.model
392             if (modelName.length() > MAX_MODEL_NAME_UTF8_BYTES) {
393                 modelName = modelName.substring(0, MAX_MODEL_NAME_UTF8_BYTES);
394             }
395         }
396         return modelName;
397     }
398 
399     @VisibleForTesting
getMeshcopTxtAttributes( Resources resources, MockableSystemProperties systemProperties)400     static MeshcopTxtAttributes getMeshcopTxtAttributes(
401             Resources resources, MockableSystemProperties systemProperties) {
402         final String vendorName = getVendorName(resources, systemProperties);
403         final String modelName = getModelName(resources, systemProperties);
404         final String vendorOui = resources.getString(R.string.config_thread_vendor_oui);
405         final String[] vendorSpecificTxts =
406                 resources.getStringArray(R.array.config_thread_mdns_vendor_specific_txts);
407 
408         if (!modelName.isEmpty()) {
409             if (modelName.getBytes(UTF_8).length > MAX_MODEL_NAME_UTF8_BYTES) {
410                 throw new IllegalStateException(
411                         "Model name is longer than "
412                                 + MAX_MODEL_NAME_UTF8_BYTES
413                                 + "utf-8 bytes: "
414                                 + modelName);
415             }
416         }
417 
418         if (!vendorName.isEmpty()) {
419             if (vendorName.getBytes(UTF_8).length > MAX_VENDOR_NAME_UTF8_BYTES) {
420                 throw new IllegalStateException(
421                         "Vendor name is longer than "
422                                 + MAX_VENDOR_NAME_UTF8_BYTES
423                                 + " utf-8 bytes: "
424                                 + vendorName);
425             }
426         }
427 
428         if (!vendorOui.isEmpty() && !Pattern.compile(OUI_REGEX).matcher(vendorOui).matches()) {
429             throw new IllegalStateException("Vendor OUI is invalid: " + vendorOui);
430         }
431 
432         MeshcopTxtAttributes meshcopTxts = new MeshcopTxtAttributes();
433         meshcopTxts.modelName = modelName;
434         meshcopTxts.vendorName = vendorName;
435         meshcopTxts.vendorOui = HexEncoding.decode(vendorOui.replace("-", "").replace(":", ""));
436         meshcopTxts.nonStandardTxtEntries = makeVendorSpecificTxtAttrs(vendorSpecificTxts);
437 
438         return meshcopTxts;
439     }
440 
441     /**
442      * Parses vendor-specific TXT entries from "=" separated strings into list of {@link
443      * DnsTxtAttribute}.
444      *
445      * @throws IllegalArgumentsException if invalid TXT entries are found in {@code vendorTxts}
446      */
447     @VisibleForTesting
makeVendorSpecificTxtAttrs(String[] vendorTxts)448     static List<DnsTxtAttribute> makeVendorSpecificTxtAttrs(String[] vendorTxts) {
449         List<DnsTxtAttribute> txts = new ArrayList<>();
450         for (String txt : vendorTxts) {
451             String[] kv = txt.split("=", 2 /* limit */); // Split with only the first '='
452             if (kv.length < 1) {
453                 throw new IllegalArgumentException(
454                         "Invalid vendor-specific TXT is found in resources: " + txt);
455             }
456 
457             if (kv[0].length() < 2) {
458                 throw new IllegalArgumentException(
459                         "Invalid vendor-specific TXT key \""
460                                 + kv[0]
461                                 + "\": it must contain at least 2 characters");
462             }
463 
464             if (!kv[0].startsWith("v")) {
465                 throw new IllegalArgumentException(
466                         "Invalid vendor-specific TXT key \""
467                                 + kv[0]
468                                 + "\": it doesn't start with \"v\"");
469             }
470 
471             txts.add(new DnsTxtAttribute(kv[0], (kv.length >= 2 ? kv[1] : "").getBytes(UTF_8)));
472         }
473         return txts;
474     }
475 
onOtDaemonDied()476     private void onOtDaemonDied() {
477         checkOnHandlerThread();
478         LOG.w("OT daemon is dead, clean up...");
479 
480         OperationReceiverWrapper.onOtDaemonDied();
481         OutputReceiverWrapper.onOtDaemonDied();
482         mOtDaemonCallbackProxy.onOtDaemonDied();
483         mTunIfController.onOtDaemonDied();
484         mNsdPublisher.onOtDaemonDied();
485         mOtDaemon = null;
486         maybeInitializeOtDaemon();
487     }
488 
initialize()489     public void initialize() {
490         mHandler.post(() -> initializeInternal());
491     }
492 
initializeInternal()493     private void initializeInternal() {
494         checkOnHandlerThread();
495 
496         LOG.v(
497                 "Initializing Thread system service: Thread is "
498                         + (shouldEnableThread() ? "enabled" : "disabled"));
499         try {
500             mTunIfController.createTunInterface();
501         } catch (IOException e) {
502             throw new IllegalStateException("Failed to create Thread tunnel interface", e);
503         }
504         mConnectivityManager.registerNetworkProvider(mNetworkProvider);
505         mUserRestricted = isThreadUserRestricted();
506         registerUserRestrictionsReceiver();
507 
508         if (isBorderRouterMode()) {
509             requestUpstreamNetwork();
510             registerThreadNetworkCallback();
511         } else {
512             cancelRequestUpstreamNetwork();
513             unregisterThreadNetworkCallback();
514         }
515         maybeInitializeOtDaemon();
516     }
517 
518     /**
519      * Force stops ot-daemon immediately and prevents ot-daemon from being restarted by
520      * system_server again.
521      *
522      * <p>This is for VTS testing only.
523      */
524     @RequiresPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
forceStopOtDaemonForTest(boolean enabled, @NonNull IOperationReceiver receiver)525     void forceStopOtDaemonForTest(boolean enabled, @NonNull IOperationReceiver receiver) {
526         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
527 
528         mHandler.post(
529                 () ->
530                         forceStopOtDaemonForTestInternal(
531                                 enabled,
532                                 new OperationReceiverWrapper(
533                                         receiver, true /* expectOtDaemonDied */)));
534     }
535 
forceStopOtDaemonForTestInternal( boolean enabled, @NonNull OperationReceiverWrapper receiver)536     private void forceStopOtDaemonForTestInternal(
537             boolean enabled, @NonNull OperationReceiverWrapper receiver) {
538         checkOnHandlerThread();
539         if (enabled == mForceStopOtDaemonEnabled) {
540             receiver.onSuccess();
541             return;
542         }
543 
544         if (!enabled) {
545             mForceStopOtDaemonEnabled = false;
546             maybeInitializeOtDaemon();
547             receiver.onSuccess();
548             return;
549         }
550 
551         try {
552             getOtDaemon().terminate();
553             // Do not invoke the {@code receiver} callback here but wait for ot-daemon to
554             // become dead, so that it's guaranteed that ot-daemon is stopped when {@code
555             // receiver} is completed
556         } catch (RemoteException e) {
557             LOG.e("otDaemon.terminate failed", e);
558             receiver.onError(ERROR_INTERNAL_ERROR, "Thread stack error");
559         } catch (ThreadNetworkException e) {
560             // No ThreadNetworkException.ERROR_THREAD_DISABLED error will be thrown
561             throw new AssertionError(e);
562         } finally {
563             mForceStopOtDaemonEnabled = true;
564         }
565     }
566 
setEnabled(boolean isEnabled, @NonNull IOperationReceiver receiver)567     public void setEnabled(boolean isEnabled, @NonNull IOperationReceiver receiver) {
568         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
569 
570         mHandler.post(
571                 () ->
572                         setEnabledInternal(
573                                 isEnabled,
574                                 true /* persist */,
575                                 new OperationReceiverWrapper(receiver)));
576     }
577 
setEnabledInternal( boolean isEnabled, boolean persist, @NonNull OperationReceiverWrapper receiver)578     private void setEnabledInternal(
579             boolean isEnabled, boolean persist, @NonNull OperationReceiverWrapper receiver) {
580         checkOnHandlerThread();
581         if (isEnabled && isThreadUserRestricted()) {
582             receiver.onError(
583                     ERROR_FAILED_PRECONDITION,
584                     "Cannot enable Thread: forbidden by user restriction");
585             return;
586         }
587 
588         LOG.i("Set Thread enabled: " + isEnabled + ", persist: " + persist);
589 
590         if (persist) {
591             // The persistent setting keeps the desired enabled state, thus it's set regardless
592             // the otDaemon set enabled state operation succeeded or not, so that it can recover
593             // to the desired value after reboot.
594             mPersistentSettings.put(ThreadPersistentSettings.KEY_THREAD_ENABLED, isEnabled);
595         }
596 
597         try {
598             getOtDaemon().setThreadEnabled(isEnabled, newOtStatusReceiver(receiver));
599         } catch (RemoteException | ThreadNetworkException e) {
600             LOG.e("otDaemon.setThreadEnabled failed", e);
601             receiver.onError(e);
602         }
603     }
604 
605     @Override
setConfiguration( @onNull ThreadConfiguration configuration, @NonNull IOperationReceiver receiver)606     public void setConfiguration(
607             @NonNull ThreadConfiguration configuration, @NonNull IOperationReceiver receiver) {
608         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
609         mHandler.post(
610                 () ->
611                         setConfigurationInternal(
612                                 configuration, new OperationReceiverWrapper(receiver)));
613     }
614 
setConfigurationInternal( @onNull ThreadConfiguration configuration, @NonNull OperationReceiverWrapper receiver)615     private void setConfigurationInternal(
616             @NonNull ThreadConfiguration configuration,
617             @NonNull OperationReceiverWrapper receiver) {
618         checkOnHandlerThread();
619 
620         LOG.i("Set Thread configuration: " + configuration);
621 
622         final boolean changed = mPersistentSettings.putConfiguration(configuration);
623 
624         if (changed) {
625             if (isBorderRouterMode()) {
626                 requestUpstreamNetwork();
627                 registerThreadNetworkCallback();
628             } else {
629                 cancelRequestUpstreamNetwork();
630                 unregisterThreadNetworkCallback();
631                 disableBorderRouting();
632             }
633         }
634 
635         receiver.onSuccess();
636 
637         if (changed) {
638             for (IConfigurationReceiver configReceiver : mConfigurationReceivers.keySet()) {
639                 try {
640                     configReceiver.onConfigurationChanged(configuration);
641                 } catch (RemoteException e) {
642                     // do nothing if the client is dead
643                 }
644             }
645         }
646 
647         try {
648             getOtDaemon()
649                     .setConfiguration(
650                             newOtDaemonConfig(configuration),
651                             new LoggingOtStatusReceiver("setConfiguration"));
652         } catch (RemoteException | ThreadNetworkException e) {
653             LOG.e("otDaemon.setConfiguration failed. Config: " + configuration, e);
654         }
655         mNat64CidrController.maybeUpdateNat64Cidr();
656     }
657 
newOtDaemonConfig(ThreadConfiguration threadConfig)658     private OtDaemonConfiguration newOtDaemonConfig(ThreadConfiguration threadConfig) {
659         int srpServerConfig = R.bool.config_thread_srp_server_wait_for_border_routing_enabled;
660         boolean srpServerWaitEnabled = mResources.get().getBoolean(srpServerConfig);
661         int autoJoinConfig = R.bool.config_thread_border_router_auto_join_enabled;
662         boolean autoJoinEnabled = mResources.get().getBoolean(autoJoinConfig);
663         boolean countryCodeEnabled =
664                 mResources.get().getBoolean(R.bool.config_thread_country_code_enabled);
665         return new OtDaemonConfiguration.Builder()
666                 .setBorderRouterEnabled(threadConfig.isBorderRouterEnabled())
667                 .setNat64Enabled(threadConfig.isNat64Enabled())
668                 .setDhcpv6PdEnabled(threadConfig.isDhcpv6PdEnabled())
669                 .setSrpServerWaitForBorderRoutingEnabled(srpServerWaitEnabled)
670                 .setBorderRouterAutoJoinEnabled(autoJoinEnabled)
671                 .setCountryCodeEnabled(countryCodeEnabled)
672                 .setVendorName(getVendorName(mResources.get(), mSystemProperties))
673                 .setModelName(getModelName(mResources.get(), mSystemProperties))
674                 .build();
675     }
676 
677     /** Returns {@code true} if this device is operating as a border router. */
isBorderRouterMode()678     private boolean isBorderRouterMode() {
679         return mPersistentSettings.getConfiguration().isBorderRouterEnabled();
680     }
681 
682     @Override
registerConfigurationCallback(@onNull IConfigurationReceiver callback)683     public void registerConfigurationCallback(@NonNull IConfigurationReceiver callback) {
684         enforceAllPermissionsGranted(permission.THREAD_NETWORK_PRIVILEGED);
685         mHandler.post(() -> registerConfigurationCallbackInternal(callback));
686     }
687 
registerConfigurationCallbackInternal(@onNull IConfigurationReceiver callback)688     private void registerConfigurationCallbackInternal(@NonNull IConfigurationReceiver callback) {
689         checkOnHandlerThread();
690         if (mConfigurationReceivers.containsKey(callback)) {
691             throw new IllegalStateException("Registering the same IConfigurationReceiver twice");
692         }
693         IBinder.DeathRecipient deathRecipient =
694                 () -> mHandler.post(() -> unregisterConfigurationCallbackInternal(callback));
695         try {
696             callback.asBinder().linkToDeath(deathRecipient, 0);
697         } catch (RemoteException e) {
698             return;
699         }
700         mConfigurationReceivers.put(callback, deathRecipient);
701         try {
702             callback.onConfigurationChanged(mPersistentSettings.getConfiguration());
703         } catch (RemoteException e) {
704             // do nothing if the client is dead
705         }
706     }
707 
708     @Override
unregisterConfigurationCallback(@onNull IConfigurationReceiver callback)709     public void unregisterConfigurationCallback(@NonNull IConfigurationReceiver callback) {
710         enforceAllPermissionsGranted(permission.THREAD_NETWORK_PRIVILEGED);
711         mHandler.post(() -> unregisterConfigurationCallbackInternal(callback));
712     }
713 
unregisterConfigurationCallbackInternal(@onNull IConfigurationReceiver callback)714     private void unregisterConfigurationCallbackInternal(@NonNull IConfigurationReceiver callback) {
715         checkOnHandlerThread();
716         if (!mConfigurationReceivers.containsKey(callback)) {
717             return;
718         }
719         callback.asBinder().unlinkToDeath(mConfigurationReceivers.remove(callback), 0);
720     }
721 
registerUserRestrictionsReceiver()722     private void registerUserRestrictionsReceiver() {
723         mContext.registerReceiver(
724                 new BroadcastReceiver() {
725                     @Override
726                     public void onReceive(Context context, Intent intent) {
727                         onUserRestrictionsChanged(isThreadUserRestricted());
728                     }
729                 },
730                 new IntentFilter(UserManager.ACTION_USER_RESTRICTIONS_CHANGED),
731                 null /* broadcastPermission */,
732                 mHandler);
733     }
734 
onUserRestrictionsChanged(boolean newUserRestrictedState)735     private void onUserRestrictionsChanged(boolean newUserRestrictedState) {
736         checkOnHandlerThread();
737         if (mUserRestricted == newUserRestrictedState) {
738             return;
739         }
740         LOG.i(
741                 "Thread user restriction changed: "
742                         + mUserRestricted
743                         + " -> "
744                         + newUserRestrictedState);
745         mUserRestricted = newUserRestrictedState;
746 
747         final boolean shouldEnableThread = shouldEnableThread();
748         final IOperationReceiver receiver =
749                 new IOperationReceiver.Stub() {
750                     @Override
751                     public void onSuccess() {
752                         LOG.v(
753                                 (shouldEnableThread ? "Enabled" : "Disabled")
754                                         + " Thread due to user restriction change");
755                     }
756 
757                     @Override
758                     public void onError(int errorCode, String errorMessage) {
759                         LOG.e(
760                                 "Failed to "
761                                         + (shouldEnableThread ? "enable" : "disable")
762                                         + " Thread for user restriction change");
763                     }
764                 };
765         // Do not save the user restriction state to persistent settings so that the user
766         // configuration won't be overwritten
767         setEnabledInternal(
768                 shouldEnableThread, false /* persist */, new OperationReceiverWrapper(receiver));
769     }
770 
771     /** Returns {@code true} if Thread has been restricted for the user. */
isThreadUserRestricted()772     private boolean isThreadUserRestricted() {
773         return mUserManager.hasUserRestriction(DISALLOW_THREAD_NETWORK);
774     }
775 
776     /**
777      * Returns {@code true} if Thread should be enabled based on current settings, runtime user
778      * restriction state.
779      */
shouldEnableThread()780     private boolean shouldEnableThread() {
781         return !mForceStopOtDaemonEnabled
782                 && !mUserRestricted
783                 && mPersistentSettings.get(ThreadPersistentSettings.KEY_THREAD_ENABLED);
784     }
785 
requestUpstreamNetwork()786     private void requestUpstreamNetwork() {
787         if (mUpstreamNetworkCallback != null) {
788             return;
789         }
790         mUpstreamNetworkCallback = new UpstreamNetworkCallback();
791         mConnectivityManager.registerNetworkCallback(
792                 mUpstreamNetworkRequest, mUpstreamNetworkCallback, mHandler);
793     }
794 
cancelRequestUpstreamNetwork()795     private void cancelRequestUpstreamNetwork() {
796         if (mUpstreamNetworkCallback == null) {
797             return;
798         }
799         mNetworkToLinkProperties.clear();
800         mConnectivityManager.unregisterNetworkCallback(mUpstreamNetworkCallback);
801         mUpstreamNetworkCallback = null;
802     }
803 
804     private final class UpstreamNetworkCallback extends ConnectivityManager.NetworkCallback {
805         @Override
onAvailable(@onNull Network network)806         public void onAvailable(@NonNull Network network) {
807             checkOnHandlerThread();
808             LOG.i("Upstream network available: " + network);
809         }
810 
811         @Override
onLost(@onNull Network network)812         public void onLost(@NonNull Network network) {
813             checkOnHandlerThread();
814             LOG.i("Upstream network lost: " + network);
815 
816             // TODO: disable border routing when upsteam network disconnected
817         }
818 
819         @Override
onLinkPropertiesChanged( @onNull Network network, @NonNull LinkProperties newLinkProperties)820         public void onLinkPropertiesChanged(
821                 @NonNull Network network, @NonNull LinkProperties newLinkProperties) {
822             checkOnHandlerThread();
823 
824             LinkProperties oldLinkProperties = mNetworkToLinkProperties.get(network);
825             if (Objects.equals(oldLinkProperties, newLinkProperties)) {
826                 return;
827             }
828             LOG.i("Upstream network changed: " + oldLinkProperties + " -> " + newLinkProperties);
829             mNetworkToLinkProperties.put(network, newLinkProperties);
830 
831             // TODO: disable border routing if netIfName is null
832             if (network.equals(mUpstreamNetwork)) {
833                 setInfraLinkState(newInfraLinkStateBuilder(newLinkProperties).build());
834             }
835         }
836     }
837 
838     private final class ThreadNetworkCallback extends ConnectivityManager.NetworkCallback {
839         @Override
onAvailable(@onNull Network network)840         public void onAvailable(@NonNull Network network) {
841             checkOnHandlerThread();
842             LOG.i("Thread network is available: " + network);
843         }
844 
845         @Override
onLost(@onNull Network network)846         public void onLost(@NonNull Network network) {
847             checkOnHandlerThread();
848             LOG.i("Thread network is lost: " + network);
849             setInfraLinkState(newInfraLinkStateBuilder().build());
850         }
851 
852         @Override
onLocalNetworkInfoChanged( @onNull Network network, @NonNull LocalNetworkInfo localNetworkInfo)853         public void onLocalNetworkInfoChanged(
854                 @NonNull Network network, @NonNull LocalNetworkInfo localNetworkInfo) {
855             checkOnHandlerThread();
856             LOG.i(
857                     "LocalNetworkInfo of Thread network changed: {threadNetwork: "
858                             + network
859                             + ", localNetworkInfo: "
860                             + localNetworkInfo
861                             + "}");
862             mUpstreamNetwork = localNetworkInfo.getUpstreamNetwork();
863             if (mUpstreamNetwork == null) {
864                 setInfraLinkState(newInfraLinkStateBuilder().build());
865                 return;
866             }
867             if (mNetworkToLinkProperties.containsKey(mUpstreamNetwork)) {
868                 setInfraLinkState(
869                         newInfraLinkStateBuilder(mNetworkToLinkProperties.get(mUpstreamNetwork))
870                                 .build());
871             }
872             mNsdPublisher.setNetworkForHostResolution(mUpstreamNetwork);
873         }
874     }
875 
registerThreadNetworkCallback()876     private void registerThreadNetworkCallback() {
877         if (mThreadNetworkCallback != null) {
878             return;
879         }
880 
881         mThreadNetworkCallback = new ThreadNetworkCallback();
882         NetworkRequest request =
883                 new NetworkRequest.Builder()
884                         // clearCapabilities() is needed to remove forbidden capabilities and UID
885                         // requirement.
886                         .clearCapabilities()
887                         .addTransportType(TRANSPORT_THREAD)
888                         .addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)
889                         .build();
890         mConnectivityManager.registerNetworkCallback(request, mThreadNetworkCallback, mHandler);
891     }
892 
unregisterThreadNetworkCallback()893     private void unregisterThreadNetworkCallback() {
894         if (mThreadNetworkCallback == null) {
895             return;
896         }
897         mConnectivityManager.unregisterNetworkCallback(mThreadNetworkCallback);
898         mThreadNetworkCallback = null;
899     }
900 
901     /** Injects a {@link NetworkAgent} for testing. */
902     @VisibleForTesting
setTestNetworkAgent(@ullable NetworkAgent testNetworkAgent)903     void setTestNetworkAgent(@Nullable NetworkAgent testNetworkAgent) {
904         mTestNetworkAgent = testNetworkAgent;
905     }
906 
newNetworkAgent()907     private NetworkAgent newNetworkAgent() {
908         if (mTestNetworkAgent != null) {
909             return mTestNetworkAgent;
910         }
911 
912         final var netCapsBuilder =
913                 new NetworkCapabilities.Builder()
914                         .addTransportType(TRANSPORT_THREAD)
915                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
916                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
917         final var scoreBuilder = new NetworkScore.Builder();
918 
919         netCapsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK);
920         scoreBuilder.setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_LOCAL_NETWORK);
921 
922         return new NetworkAgent(
923                 mContext,
924                 mHandler.getLooper(),
925                 LOG.getTag(),
926                 netCapsBuilder.build(),
927                 getTunIfLinkProperties(),
928                 newLocalNetworkConfig(),
929                 scoreBuilder.build(),
930                 new NetworkAgentConfig.Builder().build(),
931                 mNetworkProvider) {
932 
933             // TODO(b/374037595): use NetworkFactory to handle dynamic network requests
934             @Override
935             public void onNetworkUnwanted() {
936                 LOG.i("Thread network is unwanted by ConnectivityService");
937                 // TODO(b/374037595): leave() the current network when the new APIs for mobile
938                 // is available
939             }
940         };
941     }
942 
943     private LocalNetworkConfig newLocalNetworkConfig() {
944         return new LocalNetworkConfig.Builder()
945                 .setUpstreamMulticastRoutingConfig(mUpstreamMulticastRoutingConfig)
946                 .setDownstreamMulticastRoutingConfig(mDownstreamMulticastRoutingConfig)
947                 .setUpstreamSelector(mUpstreamNetworkRequest)
948                 .build();
949     }
950 
951     private void registerThreadNetwork() {
952         if (mNetworkAgent != null) {
953             return;
954         }
955 
956         mNetworkAgent = newNetworkAgent();
957         mNetworkAgent.register();
958         mNetworkAgent.markConnected();
959         LOG.i("Registered Thread network");
960     }
961 
962     private void unregisterThreadNetwork() {
963         if (mNetworkAgent == null) {
964             // unregisterThreadNetwork can be called every time this device becomes detached or
965             // disabled and the mNetworkAgent may not be created in this cases
966             return;
967         }
968 
969         LOG.v("Unregistering Thread network agent");
970 
971         mNetworkAgent.unregister();
972         mNetworkAgent = null;
973     }
974 
975     @Override
976     public int getThreadVersion() {
977         return THREAD_VERSION_1_3;
978     }
979 
980     @Override
981     public void activateEphemeralKeyMode(long lifetimeMillis, IOperationReceiver receiver) {
982         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
983 
984         mHandler.post(
985                 () ->
986                         activateEphemeralKeyModeInternal(
987                                 lifetimeMillis, new OperationReceiverWrapper(receiver)));
988     }
989 
990     private void activateEphemeralKeyModeInternal(
991             long lifetimeMillis, OperationReceiverWrapper receiver) {
992         checkOnHandlerThread();
993 
994         if (!isBorderRouterMode()) {
995             receiver.onError(
996                     ERROR_FAILED_PRECONDITION, "This device is not configured a Border Router");
997             return;
998         }
999 
1000         try {
1001             getOtDaemon().activateEphemeralKeyMode(lifetimeMillis, newOtStatusReceiver(receiver));
1002         } catch (RemoteException | ThreadNetworkException e) {
1003             LOG.e("otDaemon.activateEphemeralKeyMode failed", e);
1004             receiver.onError(e);
1005         }
1006     }
1007 
1008     @Override
1009     public void deactivateEphemeralKeyMode(IOperationReceiver receiver) {
1010         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1011 
1012         mHandler.post(
1013                 () -> deactivateEphemeralKeyModeInternal(new OperationReceiverWrapper(receiver)));
1014     }
1015 
1016     private void deactivateEphemeralKeyModeInternal(OperationReceiverWrapper receiver) {
1017         checkOnHandlerThread();
1018 
1019         if (!isBorderRouterMode()) {
1020             receiver.onError(
1021                     ERROR_FAILED_PRECONDITION, "This device is not configured a Border Router");
1022             return;
1023         }
1024 
1025         try {
1026             getOtDaemon().deactivateEphemeralKeyMode(newOtStatusReceiver(receiver));
1027         } catch (RemoteException | ThreadNetworkException e) {
1028             LOG.e("otDaemon.deactivateEphemeralKeyMode failed", e);
1029             receiver.onError(e);
1030         }
1031     }
1032 
1033     @Override
1034     public void createRandomizedDataset(
1035             String networkName, IActiveOperationalDatasetReceiver receiver) {
1036         ActiveOperationalDatasetReceiverWrapper receiverWrapper =
1037                 new ActiveOperationalDatasetReceiverWrapper(receiver);
1038         mHandler.post(() -> createRandomizedDatasetInternal(networkName, receiverWrapper));
1039     }
1040 
1041     private void createRandomizedDatasetInternal(
1042             String networkName, @NonNull ActiveOperationalDatasetReceiverWrapper receiver) {
1043         checkOnHandlerThread();
1044 
1045         try {
1046             getOtDaemon().getChannelMasks(newChannelMasksReceiver(networkName, receiver));
1047         } catch (RemoteException | ThreadNetworkException e) {
1048             LOG.e("otDaemon.getChannelMasks failed", e);
1049             receiver.onError(e);
1050         }
1051     }
1052 
1053     private IChannelMasksReceiver newChannelMasksReceiver(
1054             String networkName, ActiveOperationalDatasetReceiverWrapper receiver) {
1055         return new IChannelMasksReceiver.Stub() {
1056             @Override
1057             public void onSuccess(int supportedChannelMask, int preferredChannelMask) {
1058                 ActiveOperationalDataset dataset =
1059                         createRandomizedDataset(
1060                                 networkName,
1061                                 supportedChannelMask,
1062                                 preferredChannelMask,
1063                                 new Random(),
1064                                 new SecureRandom());
1065 
1066                 receiver.onSuccess(dataset);
1067             }
1068 
1069             @Override
1070             public void onError(int errorCode, String errorMessage) {
1071                 receiver.onError(otErrorToAndroidError(errorCode), errorMessage);
1072             }
1073         };
1074     }
1075 
1076     private static ActiveOperationalDataset createRandomizedDataset(
1077             String networkName,
1078             int supportedChannelMask,
1079             int preferredChannelMask,
1080             Random random,
1081             SecureRandom secureRandom) {
1082         boolean authoritative = false;
1083         Instant now = Instant.now();
1084         try {
1085             Clock clock = SystemClock.currentNetworkTimeClock();
1086             now = clock.instant();
1087             authoritative = true;
1088         } catch (DateTimeException e) {
1089             LOG.w("Failed to get authoritative time: " + e.getMessage());
1090         }
1091 
1092         int panId = random.nextInt(/* bound= */ 0xffff);
1093         final byte[] meshLocalPrefix = newRandomBytes(random, LENGTH_MESH_LOCAL_PREFIX_BITS / 8);
1094         meshLocalPrefix[0] = MESH_LOCAL_PREFIX_FIRST_BYTE;
1095 
1096         final SparseArray<byte[]> channelMask = new SparseArray<>(1);
1097         channelMask.put(CHANNEL_PAGE_24_GHZ, channelMaskToByteArray(supportedChannelMask));
1098         final int channel = selectChannel(supportedChannelMask, preferredChannelMask, random);
1099 
1100         final byte[] securityFlags = new byte[] {(byte) 0xff, (byte) 0xf8};
1101 
1102         return new ActiveOperationalDataset.Builder()
1103                 .setActiveTimestamp(OperationalDatasetTimestamp.fromInstant(now, authoritative))
1104                 .setExtendedPanId(newRandomBytes(random, LENGTH_EXTENDED_PAN_ID))
1105                 .setPanId(panId)
1106                 .setNetworkName(networkName)
1107                 .setChannel(CHANNEL_PAGE_24_GHZ, channel)
1108                 .setChannelMask(channelMask)
1109                 .setPskc(newRandomBytes(secureRandom, LENGTH_PSKC))
1110                 .setNetworkKey(newRandomBytes(secureRandom, LENGTH_NETWORK_KEY))
1111                 .setMeshLocalPrefix(meshLocalPrefix)
1112                 .setSecurityPolicy(new SecurityPolicy(DEFAULT_ROTATION_TIME_HOURS, securityFlags))
1113                 .build();
1114     }
1115 
1116     private static int selectChannel(
1117             int supportedChannelMask, int preferredChannelMask, Random random) {
1118         // Due to radio hardware performance reasons, many Thread radio chips need to reduce their
1119         // transmit power on edge channels to pass regulatory RF certification. Thread edge channel
1120         // 25 and 26 are not preferred here.
1121         //
1122         // If users want to use channel 25 or 26, they can change the channel via the method
1123         // ActiveOperationalDataset.Builder(activeOperationalDataset).setChannel(channel).build().
1124         preferredChannelMask = preferredChannelMask & CHANNEL_MASK_11_TO_24;
1125 
1126         // If the preferred channel mask is not empty, select a random channel from it, otherwise
1127         // choose one from the supported channel mask.
1128         preferredChannelMask = preferredChannelMask & supportedChannelMask;
1129         if (preferredChannelMask == 0) {
1130             preferredChannelMask = supportedChannelMask;
1131         }
1132 
1133         return selectRandomChannel(preferredChannelMask, random);
1134     }
1135 
1136     private static byte[] newRandomBytes(Random random, int length) {
1137         byte[] result = new byte[length];
1138         random.nextBytes(result);
1139         return result;
1140     }
1141 
1142     private static byte[] channelMaskToByteArray(int channelMask) {
1143         // Per Thread spec, a Channel Mask is:
1144         // A variable-length bit mask that identifies the channels within the channel page
1145         // (1 = selected, 0 = unselected). The channels are represented in most significant bit
1146         // order. For example, the most significant bit of the left-most byte indicates channel 0.
1147         // If channel 0 and channel 10 are selected, the mask would be: 80 20 00 00. For IEEE
1148         // 802.15.4-2006 2.4 GHz PHY, the ChannelMask is 27 bits and MaskLength is 4.
1149         //
1150         // The pass-in channelMask represents a channel K by (channelMask & (1 << K)), so here
1151         // needs to do bit-wise reverse to convert it to the Thread spec format in bytes.
1152         channelMask = Integer.reverse(channelMask);
1153         return new byte[] {
1154             (byte) (channelMask >>> 24),
1155             (byte) (channelMask >>> 16),
1156             (byte) (channelMask >>> 8),
1157             (byte) channelMask
1158         };
1159     }
1160 
1161     private static int selectRandomChannel(int supportedChannelMask, Random random) {
1162         int num = random.nextInt(Integer.bitCount(supportedChannelMask));
1163         for (int i = 0; i < 32; i++) {
1164             if ((supportedChannelMask & 1) == 1 && (num--) == 0) {
1165                 return i;
1166             }
1167             supportedChannelMask >>>= 1;
1168         }
1169         return -1;
1170     }
1171 
1172     private void enforceAllPermissionsGranted(String... permissions) {
1173         for (String permission : permissions) {
1174             mContext.enforceCallingOrSelfPermission(
1175                     permission, "Permission " + permission + " is missing");
1176         }
1177     }
1178 
1179     @Override
1180     public void registerStateCallback(IStateCallback stateCallback) throws RemoteException {
1181         enforceAllPermissionsGranted(permission.ACCESS_NETWORK_STATE);
1182         boolean hasThreadPrivilegedPermission =
1183                 (mContext.checkCallingOrSelfPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
1184                         == PERMISSION_GRANTED);
1185 
1186         mHandler.post(
1187                 () ->
1188                         mOtDaemonCallbackProxy.registerStateCallback(
1189                                 stateCallback, hasThreadPrivilegedPermission));
1190     }
1191 
1192     @Override
1193     public void unregisterStateCallback(IStateCallback stateCallback) throws RemoteException {
1194         enforceAllPermissionsGranted(permission.ACCESS_NETWORK_STATE);
1195         mHandler.post(() -> mOtDaemonCallbackProxy.unregisterStateCallback(stateCallback));
1196     }
1197 
1198     @Override
1199     public void registerOperationalDatasetCallback(IOperationalDatasetCallback callback)
1200             throws RemoteException {
1201         enforceAllPermissionsGranted(
1202                 permission.ACCESS_NETWORK_STATE, PERMISSION_THREAD_NETWORK_PRIVILEGED);
1203         mHandler.post(() -> mOtDaemonCallbackProxy.registerDatasetCallback(callback));
1204     }
1205 
1206     @Override
1207     public void unregisterOperationalDatasetCallback(IOperationalDatasetCallback callback)
1208             throws RemoteException {
1209         enforceAllPermissionsGranted(
1210                 permission.ACCESS_NETWORK_STATE, PERMISSION_THREAD_NETWORK_PRIVILEGED);
1211         mHandler.post(() -> mOtDaemonCallbackProxy.unregisterDatasetCallback(callback));
1212     }
1213 
1214     private void checkOnHandlerThread() {
1215         if (Looper.myLooper() != mHandler.getLooper()) {
1216             throw new IllegalStateException(
1217                     "Not running on ThreadNetworkControllerService thread ("
1218                             + mHandler.getLooper()
1219                             + ") : "
1220                             + Looper.myLooper());
1221         }
1222     }
1223 
1224     private IOtStatusReceiver newOtStatusReceiver(OperationReceiverWrapper receiver) {
1225         return new IOtStatusReceiver.Stub() {
1226             @Override
1227             public void onSuccess() {
1228                 receiver.onSuccess();
1229             }
1230 
1231             @Override
1232             public void onError(int otError, String message) {
1233                 receiver.onError(otErrorToAndroidError(otError), message);
1234             }
1235         };
1236     }
1237 
1238     private IOtOutputReceiver newOtOutputReceiver(OutputReceiverWrapper receiver) {
1239         return new IOtOutputReceiver.Stub() {
1240             @Override
1241             public void onOutput(String output) {
1242                 receiver.onOutput(output);
1243             }
1244 
1245             @Override
1246             public void onComplete() {
1247                 receiver.onComplete();
1248             }
1249 
1250             @Override
1251             public void onError(int otError, String message) {
1252                 receiver.onError(otErrorToAndroidError(otError), message);
1253             }
1254         };
1255     }
1256 
1257     @ErrorCode
1258     private static int otErrorToAndroidError(int otError) {
1259         // See external/openthread/include/openthread/error.h for OT error definition
1260         switch (otError) {
1261             case OT_ERROR_ABORT:
1262                 return ERROR_ABORTED;
1263             case OT_ERROR_BUSY:
1264                 return ERROR_BUSY;
1265             case OT_ERROR_NOT_IMPLEMENTED:
1266                 return ERROR_UNSUPPORTED_FEATURE;
1267             case OT_ERROR_NO_BUFS:
1268                 return ERROR_RESOURCE_EXHAUSTED;
1269             case OT_ERROR_PARSE:
1270                 return ERROR_RESPONSE_BAD_FORMAT;
1271             case OT_ERROR_REASSEMBLY_TIMEOUT:
1272             case OT_ERROR_RESPONSE_TIMEOUT:
1273                 return ERROR_TIMEOUT;
1274             case OT_ERROR_REJECTED:
1275                 return ERROR_REJECTED_BY_PEER;
1276             case OT_ERROR_UNSUPPORTED_CHANNEL:
1277                 return ERROR_UNSUPPORTED_CHANNEL;
1278             case OT_ERROR_THREAD_DISABLED:
1279                 return ERROR_THREAD_DISABLED;
1280             case OT_ERROR_FAILED_PRECONDITION:
1281                 return ERROR_FAILED_PRECONDITION;
1282             case OT_ERROR_INVALID_STATE:
1283             default:
1284                 return ERROR_INTERNAL_ERROR;
1285         }
1286     }
1287 
1288     @Override
1289     public void join(
1290             @NonNull ActiveOperationalDataset activeDataset, @NonNull IOperationReceiver receiver) {
1291         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1292 
1293         OperationReceiverWrapper receiverWrapper = new OperationReceiverWrapper(receiver);
1294         mHandler.post(() -> joinInternal(activeDataset, receiverWrapper));
1295     }
1296 
1297     private void joinInternal(
1298             @NonNull ActiveOperationalDataset activeDataset,
1299             @NonNull OperationReceiverWrapper receiver) {
1300         checkOnHandlerThread();
1301 
1302         try {
1303             // The otDaemon.join() will leave first if this device is currently attached
1304             getOtDaemon().join(activeDataset.toThreadTlvs(), newOtStatusReceiver(receiver));
1305         } catch (RemoteException | ThreadNetworkException e) {
1306             LOG.e("otDaemon.join failed", e);
1307             receiver.onError(e);
1308         }
1309     }
1310 
1311     @Override
1312     public void scheduleMigration(
1313             @NonNull PendingOperationalDataset pendingDataset,
1314             @NonNull IOperationReceiver receiver) {
1315         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1316 
1317         OperationReceiverWrapper receiverWrapper = new OperationReceiverWrapper(receiver);
1318         mHandler.post(() -> scheduleMigrationInternal(pendingDataset, receiverWrapper));
1319     }
1320 
1321     public void scheduleMigrationInternal(
1322             @NonNull PendingOperationalDataset pendingDataset,
1323             @NonNull OperationReceiverWrapper receiver) {
1324         checkOnHandlerThread();
1325 
1326         try {
1327             getOtDaemon()
1328                     .scheduleMigration(
1329                             pendingDataset.toThreadTlvs(), newOtStatusReceiver(receiver));
1330         } catch (RemoteException | ThreadNetworkException e) {
1331             LOG.e("otDaemon.scheduleMigration failed", e);
1332             receiver.onError(e);
1333         }
1334     }
1335 
1336     @Override
1337     public void leave(@NonNull IOperationReceiver receiver) {
1338         leave(true /* eraseDataset */, receiver);
1339     }
1340 
1341     private void leave(boolean eraseDataset, @NonNull IOperationReceiver receiver) {
1342         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1343 
1344         mHandler.post(() -> leaveInternal(eraseDataset, new OperationReceiverWrapper(receiver)));
1345     }
1346 
1347     private void leaveInternal(boolean eraseDataset, @NonNull OperationReceiverWrapper receiver) {
1348         checkOnHandlerThread();
1349 
1350         try {
1351             getOtDaemon().leave(eraseDataset, newOtStatusReceiver(receiver));
1352         } catch (RemoteException | ThreadNetworkException e) {
1353             LOG.e("otDaemon.leave failed", e);
1354             receiver.onError(e);
1355         }
1356     }
1357 
1358     /**
1359      * Sets the country code.
1360      *
1361      * @param countryCode 2 characters string country code (as defined in ISO 3166) to set.
1362      * @param receiver the receiver to receive result of this operation
1363      */
1364     @RequiresPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
1365     public void setCountryCode(@NonNull String countryCode, @NonNull IOperationReceiver receiver) {
1366         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1367 
1368         OperationReceiverWrapper receiverWrapper = new OperationReceiverWrapper(receiver);
1369         mHandler.post(() -> setCountryCodeInternal(countryCode, receiverWrapper));
1370     }
1371 
1372     private void setCountryCodeInternal(
1373             String countryCode, @NonNull OperationReceiverWrapper receiver) {
1374         checkOnHandlerThread();
1375 
1376         // Fails early to avoid waking up ot-daemon by the ThreadNetworkCountryCode class
1377         if (!shouldEnableThread()) {
1378             receiver.onError(
1379                     ERROR_THREAD_DISABLED, "Can't set country code when Thread is disabled");
1380             return;
1381         }
1382 
1383         try {
1384             getOtDaemon().setCountryCode(countryCode, newOtStatusReceiver(receiver));
1385         } catch (RemoteException | ThreadNetworkException e) {
1386             LOG.e("otDaemon.setCountryCode failed", e);
1387             receiver.onError(e);
1388         }
1389     }
1390 
1391     @Override
1392     public void setTestNetworkAsUpstream(
1393             @Nullable String testNetworkInterfaceName, @NonNull IOperationReceiver receiver) {
1394         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED, NETWORK_SETTINGS);
1395 
1396         LOG.i("setTestNetworkAsUpstream: " + testNetworkInterfaceName);
1397         mHandler.post(() -> setTestNetworkAsUpstreamInternal(testNetworkInterfaceName, receiver));
1398     }
1399 
1400     private void setTestNetworkAsUpstreamInternal(
1401             @Nullable String testNetworkInterfaceName, @NonNull IOperationReceiver receiver) {
1402         checkOnHandlerThread();
1403 
1404         TestNetworkSpecifier testNetworkSpecifier = null;
1405         if (testNetworkInterfaceName != null) {
1406             testNetworkSpecifier = new TestNetworkSpecifier(testNetworkInterfaceName);
1407         }
1408 
1409         if (!Objects.equals(mUpstreamTestNetworkSpecifier, testNetworkSpecifier)) {
1410             cancelRequestUpstreamNetwork();
1411             mUpstreamTestNetworkSpecifier = testNetworkSpecifier;
1412             mUpstreamNetworkRequest = newUpstreamNetworkRequest();
1413             requestUpstreamNetwork();
1414             sendLocalNetworkConfig();
1415         }
1416         try {
1417             receiver.onSuccess();
1418         } catch (RemoteException ignored) {
1419             // do nothing if the client is dead
1420         }
1421     }
1422 
1423     @RequiresPermission(PERMISSION_THREAD_NETWORK_PRIVILEGED)
1424     public void setChannelMaxPowers(
1425             @NonNull ChannelMaxPower[] channelMaxPowers, @NonNull IOperationReceiver receiver) {
1426         enforceAllPermissionsGranted(PERMISSION_THREAD_NETWORK_PRIVILEGED);
1427 
1428         mHandler.post(
1429                 () ->
1430                         setChannelMaxPowersInternal(
1431                                 channelMaxPowers, new OperationReceiverWrapper(receiver)));
1432     }
1433 
1434     private void setChannelMaxPowersInternal(
1435             @NonNull ChannelMaxPower[] channelMaxPowers,
1436             @NonNull OperationReceiverWrapper receiver) {
1437         checkOnHandlerThread();
1438 
1439         try {
1440             getOtDaemon().setChannelMaxPowers(channelMaxPowers, newOtStatusReceiver(receiver));
1441         } catch (RemoteException | ThreadNetworkException e) {
1442             LOG.e("otDaemon.setChannelMaxPowers failed", e);
1443             receiver.onError(ERROR_INTERNAL_ERROR, "Thread stack error");
1444         }
1445     }
1446 
1447     private void setInfraLinkState(InfraLinkState newInfraLinkState) {
1448         if (Objects.equals(mInfraLinkState, newInfraLinkState)) {
1449             return;
1450         }
1451         LOG.i("Infra link state changed: " + mInfraLinkState + " -> " + newInfraLinkState);
1452         setInfraLinkInterfaceName(newInfraLinkState.interfaceName);
1453         setInfraLinkNat64Prefix(newInfraLinkState.nat64Prefix);
1454         setInfraLinkDnsServers(newInfraLinkState.dnsServers);
1455         mInfraLinkState = newInfraLinkState;
1456     }
1457 
1458     private void setInfraLinkInterfaceName(String newInfraLinkInterfaceName) {
1459         if (Objects.equals(mInfraLinkState.interfaceName, newInfraLinkInterfaceName)) {
1460             return;
1461         }
1462         ParcelFileDescriptor infraIcmp6Socket = null;
1463         if (newInfraLinkInterfaceName != null) {
1464             try {
1465                 infraIcmp6Socket = mInfraIfController.createIcmp6Socket(newInfraLinkInterfaceName);
1466             } catch (IOException e) {
1467                 LOG.e("Failed to create ICMPv6 socket on infra network interface", e);
1468             }
1469         }
1470         try {
1471             getOtDaemon()
1472                     .setInfraLinkInterfaceName(
1473                             newInfraLinkInterfaceName,
1474                             infraIcmp6Socket,
1475                             new LoggingOtStatusReceiver("setInfraLinkInterfaceName"));
1476         } catch (RemoteException | ThreadNetworkException e) {
1477             LOG.e("Failed to set infra link interface name " + newInfraLinkInterfaceName, e);
1478         }
1479     }
1480 
1481     private void setInfraLinkNat64Prefix(@Nullable String newNat64Prefix) {
1482         if (Objects.equals(newNat64Prefix, mInfraLinkState.nat64Prefix)) {
1483             return;
1484         }
1485         try {
1486             getOtDaemon()
1487                     .setInfraLinkNat64Prefix(
1488                             newNat64Prefix, new LoggingOtStatusReceiver("setInfraLinkNat64Prefix"));
1489         } catch (RemoteException | ThreadNetworkException e) {
1490             LOG.e("Failed to set infra link NAT64 prefix " + newNat64Prefix, e);
1491         }
1492     }
1493 
1494     private void setInfraLinkDnsServers(List<String> newDnsServers) {
1495         if (Objects.equals(newDnsServers, mInfraLinkState.dnsServers)) {
1496             return;
1497         }
1498         try {
1499             getOtDaemon()
1500                     .setInfraLinkDnsServers(
1501                             newDnsServers, new LoggingOtStatusReceiver("setInfraLinkDnsServers"));
1502         } catch (RemoteException | ThreadNetworkException e) {
1503             LOG.e("Failed to set infra link DNS servers " + newDnsServers, e);
1504         }
1505     }
1506 
1507     private void disableBorderRouting() {
1508         LOG.i("Disabling border routing");
1509         setInfraLinkState(newInfraLinkStateBuilder().build());
1510     }
1511 
1512     private void handleThreadInterfaceStateChanged(boolean isUp) {
1513         try {
1514             mTunIfController.setInterfaceUp(isUp);
1515             LOG.i("Thread TUN interface becomes " + (isUp ? "up" : "down"));
1516         } catch (IOException e) {
1517             LOG.e("Failed to handle Thread interface state changes", e);
1518         }
1519     }
1520 
1521     private void handleDeviceRoleChanged(@DeviceRole int deviceRole) {
1522         if (ThreadNetworkController.isAttached(deviceRole)) {
1523             LOG.i("Attached to the Thread network");
1524 
1525             // This is an idempotent method which can be called for multiple times when the device
1526             // is already attached (e.g. going from Child to Router)
1527             registerThreadNetwork();
1528         } else {
1529             LOG.i("Detached from the Thread network");
1530 
1531             // This is an idempotent method which can be called for multiple times when the device
1532             // is already detached or stopped
1533             unregisterThreadNetwork();
1534         }
1535     }
1536 
1537     private void handleAddressChanged(List<Ipv6AddressInfo> addressInfoList) {
1538         checkOnHandlerThread();
1539 
1540         mTunIfController.updateAddresses(addressInfoList);
1541 
1542         // The OT daemon can send link property updates before the networkAgent is
1543         // registered
1544         maybeSendLinkProperties();
1545     }
1546 
1547     private void handlePrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
1548         checkOnHandlerThread();
1549 
1550         mTunIfController.updatePrefixes(onMeshPrefixConfigList);
1551 
1552         // The OT daemon can send link property updates before the networkAgent is
1553         // registered
1554         maybeSendLinkProperties();
1555     }
1556 
1557     private void maybeSendLinkProperties() {
1558         if (mNetworkAgent == null) {
1559             return;
1560         }
1561         mNetworkAgent.sendLinkProperties(getTunIfLinkProperties());
1562     }
1563 
1564     private LinkProperties getTunIfLinkProperties() {
1565         return mTunIfController.getLinkPropertiesWithNat64Cidr(mNat64CidrController.mNat64Cidr);
1566     }
1567 
1568     @RequiresPermission(
1569             allOf = {PERMISSION_THREAD_NETWORK_PRIVILEGED, PERMISSION_THREAD_NETWORK_TESTING})
1570     public void runOtCtlCommand(
1571             @NonNull String command, boolean isInteractive, @NonNull IOutputReceiver receiver) {
1572         enforceAllPermissionsGranted(
1573                 PERMISSION_THREAD_NETWORK_PRIVILEGED, PERMISSION_THREAD_NETWORK_TESTING);
1574 
1575         mHandler.post(
1576                 () ->
1577                         runOtCtlCommandInternal(
1578                                 command, isInteractive, new OutputReceiverWrapper(receiver)));
1579     }
1580 
1581     private void runOtCtlCommandInternal(
1582             String command, boolean isInteractive, @NonNull OutputReceiverWrapper receiver) {
1583         checkOnHandlerThread();
1584 
1585         try {
1586             getOtDaemon().runOtCtlCommand(command, isInteractive, newOtOutputReceiver(receiver));
1587         } catch (RemoteException | ThreadNetworkException e) {
1588             LOG.e("otDaemon.runOtCtlCommand failed", e);
1589             receiver.onError(ERROR_INTERNAL_ERROR, "Thread stack error");
1590         }
1591     }
1592 
1593     private void sendLocalNetworkConfig() {
1594         if (mNetworkAgent == null) {
1595             return;
1596         }
1597         final LocalNetworkConfig localNetworkConfig = newLocalNetworkConfig();
1598         mNetworkAgent.sendLocalNetworkConfig(localNetworkConfig);
1599         LOG.v("Sent localNetworkConfig: " + localNetworkConfig);
1600     }
1601 
1602     private void handleMulticastForwardingChanged(BackboneRouterState state) {
1603         MulticastRoutingConfig upstreamMulticastRoutingConfig;
1604         MulticastRoutingConfig downstreamMulticastRoutingConfig;
1605 
1606         if (state.multicastForwardingEnabled) {
1607             // When multicast forwarding is enabled, setup upstream forwarding to any address
1608             // with minimal scope 4
1609             // setup downstream forwarding with addresses subscribed from Thread network
1610             upstreamMulticastRoutingConfig =
1611                     new MulticastRoutingConfig.Builder(FORWARD_WITH_MIN_SCOPE, 4).build();
1612             downstreamMulticastRoutingConfig =
1613                     buildDownstreamMulticastRoutingConfigSelected(state.listeningAddresses);
1614         } else {
1615             // When multicast forwarding is disabled, set both upstream and downstream
1616             // forwarding config to FORWARD_NONE.
1617             upstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
1618             downstreamMulticastRoutingConfig = CONFIG_FORWARD_NONE;
1619         }
1620 
1621         if (upstreamMulticastRoutingConfig.equals(mUpstreamMulticastRoutingConfig)
1622                 && downstreamMulticastRoutingConfig.equals(mDownstreamMulticastRoutingConfig)) {
1623             return;
1624         }
1625 
1626         mUpstreamMulticastRoutingConfig = upstreamMulticastRoutingConfig;
1627         mDownstreamMulticastRoutingConfig = downstreamMulticastRoutingConfig;
1628         sendLocalNetworkConfig();
1629     }
1630 
1631     private MulticastRoutingConfig buildDownstreamMulticastRoutingConfigSelected(
1632             List<String> listeningAddresses) {
1633         MulticastRoutingConfig.Builder builder =
1634                 new MulticastRoutingConfig.Builder(FORWARD_SELECTED);
1635         for (String addressStr : listeningAddresses) {
1636             Inet6Address address = (Inet6Address) InetAddresses.parseNumericAddress(addressStr);
1637             builder.addListeningAddress(address);
1638         }
1639         return builder.build();
1640     }
1641 
1642     private static InfraLinkState.Builder newInfraLinkStateBuilder() {
1643         return new InfraLinkState.Builder().setInterfaceName("");
1644     }
1645 
1646     private static InfraLinkState.Builder newInfraLinkStateBuilder(
1647             @Nullable LinkProperties linkProperties) {
1648         if (linkProperties == null) {
1649             return newInfraLinkStateBuilder();
1650         }
1651         String nat64Prefix = null;
1652         if (linkProperties.getNat64Prefix() != null) {
1653             nat64Prefix = linkProperties.getNat64Prefix().toString();
1654         }
1655         return new InfraLinkState.Builder()
1656                 .setInterfaceName(linkProperties.getInterfaceName())
1657                 .setNat64Prefix(nat64Prefix)
1658                 .setDnsServers(addressesToStrings(linkProperties.getDnsServers()));
1659     }
1660 
1661     private static List<String> addressesToStrings(List<InetAddress> addresses) {
1662         List<String> strings = new ArrayList<>();
1663 
1664         for (InetAddress address : addresses) {
1665             strings.add(address.getHostAddress());
1666         }
1667         return strings;
1668     }
1669 
1670     private static final class CallbackMetadata {
1671         private static long gId = 0;
1672 
1673         // The unique ID
1674         final long id;
1675 
1676         final IBinder.DeathRecipient deathRecipient;
1677 
1678         final boolean hasThreadPrivilegedPermission;
1679 
1680         CallbackMetadata(
1681                 IBinder.DeathRecipient deathRecipient, boolean hasThreadPrivilegedPermission) {
1682             this.id = allocId();
1683             this.deathRecipient = deathRecipient;
1684             this.hasThreadPrivilegedPermission = hasThreadPrivilegedPermission;
1685         }
1686 
1687         private static long allocId() {
1688             if (gId == Long.MAX_VALUE) {
1689                 gId = 0;
1690             }
1691             return gId++;
1692         }
1693     }
1694 
1695     /** An implementation of {@link IOperationReceiver} that simply logs the operation result. */
1696     private static class LoggingOperationReceiver extends IOperationReceiver.Stub {
1697         private final String mOperation;
1698 
1699         LoggingOperationReceiver(String operation) {
1700             mOperation = operation;
1701         }
1702 
1703         @Override
1704         public void onSuccess() {
1705             LOG.i("The operation " + mOperation + " succeeded");
1706         }
1707 
1708         @Override
1709         public void onError(int errorCode, String errorMessage) {
1710             LOG.w("The operation " + mOperation + " failed: " + errorCode + " " + errorMessage);
1711         }
1712     }
1713 
1714     private static class LoggingOtStatusReceiver extends IOtStatusReceiver.Stub {
1715         private final String mAction;
1716 
1717         LoggingOtStatusReceiver(String action) {
1718             mAction = action;
1719         }
1720 
1721         @Override
1722         public void onSuccess() {
1723             LOG.i("The action " + mAction + " succeeded");
1724         }
1725 
1726         @Override
1727         public void onError(int i, String s) {
1728             LOG.w("The action " + mAction + " failed: " + i + " " + s);
1729         }
1730     }
1731 
1732     /**
1733      * Handles and forwards Thread daemon callbacks. This class must be accessed from the thread of
1734      * {@code mHandler}.
1735      */
1736     private final class OtDaemonCallbackProxy extends IOtDaemonCallback.Stub {
1737         private final Map<IStateCallback, CallbackMetadata> mStateCallbacks = new HashMap<>();
1738         private final Map<IOperationalDatasetCallback, CallbackMetadata> mOpDatasetCallbacks =
1739                 new HashMap<>();
1740 
1741         private OtDaemonState mState;
1742         private ActiveOperationalDataset mActiveDataset;
1743         private PendingOperationalDataset mPendingDataset;
1744 
1745         public void registerStateCallback(
1746                 IStateCallback callback, boolean hasThreadPrivilegedPermission) {
1747             checkOnHandlerThread();
1748             if (mStateCallbacks.containsKey(callback)) {
1749                 throw new IllegalStateException("Registering the same IStateCallback twice");
1750             }
1751 
1752             IBinder.DeathRecipient deathRecipient =
1753                     () -> mHandler.post(() -> unregisterStateCallback(callback));
1754             CallbackMetadata callbackMetadata =
1755                     new CallbackMetadata(deathRecipient, hasThreadPrivilegedPermission);
1756             mStateCallbacks.put(callback, callbackMetadata);
1757             try {
1758                 callback.asBinder().linkToDeath(deathRecipient, 0);
1759             } catch (RemoteException e) {
1760                 mStateCallbacks.remove(callback);
1761                 // This is thrown when the client is dead, do nothing
1762             }
1763 
1764             try {
1765                 getOtDaemon().registerStateCallback(this, callbackMetadata.id);
1766             } catch (RemoteException | ThreadNetworkException e) {
1767                 LOG.e("otDaemon.registerStateCallback failed", e);
1768             }
1769         }
1770 
1771         public void unregisterStateCallback(IStateCallback callback) {
1772             checkOnHandlerThread();
1773             if (!mStateCallbacks.containsKey(callback)) {
1774                 return;
1775             }
1776             callback.asBinder().unlinkToDeath(mStateCallbacks.remove(callback).deathRecipient, 0);
1777         }
1778 
1779         public void registerDatasetCallback(IOperationalDatasetCallback callback) {
1780             checkOnHandlerThread();
1781             if (mOpDatasetCallbacks.containsKey(callback)) {
1782                 throw new IllegalStateException(
1783                         "Registering the same IOperationalDatasetCallback twice");
1784             }
1785 
1786             IBinder.DeathRecipient deathRecipient =
1787                     () -> mHandler.post(() -> unregisterDatasetCallback(callback));
1788             CallbackMetadata callbackMetadata =
1789                     new CallbackMetadata(deathRecipient, true /* hasThreadPrivilegedPermission */);
1790             mOpDatasetCallbacks.put(callback, callbackMetadata);
1791             try {
1792                 callback.asBinder().linkToDeath(deathRecipient, 0);
1793             } catch (RemoteException e) {
1794                 mOpDatasetCallbacks.remove(callback);
1795             }
1796 
1797             try {
1798                 getOtDaemon().registerStateCallback(this, callbackMetadata.id);
1799             } catch (RemoteException | ThreadNetworkException e) {
1800                 LOG.e("otDaemon.registerStateCallback failed", e);
1801             }
1802         }
1803 
1804         public void unregisterDatasetCallback(IOperationalDatasetCallback callback) {
1805             checkOnHandlerThread();
1806             if (!mOpDatasetCallbacks.containsKey(callback)) {
1807                 return;
1808             }
1809             callback.asBinder()
1810                     .unlinkToDeath(mOpDatasetCallbacks.remove(callback).deathRecipient, 0);
1811         }
1812 
1813         public void onOtDaemonDied() {
1814             checkOnHandlerThread();
1815             if (mState == null) {
1816                 return;
1817             }
1818 
1819             final int deviceRole = mState.deviceRole;
1820             mState = null;
1821 
1822             // If this device is already STOPPED or DETACHED, do nothing
1823             if (!ThreadNetworkController.isAttached(deviceRole)) {
1824                 return;
1825             }
1826 
1827             // The Thread device role is considered DETACHED when the OT daemon process is dead
1828             handleDeviceRoleChanged(DEVICE_ROLE_DETACHED);
1829             for (IStateCallback callback : mStateCallbacks.keySet()) {
1830                 try {
1831                     callback.onDeviceRoleChanged(DEVICE_ROLE_DETACHED);
1832                 } catch (RemoteException ignored) {
1833                     // do nothing if the client is dead
1834                 }
1835             }
1836             mInfraLinkState = newInfraLinkStateBuilder().build();
1837         }
1838 
1839         private void onThreadEnabledChanged(int state, long listenerId) {
1840             checkOnHandlerThread();
1841             boolean stateChanged = (mState == null || mState.threadEnabled != state);
1842 
1843             for (var callbackEntry : mStateCallbacks.entrySet()) {
1844                 if (!stateChanged && callbackEntry.getValue().id != listenerId) {
1845                     continue;
1846                 }
1847                 try {
1848                     callbackEntry.getKey().onThreadEnableStateChanged(otStateToAndroidState(state));
1849                 } catch (RemoteException ignored) {
1850                     // do nothing if the client is dead
1851                 }
1852             }
1853         }
1854 
1855         private static int otStateToAndroidState(int state) {
1856             switch (state) {
1857                 case OT_STATE_ENABLED:
1858                     return STATE_ENABLED;
1859                 case OT_STATE_DISABLED:
1860                     return STATE_DISABLED;
1861                 case OT_STATE_DISABLING:
1862                     return STATE_DISABLING;
1863                 default:
1864                     throw new IllegalArgumentException("Unknown ot state " + state);
1865             }
1866         }
1867 
1868         @Override
1869         public void onStateChanged(@NonNull OtDaemonState newState, long listenerId) {
1870             mHandler.post(() -> onStateChangedInternal(newState, listenerId));
1871         }
1872 
1873         private void onStateChangedInternal(OtDaemonState newState, long listenerId) {
1874             checkOnHandlerThread();
1875 
1876             onInterfaceStateChanged(newState.isInterfaceUp);
1877             onDeviceRoleChanged(newState.deviceRole, listenerId);
1878             onPartitionIdChanged(newState.partitionId, listenerId);
1879             onThreadEnabledChanged(newState.threadEnabled, listenerId);
1880             onEphemeralKeyStateChanged(newState, listenerId);
1881             mState = newState;
1882 
1883             ActiveOperationalDataset newActiveDataset;
1884             try {
1885                 if (newState.activeDatasetTlvs.length != 0) {
1886                     newActiveDataset =
1887                             ActiveOperationalDataset.fromThreadTlvs(newState.activeDatasetTlvs);
1888                 } else {
1889                     newActiveDataset = null;
1890                 }
1891                 onActiveOperationalDatasetChanged(newActiveDataset, listenerId);
1892                 mActiveDataset = newActiveDataset;
1893             } catch (IllegalArgumentException e) {
1894                 // Is unlikely that OT will generate invalid Operational Dataset
1895                 LOG.wtf("Invalid Active Operational Dataset from OpenThread", e);
1896             }
1897 
1898             PendingOperationalDataset newPendingDataset;
1899             try {
1900                 if (newState.pendingDatasetTlvs.length != 0) {
1901                     newPendingDataset =
1902                             PendingOperationalDataset.fromThreadTlvs(newState.pendingDatasetTlvs);
1903                 } else {
1904                     newPendingDataset = null;
1905                 }
1906                 onPendingOperationalDatasetChanged(newPendingDataset, listenerId);
1907                 mPendingDataset = newPendingDataset;
1908             } catch (IllegalArgumentException e) {
1909                 // Is unlikely that OT will generate invalid Operational Dataset
1910                 LOG.wtf("Invalid Pending Operational Dataset from OpenThread", e);
1911             }
1912         }
1913 
1914         private void onInterfaceStateChanged(boolean isUp) {
1915             checkOnHandlerThread();
1916             if (mState == null || mState.isInterfaceUp != isUp) {
1917                 handleThreadInterfaceStateChanged(isUp);
1918             }
1919         }
1920 
1921         private void onDeviceRoleChanged(@DeviceRole int deviceRole, long listenerId) {
1922             checkOnHandlerThread();
1923             boolean hasChange = (mState == null || mState.deviceRole != deviceRole);
1924             if (hasChange) {
1925                 handleDeviceRoleChanged(deviceRole);
1926             }
1927 
1928             for (var callbackEntry : mStateCallbacks.entrySet()) {
1929                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1930                     continue;
1931                 }
1932                 try {
1933                     callbackEntry.getKey().onDeviceRoleChanged(deviceRole);
1934                 } catch (RemoteException ignored) {
1935                     // do nothing if the client is dead
1936                 }
1937             }
1938         }
1939 
1940         private void onPartitionIdChanged(long partitionId, long listenerId) {
1941             checkOnHandlerThread();
1942             boolean hasChange = (mState == null || mState.partitionId != partitionId);
1943 
1944             for (var callbackEntry : mStateCallbacks.entrySet()) {
1945                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1946                     continue;
1947                 }
1948                 try {
1949                     callbackEntry.getKey().onPartitionIdChanged(partitionId);
1950                 } catch (RemoteException ignored) {
1951                     // do nothing if the client is dead
1952                 }
1953             }
1954         }
1955 
1956         private void onEphemeralKeyStateChanged(OtDaemonState newState, long listenerId) {
1957             checkOnHandlerThread();
1958             boolean hasChange = isEphemeralKeyStateChanged(mState, newState);
1959 
1960             for (var callbackEntry : mStateCallbacks.entrySet()) {
1961                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
1962                     continue;
1963                 }
1964                 String passcode =
1965                         callbackEntry.getValue().hasThreadPrivilegedPermission
1966                                 ? newState.ephemeralKeyPasscode
1967                                 : null;
1968                 if (newState.ephemeralKeyState == EPHEMERAL_KEY_DISABLED) {
1969                     passcode = null;
1970                 }
1971                 try {
1972                     callbackEntry
1973                             .getKey()
1974                             .onEphemeralKeyStateChanged(
1975                                     newState.ephemeralKeyState,
1976                                     passcode,
1977                                     newState.ephemeralKeyLifetimeMillis);
1978                 } catch (RemoteException ignored) {
1979                     // do nothing if the client is dead
1980                 }
1981             }
1982         }
1983 
1984         private static boolean isEphemeralKeyStateChanged(
1985                 OtDaemonState oldState, @NonNull OtDaemonState newState) {
1986             if (oldState == null) return true;
1987             if (oldState.ephemeralKeyState != newState.ephemeralKeyState) return true;
1988             if (oldState.ephemeralKeyState == EPHEMERAL_KEY_DISABLED) return false;
1989             return (!Objects.equals(oldState.ephemeralKeyPasscode, newState.ephemeralKeyPasscode)
1990                     || oldState.ephemeralKeyLifetimeMillis != newState.ephemeralKeyLifetimeMillis);
1991         }
1992 
1993         private void onActiveOperationalDatasetChanged(
1994                 ActiveOperationalDataset activeDataset, long listenerId) {
1995             checkOnHandlerThread();
1996             boolean hasChange = !Objects.equals(mActiveDataset, activeDataset);
1997 
1998             for (var callbackEntry : mOpDatasetCallbacks.entrySet()) {
1999                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
2000                     continue;
2001                 }
2002                 try {
2003                     callbackEntry.getKey().onActiveOperationalDatasetChanged(activeDataset);
2004                 } catch (RemoteException ignored) {
2005                     // do nothing if the client is dead
2006                 }
2007             }
2008         }
2009 
2010         private void onPendingOperationalDatasetChanged(
2011                 PendingOperationalDataset pendingDataset, long listenerId) {
2012             checkOnHandlerThread();
2013             boolean hasChange = !Objects.equals(mPendingDataset, pendingDataset);
2014             for (var callbackEntry : mOpDatasetCallbacks.entrySet()) {
2015                 if (!hasChange && callbackEntry.getValue().id != listenerId) {
2016                     continue;
2017                 }
2018                 try {
2019                     callbackEntry.getKey().onPendingOperationalDatasetChanged(pendingDataset);
2020                 } catch (RemoteException ignored) {
2021                     // do nothing if the client is dead
2022                 }
2023             }
2024         }
2025 
2026         @Override
2027         public void onAddressChanged(List<Ipv6AddressInfo> addressInfoList) {
2028             mHandler.post(() -> handleAddressChanged(addressInfoList));
2029         }
2030 
2031         @Override
2032         public void onBackboneRouterStateChanged(BackboneRouterState state) {
2033             mHandler.post(() -> handleMulticastForwardingChanged(state));
2034         }
2035 
2036         @Override
2037         public void onPrefixChanged(List<OnMeshPrefixConfig> onMeshPrefixConfigList) {
2038             mHandler.post(() -> handlePrefixChanged(onMeshPrefixConfigList));
2039         }
2040     }
2041 
2042     private final class Nat64CidrController extends IIpv4PrefixRequest.Stub {
2043         private static final int RETRY_DELAY_ON_FAILURE_MILLIS = 600_000; // 10 minutes
2044 
2045         @Nullable private LinkAddress mNat64Cidr;
2046 
2047         @Override
2048         public void onIpv4PrefixConflict(IpPrefix prefix) {
2049             mHandler.post(() -> onIpv4PrefixConflictInternal(prefix));
2050         }
2051 
2052         private void onIpv4PrefixConflictInternal(IpPrefix prefix) {
2053             checkOnHandlerThread();
2054 
2055             LOG.i("Conflict on NAT64 CIDR: " + prefix);
2056             maybeReleaseNat64Cidr();
2057             maybeUpdateNat64Cidr();
2058         }
2059 
2060         public void maybeUpdateNat64Cidr() {
2061             checkOnHandlerThread();
2062 
2063             if (mPersistentSettings.getConfiguration().isNat64Enabled()) {
2064                 maybeRequestNat64Cidr();
2065             } else {
2066                 maybeReleaseNat64Cidr();
2067             }
2068             try {
2069                 getOtDaemon()
2070                         .setNat64Cidr(
2071                                 mNat64Cidr == null ? null : mNat64Cidr.toString(),
2072                                 new LoggingOtStatusReceiver("setNat64Cidr"));
2073             } catch (RemoteException | ThreadNetworkException e) {
2074                 LOG.e("Failed to set NAT64 CIDR at otd-daemon", e);
2075             }
2076             maybeSendLinkProperties();
2077         }
2078 
2079         private void maybeRequestNat64Cidr() {
2080             if (mNat64Cidr != null) {
2081                 return;
2082             }
2083             final LinkAddress downstreamAddress =
2084                     mRoutingCoordinatorManager.requestDownstreamAddress(this);
2085             if (downstreamAddress == null) {
2086                 mHandler.postDelayed(() -> maybeUpdateNat64Cidr(), RETRY_DELAY_ON_FAILURE_MILLIS);
2087             }
2088             mNat64Cidr = downstreamAddress;
2089             LOG.i("Allocated NAT64 CIDR: " + mNat64Cidr);
2090         }
2091 
2092         private void maybeReleaseNat64Cidr() {
2093             if (mNat64Cidr == null) {
2094                 return;
2095             }
2096             LOG.i("Released NAT64 CIDR: " + mNat64Cidr);
2097             mNat64Cidr = null;
2098             mRoutingCoordinatorManager.releaseDownstream(this);
2099         }
2100     }
2101 }
2102