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