1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.adb; 18 19 import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull; 20 21 import android.annotation.NonNull; 22 import android.annotation.TestApi; 23 import android.app.ActivityManager; 24 import android.app.Notification; 25 import android.app.NotificationChannel; 26 import android.app.NotificationManager; 27 import android.content.ActivityNotFoundException; 28 import android.content.BroadcastReceiver; 29 import android.content.ComponentName; 30 import android.content.ContentResolver; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.content.pm.PackageManager; 35 import android.content.pm.UserInfo; 36 import android.content.res.Resources; 37 import android.database.ContentObserver; 38 import android.debug.AdbManager; 39 import android.debug.AdbNotifications; 40 import android.debug.AdbProtoEnums; 41 import android.debug.AdbTransportType; 42 import android.debug.PairDevice; 43 import android.net.ConnectivityManager; 44 import android.net.LocalSocket; 45 import android.net.LocalSocketAddress; 46 import android.net.NetworkInfo; 47 import android.net.Uri; 48 import android.net.nsd.NsdManager; 49 import android.net.nsd.NsdServiceInfo; 50 import android.net.wifi.WifiConfiguration; 51 import android.net.wifi.WifiInfo; 52 import android.net.wifi.WifiManager; 53 import android.os.Bundle; 54 import android.os.Environment; 55 import android.os.FileUtils; 56 import android.os.Handler; 57 import android.os.Looper; 58 import android.os.Message; 59 import android.os.SystemClock; 60 import android.os.SystemProperties; 61 import android.os.UserHandle; 62 import android.os.UserManager; 63 import android.provider.Settings; 64 import android.service.adb.AdbDebuggingManagerProto; 65 import android.util.AtomicFile; 66 import android.util.Base64; 67 import android.util.Slog; 68 import android.util.TypedXmlPullParser; 69 import android.util.TypedXmlSerializer; 70 import android.util.Xml; 71 72 import com.android.internal.R; 73 import com.android.internal.annotations.VisibleForTesting; 74 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 75 import com.android.internal.util.FrameworkStatsLog; 76 import com.android.internal.util.XmlUtils; 77 import com.android.internal.util.dump.DualDumpOutputStream; 78 import com.android.server.FgThread; 79 80 import org.xmlpull.v1.XmlPullParser; 81 import org.xmlpull.v1.XmlPullParserException; 82 83 import java.io.BufferedReader; 84 import java.io.File; 85 import java.io.FileInputStream; 86 import java.io.FileOutputStream; 87 import java.io.FileReader; 88 import java.io.IOException; 89 import java.io.InputStream; 90 import java.io.OutputStream; 91 import java.security.MessageDigest; 92 import java.security.SecureRandom; 93 import java.util.AbstractMap; 94 import java.util.ArrayList; 95 import java.util.Arrays; 96 import java.util.HashMap; 97 import java.util.HashSet; 98 import java.util.Iterator; 99 import java.util.List; 100 import java.util.Map; 101 import java.util.Set; 102 import java.util.concurrent.atomic.AtomicBoolean; 103 104 /** 105 * Provides communication to the Android Debug Bridge daemon to allow, deny, or clear public keysi 106 * that are authorized to connect to the ADB service itself. 107 */ 108 public class AdbDebuggingManager { 109 private static final String TAG = "AdbDebuggingManager"; 110 private static final boolean DEBUG = false; 111 private static final boolean MDNS_DEBUG = false; 112 113 private static final String ADBD_SOCKET = "adbd"; 114 private static final String ADB_DIRECTORY = "misc/adb"; 115 // This file contains keys that will always be allowed to connect to the device via adb. 116 private static final String ADB_KEYS_FILE = "adb_keys"; 117 // This file contains keys that will be allowed to connect without user interaction as long 118 // as a subsequent connection occurs within the allowed duration. 119 private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml"; 120 private static final int BUFFER_SIZE = 65536; 121 122 private final Context mContext; 123 private final ContentResolver mContentResolver; 124 private final Handler mHandler; 125 private AdbDebuggingThread mThread; 126 private boolean mAdbUsbEnabled = false; 127 private boolean mAdbWifiEnabled = false; 128 private String mFingerprints; 129 // A key can be used more than once (e.g. USB, wifi), so need to keep a refcount 130 private final Map<String, Integer> mConnectedKeys; 131 private String mConfirmComponent; 132 private final File mTestUserKeyFile; 133 134 private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = 135 "persist.adb.tls_server.enable"; 136 private static final String WIFI_PERSISTENT_GUID = 137 "persist.adb.wifi.guid"; 138 private static final int PAIRING_CODE_LENGTH = 6; 139 private PairingThread mPairingThread = null; 140 // A list of keys connected via wifi 141 private final Set<String> mWifiConnectedKeys; 142 // The current info of the adbwifi connection. 143 private AdbConnectionInfo mAdbConnectionInfo; 144 // Polls for a tls port property when adb wifi is enabled 145 private AdbConnectionPortPoller mConnectionPortPoller; 146 private final PortListenerImpl mPortListener = new PortListenerImpl(); 147 AdbDebuggingManager(Context context)148 public AdbDebuggingManager(Context context) { 149 mHandler = new AdbDebuggingHandler(FgThread.get().getLooper()); 150 mContext = context; 151 mContentResolver = mContext.getContentResolver(); 152 mTestUserKeyFile = null; 153 mConnectedKeys = new HashMap<String, Integer>(); 154 mWifiConnectedKeys = new HashSet<String>(); 155 mAdbConnectionInfo = new AdbConnectionInfo(); 156 } 157 158 /** 159 * Constructor that accepts the component to be invoked to confirm if the user wants to allow 160 * an adb connection from the key. 161 */ 162 @TestApi AdbDebuggingManager(Context context, String confirmComponent, File testUserKeyFile)163 protected AdbDebuggingManager(Context context, String confirmComponent, File testUserKeyFile) { 164 mHandler = new AdbDebuggingHandler(FgThread.get().getLooper()); 165 mContext = context; 166 mContentResolver = mContext.getContentResolver(); 167 mConfirmComponent = confirmComponent; 168 mTestUserKeyFile = testUserKeyFile; 169 mConnectedKeys = new HashMap<String, Integer>(); 170 mWifiConnectedKeys = new HashSet<String>(); 171 mAdbConnectionInfo = new AdbConnectionInfo(); 172 } 173 sendBroadcastWithDebugPermission(@onNull Context context, @NonNull Intent intent, @NonNull UserHandle userHandle)174 static void sendBroadcastWithDebugPermission(@NonNull Context context, @NonNull Intent intent, 175 @NonNull UserHandle userHandle) { 176 context.sendBroadcastAsUser(intent, userHandle, 177 android.Manifest.permission.MANAGE_DEBUGGING); 178 } 179 180 class PairingThread extends Thread implements NsdManager.RegistrationListener { 181 private NsdManager mNsdManager; 182 private String mPublicKey; 183 private String mPairingCode; 184 private String mGuid; 185 private String mServiceName; 186 // From RFC6763 (https://tools.ietf.org/html/rfc6763#section-7.2), 187 // The rules for Service Names [RFC6335] state that they may be no more 188 // than fifteen characters long (not counting the mandatory underscore), 189 // consisting of only letters, digits, and hyphens, must begin and end 190 // with a letter or digit, must not contain consecutive hyphens, and 191 // must contain at least one letter. 192 @VisibleForTesting 193 static final String SERVICE_PROTOCOL = "adb-tls-pairing"; 194 private final String mServiceType = String.format("_%s._tcp.", SERVICE_PROTOCOL); 195 private int mPort; 196 native_pairing_start(String guid, String password)197 private native int native_pairing_start(String guid, String password); native_pairing_cancel()198 private native void native_pairing_cancel(); native_pairing_wait()199 private native boolean native_pairing_wait(); 200 PairingThread(String pairingCode, String serviceName)201 PairingThread(String pairingCode, String serviceName) { 202 super(TAG); 203 mPairingCode = pairingCode; 204 mGuid = SystemProperties.get(WIFI_PERSISTENT_GUID); 205 mServiceName = serviceName; 206 if (serviceName == null || serviceName.isEmpty()) { 207 mServiceName = mGuid; 208 } 209 mPort = -1; 210 mNsdManager = (NsdManager) mContext.getSystemService(Context.NSD_SERVICE); 211 } 212 213 @Override run()214 public void run() { 215 if (mGuid.isEmpty()) { 216 Slog.e(TAG, "adbwifi guid was not set"); 217 return; 218 } 219 mPort = native_pairing_start(mGuid, mPairingCode); 220 if (mPort <= 0 || mPort > 65535) { 221 Slog.e(TAG, "Unable to start pairing server"); 222 return; 223 } 224 225 // Register the mdns service 226 NsdServiceInfo serviceInfo = new NsdServiceInfo(); 227 serviceInfo.setServiceName(mServiceName); 228 serviceInfo.setServiceType(mServiceType); 229 serviceInfo.setPort(mPort); 230 mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, this); 231 232 // Send pairing port to UI 233 Message msg = mHandler.obtainMessage( 234 AdbDebuggingHandler.MSG_RESPONSE_PAIRING_PORT); 235 msg.obj = mPort; 236 mHandler.sendMessage(msg); 237 238 boolean paired = native_pairing_wait(); 239 if (DEBUG) { 240 if (mPublicKey != null) { 241 Slog.i(TAG, "Pairing succeeded key=" + mPublicKey); 242 } else { 243 Slog.i(TAG, "Pairing failed"); 244 } 245 } 246 247 mNsdManager.unregisterService(this); 248 249 Bundle bundle = new Bundle(); 250 bundle.putString("publicKey", paired ? mPublicKey : null); 251 Message message = Message.obtain(mHandler, 252 AdbDebuggingHandler.MSG_RESPONSE_PAIRING_RESULT, 253 bundle); 254 mHandler.sendMessage(message); 255 } 256 cancelPairing()257 public void cancelPairing() { 258 native_pairing_cancel(); 259 } 260 261 @Override onServiceRegistered(NsdServiceInfo serviceInfo)262 public void onServiceRegistered(NsdServiceInfo serviceInfo) { 263 if (MDNS_DEBUG) Slog.i(TAG, "Registered pairing service: " + serviceInfo); 264 } 265 266 @Override onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode)267 public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { 268 Slog.e(TAG, "Failed to register pairing service(err=" + errorCode 269 + "): " + serviceInfo); 270 cancelPairing(); 271 } 272 273 @Override onServiceUnregistered(NsdServiceInfo serviceInfo)274 public void onServiceUnregistered(NsdServiceInfo serviceInfo) { 275 if (MDNS_DEBUG) Slog.i(TAG, "Unregistered pairing service: " + serviceInfo); 276 } 277 278 @Override onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode)279 public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { 280 Slog.w(TAG, "Failed to unregister pairing service(err=" + errorCode 281 + "): " + serviceInfo); 282 } 283 } 284 285 interface AdbConnectionPortListener { onPortReceived(int port)286 void onPortReceived(int port); 287 } 288 289 /** 290 * This class will poll for a period of time for adbd to write the port 291 * it connected to. 292 * 293 * TODO(joshuaduong): The port is being sent via system property because the adbd socket 294 * (AdbDebuggingManager) is not created when ro.adb.secure=0. Thus, we must communicate the 295 * port through different means. A better fix would be to always start AdbDebuggingManager, but 296 * it needs to adjust accordingly on whether ro.adb.secure is set. 297 */ 298 static class AdbConnectionPortPoller extends Thread { 299 private final String mAdbPortProp = "service.adb.tls.port"; 300 private AdbConnectionPortListener mListener; 301 private final int mDurationSecs = 10; 302 private AtomicBoolean mCanceled = new AtomicBoolean(false); 303 AdbConnectionPortPoller(AdbConnectionPortListener listener)304 AdbConnectionPortPoller(AdbConnectionPortListener listener) { 305 mListener = listener; 306 } 307 308 @Override run()309 public void run() { 310 if (DEBUG) Slog.d(TAG, "Starting adb port property poller"); 311 // Once adbwifi is enabled, we poll the service.adb.tls.port 312 // system property until we get the port, or -1 on failure. 313 // Let's also limit the polling to 10 seconds, just in case 314 // something went wrong. 315 for (int i = 0; i < mDurationSecs; ++i) { 316 if (mCanceled.get()) { 317 return; 318 } 319 320 // If the property is set to -1, then that means adbd has failed 321 // to start the server. Otherwise we should have a valid port. 322 int port = SystemProperties.getInt(mAdbPortProp, Integer.MAX_VALUE); 323 if (port == -1 || (port > 0 && port <= 65535)) { 324 mListener.onPortReceived(port); 325 return; 326 } 327 SystemClock.sleep(1000); 328 } 329 Slog.w(TAG, "Failed to receive adb connection port"); 330 mListener.onPortReceived(-1); 331 } 332 cancelAndWait()333 public void cancelAndWait() { 334 mCanceled.set(true); 335 if (this.isAlive()) { 336 try { 337 this.join(); 338 } catch (InterruptedException e) { 339 } 340 } 341 } 342 } 343 344 class PortListenerImpl implements AdbConnectionPortListener { onPortReceived(int port)345 public void onPortReceived(int port) { 346 if (DEBUG) Slog.d(TAG, "Received tls port=" + port); 347 Message msg = mHandler.obtainMessage(port > 0 348 ? AdbDebuggingHandler.MSG_SERVER_CONNECTED 349 : AdbDebuggingHandler.MSG_SERVER_DISCONNECTED); 350 msg.obj = port; 351 mHandler.sendMessage(msg); 352 } 353 } 354 355 class AdbDebuggingThread extends Thread { 356 private boolean mStopped; 357 private LocalSocket mSocket; 358 private OutputStream mOutputStream; 359 private InputStream mInputStream; 360 AdbDebuggingThread()361 AdbDebuggingThread() { 362 super(TAG); 363 } 364 365 @Override run()366 public void run() { 367 if (DEBUG) Slog.d(TAG, "Entering thread"); 368 while (true) { 369 synchronized (this) { 370 if (mStopped) { 371 if (DEBUG) Slog.d(TAG, "Exiting thread"); 372 return; 373 } 374 try { 375 openSocketLocked(); 376 } catch (Exception e) { 377 /* Don't loop too fast if adbd dies, before init restarts it */ 378 SystemClock.sleep(1000); 379 } 380 } 381 try { 382 listenToSocket(); 383 } catch (Exception e) { 384 /* Don't loop too fast if adbd dies, before init restarts it */ 385 SystemClock.sleep(1000); 386 } 387 } 388 } 389 openSocketLocked()390 private void openSocketLocked() throws IOException { 391 try { 392 LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET, 393 LocalSocketAddress.Namespace.RESERVED); 394 mInputStream = null; 395 396 if (DEBUG) Slog.d(TAG, "Creating socket"); 397 mSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET); 398 mSocket.connect(address); 399 400 mOutputStream = mSocket.getOutputStream(); 401 mInputStream = mSocket.getInputStream(); 402 mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_ADBD_SOCKET_CONNECTED); 403 } catch (IOException ioe) { 404 Slog.e(TAG, "Caught an exception opening the socket: " + ioe); 405 closeSocketLocked(); 406 throw ioe; 407 } 408 } 409 listenToSocket()410 private void listenToSocket() throws IOException { 411 try { 412 byte[] buffer = new byte[BUFFER_SIZE]; 413 while (true) { 414 int count = mInputStream.read(buffer); 415 // if less than 2 bytes are read the if statements below will throw an 416 // IndexOutOfBoundsException. 417 if (count < 2) { 418 Slog.w(TAG, "Read failed with count " + count); 419 break; 420 } 421 422 if (buffer[0] == 'P' && buffer[1] == 'K') { 423 String key = new String(Arrays.copyOfRange(buffer, 2, count)); 424 Slog.d(TAG, "Received public key: " + key); 425 Message msg = mHandler.obtainMessage( 426 AdbDebuggingHandler.MESSAGE_ADB_CONFIRM); 427 msg.obj = key; 428 mHandler.sendMessage(msg); 429 } else if (buffer[0] == 'D' && buffer[1] == 'C') { 430 String key = new String(Arrays.copyOfRange(buffer, 2, count)); 431 Slog.d(TAG, "Received disconnected message: " + key); 432 Message msg = mHandler.obtainMessage( 433 AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT); 434 msg.obj = key; 435 mHandler.sendMessage(msg); 436 } else if (buffer[0] == 'C' && buffer[1] == 'K') { 437 String key = new String(Arrays.copyOfRange(buffer, 2, count)); 438 Slog.d(TAG, "Received connected key message: " + key); 439 Message msg = mHandler.obtainMessage( 440 AdbDebuggingHandler.MESSAGE_ADB_CONNECTED_KEY); 441 msg.obj = key; 442 mHandler.sendMessage(msg); 443 } else if (buffer[0] == 'W' && buffer[1] == 'E') { 444 // adbd_auth.h and AdbTransportType.aidl need to be kept in 445 // sync. 446 byte transportType = buffer[2]; 447 String key = new String(Arrays.copyOfRange(buffer, 3, count)); 448 if (transportType == AdbTransportType.USB) { 449 Slog.d(TAG, "Received USB TLS connected key message: " + key); 450 Message msg = mHandler.obtainMessage( 451 AdbDebuggingHandler.MESSAGE_ADB_CONNECTED_KEY); 452 msg.obj = key; 453 mHandler.sendMessage(msg); 454 } else if (transportType == AdbTransportType.WIFI) { 455 Slog.d(TAG, "Received WIFI TLS connected key message: " + key); 456 Message msg = mHandler.obtainMessage( 457 AdbDebuggingHandler.MSG_WIFI_DEVICE_CONNECTED); 458 msg.obj = key; 459 mHandler.sendMessage(msg); 460 } else { 461 Slog.e(TAG, "Got unknown transport type from adbd (" + transportType 462 + ")"); 463 } 464 } else if (buffer[0] == 'W' && buffer[1] == 'F') { 465 byte transportType = buffer[2]; 466 String key = new String(Arrays.copyOfRange(buffer, 3, count)); 467 if (transportType == AdbTransportType.USB) { 468 Slog.d(TAG, "Received USB TLS disconnect message: " + key); 469 Message msg = mHandler.obtainMessage( 470 AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT); 471 msg.obj = key; 472 mHandler.sendMessage(msg); 473 } else if (transportType == AdbTransportType.WIFI) { 474 Slog.d(TAG, "Received WIFI TLS disconnect key message: " + key); 475 Message msg = mHandler.obtainMessage( 476 AdbDebuggingHandler.MSG_WIFI_DEVICE_DISCONNECTED); 477 msg.obj = key; 478 mHandler.sendMessage(msg); 479 } else { 480 Slog.e(TAG, "Got unknown transport type from adbd (" + transportType 481 + ")"); 482 } 483 } else { 484 Slog.e(TAG, "Wrong message: " 485 + (new String(Arrays.copyOfRange(buffer, 0, 2)))); 486 break; 487 } 488 } 489 } finally { 490 synchronized (this) { 491 closeSocketLocked(); 492 } 493 } 494 } 495 closeSocketLocked()496 private void closeSocketLocked() { 497 if (DEBUG) Slog.d(TAG, "Closing socket"); 498 try { 499 if (mOutputStream != null) { 500 mOutputStream.close(); 501 mOutputStream = null; 502 } 503 } catch (IOException e) { 504 Slog.e(TAG, "Failed closing output stream: " + e); 505 } 506 507 try { 508 if (mSocket != null) { 509 mSocket.close(); 510 mSocket = null; 511 } 512 } catch (IOException ex) { 513 Slog.e(TAG, "Failed closing socket: " + ex); 514 } 515 mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_ADBD_SOCKET_DISCONNECTED); 516 } 517 518 /** Call to stop listening on the socket and exit the thread. */ stopListening()519 void stopListening() { 520 synchronized (this) { 521 mStopped = true; 522 closeSocketLocked(); 523 } 524 } 525 sendResponse(String msg)526 void sendResponse(String msg) { 527 synchronized (this) { 528 if (!mStopped && mOutputStream != null) { 529 try { 530 mOutputStream.write(msg.getBytes()); 531 } catch (IOException ex) { 532 Slog.e(TAG, "Failed to write response:", ex); 533 } 534 } 535 } 536 } 537 } 538 539 class AdbConnectionInfo { 540 private String mBssid; 541 private String mSsid; 542 private int mPort; 543 AdbConnectionInfo()544 AdbConnectionInfo() { 545 mBssid = ""; 546 mSsid = ""; 547 mPort = -1; 548 } 549 AdbConnectionInfo(String bssid, String ssid)550 AdbConnectionInfo(String bssid, String ssid) { 551 mBssid = bssid; 552 mSsid = ssid; 553 } 554 AdbConnectionInfo(AdbConnectionInfo other)555 AdbConnectionInfo(AdbConnectionInfo other) { 556 mBssid = other.mBssid; 557 mSsid = other.mSsid; 558 mPort = other.mPort; 559 } 560 getBSSID()561 public String getBSSID() { 562 return mBssid; 563 } 564 getSSID()565 public String getSSID() { 566 return mSsid; 567 } 568 getPort()569 public int getPort() { 570 return mPort; 571 } 572 setPort(int port)573 public void setPort(int port) { 574 mPort = port; 575 } 576 clear()577 public void clear() { 578 mBssid = ""; 579 mSsid = ""; 580 mPort = -1; 581 } 582 } 583 setAdbConnectionInfo(AdbConnectionInfo info)584 private void setAdbConnectionInfo(AdbConnectionInfo info) { 585 synchronized (mAdbConnectionInfo) { 586 if (info == null) { 587 mAdbConnectionInfo.clear(); 588 return; 589 } 590 mAdbConnectionInfo = info; 591 } 592 } 593 getAdbConnectionInfo()594 private AdbConnectionInfo getAdbConnectionInfo() { 595 synchronized (mAdbConnectionInfo) { 596 return new AdbConnectionInfo(mAdbConnectionInfo); 597 } 598 } 599 600 class AdbDebuggingHandler extends Handler { 601 private NotificationManager mNotificationManager; 602 private boolean mAdbNotificationShown; 603 604 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 605 @Override 606 public void onReceive(Context context, Intent intent) { 607 String action = intent.getAction(); 608 // We only care about when wifi is disabled, and when there is a wifi network 609 // change. 610 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 611 int state = intent.getIntExtra( 612 WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED); 613 if (state == WifiManager.WIFI_STATE_DISABLED) { 614 Slog.i(TAG, "Wifi disabled. Disabling adbwifi."); 615 Settings.Global.putInt(mContentResolver, 616 Settings.Global.ADB_WIFI_ENABLED, 0); 617 } 618 } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { 619 // We only care about wifi type connections 620 NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra( 621 WifiManager.EXTRA_NETWORK_INFO); 622 if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { 623 // Check for network disconnect 624 if (!networkInfo.isConnected()) { 625 Slog.i(TAG, "Network disconnected. Disabling adbwifi."); 626 Settings.Global.putInt(mContentResolver, 627 Settings.Global.ADB_WIFI_ENABLED, 0); 628 return; 629 } 630 631 WifiManager wifiManager = 632 (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 633 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 634 if (wifiInfo == null || wifiInfo.getNetworkId() == -1) { 635 Slog.i(TAG, "Not connected to any wireless network." 636 + " Not enabling adbwifi."); 637 Settings.Global.putInt(mContentResolver, 638 Settings.Global.ADB_WIFI_ENABLED, 0); 639 } 640 641 // Check for network change 642 String bssid = wifiInfo.getBSSID(); 643 if (bssid == null || bssid.isEmpty()) { 644 Slog.e(TAG, "Unable to get the wifi ap's BSSID. Disabling adbwifi."); 645 Settings.Global.putInt(mContentResolver, 646 Settings.Global.ADB_WIFI_ENABLED, 0); 647 } 648 synchronized (mAdbConnectionInfo) { 649 if (!bssid.equals(mAdbConnectionInfo.getBSSID())) { 650 Slog.i(TAG, "Detected wifi network change. Disabling adbwifi."); 651 Settings.Global.putInt(mContentResolver, 652 Settings.Global.ADB_WIFI_ENABLED, 0); 653 } 654 } 655 } 656 } 657 } 658 }; 659 660 private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv"; 661 isTv()662 private boolean isTv() { 663 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); 664 } 665 setupNotifications()666 private void setupNotifications() { 667 if (mNotificationManager != null) { 668 return; 669 } 670 mNotificationManager = (NotificationManager) 671 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 672 if (mNotificationManager == null) { 673 Slog.e(TAG, "Unable to setup notifications for wireless debugging"); 674 return; 675 } 676 677 // Ensure that the notification channels are set up 678 if (isTv()) { 679 // TV-specific notification channel 680 mNotificationManager.createNotificationChannel( 681 new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV, 682 mContext.getString( 683 com.android.internal.R.string 684 .adb_debugging_notification_channel_tv), 685 NotificationManager.IMPORTANCE_HIGH)); 686 } 687 } 688 689 // The default time to schedule the job to keep the keystore updated with a currently 690 // connected key as well as to removed expired keys. 691 static final long UPDATE_KEYSTORE_JOB_INTERVAL = 86400000; 692 // The minimum interval at which the job should run to update the keystore. This is intended 693 // to prevent the job from running too often if the allowed connection time for adb grants 694 // is set to an extremely small value. 695 static final long UPDATE_KEYSTORE_MIN_JOB_INTERVAL = 60000; 696 697 static final int MESSAGE_ADB_ENABLED = 1; 698 static final int MESSAGE_ADB_DISABLED = 2; 699 static final int MESSAGE_ADB_ALLOW = 3; 700 static final int MESSAGE_ADB_DENY = 4; 701 static final int MESSAGE_ADB_CONFIRM = 5; 702 static final int MESSAGE_ADB_CLEAR = 6; 703 static final int MESSAGE_ADB_DISCONNECT = 7; 704 static final int MESSAGE_ADB_PERSIST_KEYSTORE = 8; 705 static final int MESSAGE_ADB_UPDATE_KEYSTORE = 9; 706 static final int MESSAGE_ADB_CONNECTED_KEY = 10; 707 708 // === Messages from the UI ============== 709 // UI asks adbd to enable adbdwifi 710 static final int MSG_ADBDWIFI_ENABLE = 11; 711 // UI asks adbd to disable adbdwifi 712 static final int MSG_ADBDWIFI_DISABLE = 12; 713 // Cancel pairing 714 static final int MSG_PAIRING_CANCEL = 14; 715 // Enable pairing by pairing code 716 static final int MSG_PAIR_PAIRING_CODE = 15; 717 // Enable pairing by QR code 718 static final int MSG_PAIR_QR_CODE = 16; 719 // UI asks to unpair (forget) a device. 720 static final int MSG_REQ_UNPAIR = 17; 721 // User allows debugging on the current network 722 static final int MSG_ADBWIFI_ALLOW = 18; 723 // User denies debugging on the current network 724 static final int MSG_ADBWIFI_DENY = 19; 725 726 // === Messages from the PairingThread =========== 727 // Result of the pairing 728 static final int MSG_RESPONSE_PAIRING_RESULT = 20; 729 // The port opened for pairing 730 static final int MSG_RESPONSE_PAIRING_PORT = 21; 731 732 // === Messages from adbd ================ 733 // Notifies us a wifi device connected. 734 static final int MSG_WIFI_DEVICE_CONNECTED = 22; 735 // Notifies us a wifi device disconnected. 736 static final int MSG_WIFI_DEVICE_DISCONNECTED = 23; 737 // Notifies us the TLS server is connected and listening 738 static final int MSG_SERVER_CONNECTED = 24; 739 // Notifies us the TLS server is disconnected 740 static final int MSG_SERVER_DISCONNECTED = 25; 741 // Notification when adbd socket successfully connects. 742 static final int MSG_ADBD_SOCKET_CONNECTED = 26; 743 // Notification when adbd socket is disconnected. 744 static final int MSG_ADBD_SOCKET_DISCONNECTED = 27; 745 746 // === Messages we can send to adbd =========== 747 static final String MSG_DISCONNECT_DEVICE = "DD"; 748 static final String MSG_DISABLE_ADBDWIFI = "DA"; 749 750 private AdbKeyStore mAdbKeyStore; 751 752 // Usb, Wi-Fi transports can be enabled together or separately, so don't break the framework 753 // connection unless all transport types are disconnected. 754 private int mAdbEnabledRefCount = 0; 755 756 private ContentObserver mAuthTimeObserver = new ContentObserver(this) { 757 @Override 758 public void onChange(boolean selfChange, Uri uri) { 759 Slog.d(TAG, "Received notification that uri " + uri 760 + " was modified; rescheduling keystore job"); 761 scheduleJobToUpdateAdbKeyStore(); 762 } 763 }; 764 AdbDebuggingHandler(Looper looper)765 AdbDebuggingHandler(Looper looper) { 766 super(looper); 767 } 768 769 /** 770 * Constructor that accepts the AdbDebuggingThread to which responses should be sent 771 * and the AdbKeyStore to be used to store the temporary grants. 772 */ 773 @TestApi AdbDebuggingHandler(Looper looper, AdbDebuggingThread thread, AdbKeyStore adbKeyStore)774 AdbDebuggingHandler(Looper looper, AdbDebuggingThread thread, AdbKeyStore adbKeyStore) { 775 super(looper); 776 mThread = thread; 777 mAdbKeyStore = adbKeyStore; 778 } 779 780 // Show when at least one device is connected. showAdbConnectedNotification(boolean show)781 public void showAdbConnectedNotification(boolean show) { 782 final int id = SystemMessage.NOTE_ADB_WIFI_ACTIVE; 783 if (show == mAdbNotificationShown) { 784 return; 785 } 786 setupNotifications(); 787 if (!mAdbNotificationShown) { 788 Notification notification = AdbNotifications.createNotification(mContext, 789 AdbTransportType.WIFI); 790 mAdbNotificationShown = true; 791 mNotificationManager.notifyAsUser(null, id, notification, 792 UserHandle.ALL); 793 } else { 794 mAdbNotificationShown = false; 795 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL); 796 } 797 } 798 startAdbDebuggingThread()799 private void startAdbDebuggingThread() { 800 ++mAdbEnabledRefCount; 801 if (DEBUG) Slog.i(TAG, "startAdbDebuggingThread ref=" + mAdbEnabledRefCount); 802 if (mAdbEnabledRefCount > 1) { 803 return; 804 } 805 806 registerForAuthTimeChanges(); 807 mThread = new AdbDebuggingThread(); 808 mThread.start(); 809 810 mAdbKeyStore.updateKeyStore(); 811 scheduleJobToUpdateAdbKeyStore(); 812 } 813 stopAdbDebuggingThread()814 private void stopAdbDebuggingThread() { 815 --mAdbEnabledRefCount; 816 if (DEBUG) Slog.i(TAG, "stopAdbDebuggingThread ref=" + mAdbEnabledRefCount); 817 if (mAdbEnabledRefCount > 0) { 818 return; 819 } 820 821 if (mThread != null) { 822 mThread.stopListening(); 823 mThread = null; 824 } 825 826 if (!mConnectedKeys.isEmpty()) { 827 for (Map.Entry<String, Integer> entry : mConnectedKeys.entrySet()) { 828 mAdbKeyStore.setLastConnectionTime(entry.getKey(), 829 System.currentTimeMillis()); 830 } 831 sendPersistKeyStoreMessage(); 832 mConnectedKeys.clear(); 833 mWifiConnectedKeys.clear(); 834 } 835 scheduleJobToUpdateAdbKeyStore(); 836 } 837 handleMessage(Message msg)838 public void handleMessage(Message msg) { 839 if (mAdbKeyStore == null) { 840 mAdbKeyStore = new AdbKeyStore(); 841 } 842 843 switch (msg.what) { 844 case MESSAGE_ADB_ENABLED: 845 if (mAdbUsbEnabled) { 846 break; 847 } 848 startAdbDebuggingThread(); 849 mAdbUsbEnabled = true; 850 break; 851 852 case MESSAGE_ADB_DISABLED: 853 if (!mAdbUsbEnabled) { 854 break; 855 } 856 stopAdbDebuggingThread(); 857 mAdbUsbEnabled = false; 858 break; 859 860 case MESSAGE_ADB_ALLOW: { 861 String key = (String) msg.obj; 862 String fingerprints = getFingerprints(key); 863 if (!fingerprints.equals(mFingerprints)) { 864 Slog.e(TAG, "Fingerprints do not match. Got " 865 + fingerprints + ", expected " + mFingerprints); 866 break; 867 } 868 869 boolean alwaysAllow = msg.arg1 == 1; 870 if (mThread != null) { 871 mThread.sendResponse("OK"); 872 if (alwaysAllow) { 873 if (!mConnectedKeys.containsKey(key)) { 874 mConnectedKeys.put(key, 1); 875 } 876 mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); 877 sendPersistKeyStoreMessage(); 878 scheduleJobToUpdateAdbKeyStore(); 879 } 880 logAdbConnectionChanged(key, AdbProtoEnums.USER_ALLOWED, alwaysAllow); 881 } 882 break; 883 } 884 885 case MESSAGE_ADB_DENY: 886 if (mThread != null) { 887 Slog.w(TAG, "Denying adb confirmation"); 888 mThread.sendResponse("NO"); 889 logAdbConnectionChanged(null, AdbProtoEnums.USER_DENIED, false); 890 } 891 break; 892 893 case MESSAGE_ADB_CONFIRM: { 894 String key = (String) msg.obj; 895 if ("trigger_restart_min_framework".equals( 896 SystemProperties.get("vold.decrypt"))) { 897 Slog.w(TAG, "Deferring adb confirmation until after vold decrypt"); 898 if (mThread != null) { 899 mThread.sendResponse("NO"); 900 logAdbConnectionChanged(key, AdbProtoEnums.DENIED_VOLD_DECRYPT, false); 901 } 902 break; 903 } 904 String fingerprints = getFingerprints(key); 905 if ("".equals(fingerprints)) { 906 if (mThread != null) { 907 mThread.sendResponse("NO"); 908 logAdbConnectionChanged(key, AdbProtoEnums.DENIED_INVALID_KEY, false); 909 } 910 break; 911 } 912 logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false); 913 mFingerprints = fingerprints; 914 startConfirmationForKey(key, mFingerprints); 915 break; 916 } 917 918 case MESSAGE_ADB_CLEAR: { 919 Slog.d(TAG, "Received a request to clear the adb authorizations"); 920 mConnectedKeys.clear(); 921 // If the key store has not yet been instantiated then do so now; this avoids 922 // the unnecessary creation of the key store when adb is not enabled. 923 if (mAdbKeyStore == null) { 924 mAdbKeyStore = new AdbKeyStore(); 925 } 926 mWifiConnectedKeys.clear(); 927 mAdbKeyStore.deleteKeyStore(); 928 cancelJobToUpdateAdbKeyStore(); 929 break; 930 } 931 932 case MESSAGE_ADB_DISCONNECT: { 933 String key = (String) msg.obj; 934 boolean alwaysAllow = false; 935 if (key != null && key.length() > 0) { 936 if (mConnectedKeys.containsKey(key)) { 937 alwaysAllow = true; 938 int refcount = mConnectedKeys.get(key) - 1; 939 if (refcount == 0) { 940 mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); 941 sendPersistKeyStoreMessage(); 942 scheduleJobToUpdateAdbKeyStore(); 943 mConnectedKeys.remove(key); 944 } else { 945 mConnectedKeys.put(key, refcount); 946 } 947 } 948 } else { 949 Slog.w(TAG, "Received a disconnected key message with an empty key"); 950 } 951 logAdbConnectionChanged(key, AdbProtoEnums.DISCONNECTED, alwaysAllow); 952 break; 953 } 954 955 case MESSAGE_ADB_PERSIST_KEYSTORE: { 956 if (mAdbKeyStore != null) { 957 mAdbKeyStore.persistKeyStore(); 958 } 959 break; 960 } 961 962 case MESSAGE_ADB_UPDATE_KEYSTORE: { 963 if (!mConnectedKeys.isEmpty()) { 964 for (Map.Entry<String, Integer> entry : mConnectedKeys.entrySet()) { 965 mAdbKeyStore.setLastConnectionTime(entry.getKey(), 966 System.currentTimeMillis()); 967 } 968 sendPersistKeyStoreMessage(); 969 scheduleJobToUpdateAdbKeyStore(); 970 } else if (!mAdbKeyStore.isEmpty()) { 971 mAdbKeyStore.updateKeyStore(); 972 scheduleJobToUpdateAdbKeyStore(); 973 } 974 break; 975 } 976 977 case MESSAGE_ADB_CONNECTED_KEY: { 978 String key = (String) msg.obj; 979 if (key == null || key.length() == 0) { 980 Slog.w(TAG, "Received a connected key message with an empty key"); 981 } else { 982 if (!mConnectedKeys.containsKey(key)) { 983 mConnectedKeys.put(key, 1); 984 } else { 985 mConnectedKeys.put(key, mConnectedKeys.get(key) + 1); 986 } 987 mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); 988 sendPersistKeyStoreMessage(); 989 scheduleJobToUpdateAdbKeyStore(); 990 logAdbConnectionChanged(key, AdbProtoEnums.AUTOMATICALLY_ALLOWED, true); 991 } 992 break; 993 } 994 case MSG_ADBDWIFI_ENABLE: { 995 if (mAdbWifiEnabled) { 996 break; 997 } 998 999 AdbConnectionInfo currentInfo = getCurrentWifiApInfo(); 1000 if (currentInfo == null) { 1001 Settings.Global.putInt(mContentResolver, 1002 Settings.Global.ADB_WIFI_ENABLED, 0); 1003 break; 1004 } 1005 1006 if (!verifyWifiNetwork(currentInfo.getBSSID(), 1007 currentInfo.getSSID())) { 1008 // This means that the network is not in the list of trusted networks. 1009 // We'll give user a prompt on whether to allow wireless debugging on 1010 // the current wifi network. 1011 Settings.Global.putInt(mContentResolver, 1012 Settings.Global.ADB_WIFI_ENABLED, 0); 1013 break; 1014 } 1015 1016 setAdbConnectionInfo(currentInfo); 1017 IntentFilter intentFilter = 1018 new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); 1019 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1020 mContext.registerReceiver(mBroadcastReceiver, intentFilter); 1021 1022 SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); 1023 mConnectionPortPoller = 1024 new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener); 1025 mConnectionPortPoller.start(); 1026 1027 startAdbDebuggingThread(); 1028 mAdbWifiEnabled = true; 1029 1030 if (DEBUG) Slog.i(TAG, "adb start wireless adb"); 1031 break; 1032 } 1033 case MSG_ADBDWIFI_DISABLE: 1034 if (!mAdbWifiEnabled) { 1035 break; 1036 } 1037 mAdbWifiEnabled = false; 1038 setAdbConnectionInfo(null); 1039 mContext.unregisterReceiver(mBroadcastReceiver); 1040 1041 if (mThread != null) { 1042 mThread.sendResponse(MSG_DISABLE_ADBDWIFI); 1043 } 1044 onAdbdWifiServerDisconnected(-1); 1045 stopAdbDebuggingThread(); 1046 break; 1047 case MSG_ADBWIFI_ALLOW: 1048 if (mAdbWifiEnabled) { 1049 break; 1050 } 1051 String bssid = (String) msg.obj; 1052 boolean alwaysAllow = msg.arg1 == 1; 1053 if (alwaysAllow) { 1054 mAdbKeyStore.addTrustedNetwork(bssid); 1055 } 1056 1057 // Let's check again to make sure we didn't switch networks while verifying 1058 // the wifi bssid. 1059 AdbConnectionInfo newInfo = getCurrentWifiApInfo(); 1060 if (newInfo == null || !bssid.equals(newInfo.getBSSID())) { 1061 break; 1062 } 1063 1064 setAdbConnectionInfo(newInfo); 1065 Settings.Global.putInt(mContentResolver, 1066 Settings.Global.ADB_WIFI_ENABLED, 1); 1067 IntentFilter intentFilter = 1068 new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); 1069 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1070 mContext.registerReceiver(mBroadcastReceiver, intentFilter); 1071 1072 SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); 1073 mConnectionPortPoller = 1074 new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener); 1075 mConnectionPortPoller.start(); 1076 1077 startAdbDebuggingThread(); 1078 mAdbWifiEnabled = true; 1079 1080 if (DEBUG) Slog.i(TAG, "adb start wireless adb"); 1081 break; 1082 case MSG_ADBWIFI_DENY: 1083 Settings.Global.putInt(mContentResolver, 1084 Settings.Global.ADB_WIFI_ENABLED, 0); 1085 sendServerConnectionState(false, -1); 1086 break; 1087 case MSG_REQ_UNPAIR: { 1088 String fingerprint = (String) msg.obj; 1089 // Tell adbd to disconnect the device if connected. 1090 String publicKey = mAdbKeyStore.findKeyFromFingerprint(fingerprint); 1091 if (publicKey == null || publicKey.isEmpty()) { 1092 Slog.e(TAG, "Not a known fingerprint [" + fingerprint + "]"); 1093 break; 1094 } 1095 String cmdStr = MSG_DISCONNECT_DEVICE + publicKey; 1096 if (mThread != null) { 1097 mThread.sendResponse(cmdStr); 1098 } 1099 mAdbKeyStore.removeKey(publicKey); 1100 // Send the updated paired devices list to the UI. 1101 sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); 1102 break; 1103 } 1104 case MSG_RESPONSE_PAIRING_RESULT: { 1105 Bundle bundle = (Bundle) msg.obj; 1106 String publicKey = bundle.getString("publicKey"); 1107 onPairingResult(publicKey); 1108 // Send the updated paired devices list to the UI. 1109 sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); 1110 break; 1111 } 1112 case MSG_RESPONSE_PAIRING_PORT: { 1113 int port = (int) msg.obj; 1114 sendPairingPortToUI(port); 1115 break; 1116 } 1117 case MSG_PAIR_PAIRING_CODE: { 1118 String pairingCode = createPairingCode(PAIRING_CODE_LENGTH); 1119 updateUIPairCode(pairingCode); 1120 mPairingThread = new PairingThread(pairingCode, null); 1121 mPairingThread.start(); 1122 break; 1123 } 1124 case MSG_PAIR_QR_CODE: { 1125 Bundle bundle = (Bundle) msg.obj; 1126 String serviceName = bundle.getString("serviceName"); 1127 String password = bundle.getString("password"); 1128 mPairingThread = new PairingThread(password, serviceName); 1129 mPairingThread.start(); 1130 break; 1131 } 1132 case MSG_PAIRING_CANCEL: 1133 if (mPairingThread != null) { 1134 mPairingThread.cancelPairing(); 1135 try { 1136 mPairingThread.join(); 1137 } catch (InterruptedException e) { 1138 Slog.w(TAG, "Error while waiting for pairing thread to quit."); 1139 e.printStackTrace(); 1140 } 1141 mPairingThread = null; 1142 } 1143 break; 1144 case MSG_WIFI_DEVICE_CONNECTED: { 1145 String key = (String) msg.obj; 1146 if (mWifiConnectedKeys.add(key)) { 1147 sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); 1148 showAdbConnectedNotification(true); 1149 } 1150 break; 1151 } 1152 case MSG_WIFI_DEVICE_DISCONNECTED: { 1153 String key = (String) msg.obj; 1154 if (mWifiConnectedKeys.remove(key)) { 1155 sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); 1156 if (mWifiConnectedKeys.isEmpty()) { 1157 showAdbConnectedNotification(false); 1158 } 1159 } 1160 break; 1161 } 1162 case MSG_SERVER_CONNECTED: { 1163 int port = (int) msg.obj; 1164 onAdbdWifiServerConnected(port); 1165 synchronized (mAdbConnectionInfo) { 1166 mAdbConnectionInfo.setPort(port); 1167 } 1168 Settings.Global.putInt(mContentResolver, 1169 Settings.Global.ADB_WIFI_ENABLED, 1); 1170 break; 1171 } 1172 case MSG_SERVER_DISCONNECTED: { 1173 if (!mAdbWifiEnabled) { 1174 break; 1175 } 1176 int port = (int) msg.obj; 1177 onAdbdWifiServerDisconnected(port); 1178 Settings.Global.putInt(mContentResolver, 1179 Settings.Global.ADB_WIFI_ENABLED, 0); 1180 stopAdbDebuggingThread(); 1181 if (mConnectionPortPoller != null) { 1182 mConnectionPortPoller.cancelAndWait(); 1183 mConnectionPortPoller = null; 1184 } 1185 break; 1186 } 1187 case MSG_ADBD_SOCKET_CONNECTED: { 1188 if (DEBUG) Slog.d(TAG, "adbd socket connected"); 1189 if (mAdbWifiEnabled) { 1190 // In scenarios where adbd is restarted, the tls port may change. 1191 mConnectionPortPoller = 1192 new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener); 1193 mConnectionPortPoller.start(); 1194 } 1195 break; 1196 } 1197 case MSG_ADBD_SOCKET_DISCONNECTED: { 1198 if (DEBUG) Slog.d(TAG, "adbd socket disconnected"); 1199 if (mConnectionPortPoller != null) { 1200 mConnectionPortPoller.cancelAndWait(); 1201 mConnectionPortPoller = null; 1202 } 1203 if (mAdbWifiEnabled) { 1204 // In scenarios where adbd is restarted, the tls port may change. 1205 onAdbdWifiServerDisconnected(-1); 1206 } 1207 break; 1208 } 1209 } 1210 } 1211 registerForAuthTimeChanges()1212 void registerForAuthTimeChanges() { 1213 Uri uri = Settings.Global.getUriFor(Settings.Global.ADB_ALLOWED_CONNECTION_TIME); 1214 mContext.getContentResolver().registerContentObserver(uri, false, mAuthTimeObserver); 1215 } 1216 logAdbConnectionChanged(String key, int state, boolean alwaysAllow)1217 private void logAdbConnectionChanged(String key, int state, boolean alwaysAllow) { 1218 long lastConnectionTime = mAdbKeyStore.getLastConnectionTime(key); 1219 long authWindow = mAdbKeyStore.getAllowedConnectionTime(); 1220 Slog.d(TAG, 1221 "Logging key " + key + ", state = " + state + ", alwaysAllow = " + alwaysAllow 1222 + ", lastConnectionTime = " + lastConnectionTime + ", authWindow = " 1223 + authWindow); 1224 FrameworkStatsLog.write(FrameworkStatsLog.ADB_CONNECTION_CHANGED, lastConnectionTime, 1225 authWindow, state, alwaysAllow); 1226 } 1227 1228 1229 /** 1230 * Schedules a job to update the connection time of the currently connected key and filter 1231 * out any keys that are beyond their expiration time. 1232 * 1233 * @return the time in ms when the next job will run or -1 if the job should not be 1234 * scheduled to run. 1235 */ 1236 @VisibleForTesting scheduleJobToUpdateAdbKeyStore()1237 long scheduleJobToUpdateAdbKeyStore() { 1238 cancelJobToUpdateAdbKeyStore(); 1239 long keyExpiration = mAdbKeyStore.getNextExpirationTime(); 1240 // if the keyExpiration time is -1 then either the keys are set to never expire or 1241 // there are no keys in the keystore, just return for now as a new job will be 1242 // scheduled on the next connection or when the auth time changes. 1243 if (keyExpiration == -1) { 1244 return -1; 1245 } 1246 long delay; 1247 // if the keyExpiration is 0 this indicates a key has already expired; schedule the job 1248 // to run now to ensure the key is removed immediately from adb_keys. 1249 if (keyExpiration == 0) { 1250 delay = 0; 1251 } else { 1252 // else the next job should be run either daily or when the next key is set to 1253 // expire with a min job interval to ensure this job does not run too often if a 1254 // small value is set for the key expiration. 1255 delay = Math.max(Math.min(UPDATE_KEYSTORE_JOB_INTERVAL, keyExpiration), 1256 UPDATE_KEYSTORE_MIN_JOB_INTERVAL); 1257 } 1258 Message message = obtainMessage(MESSAGE_ADB_UPDATE_KEYSTORE); 1259 sendMessageDelayed(message, delay); 1260 return delay; 1261 } 1262 1263 /** 1264 * Cancels the scheduled job to update the connection time of the currently connected key 1265 * and to remove any expired keys. 1266 */ cancelJobToUpdateAdbKeyStore()1267 private void cancelJobToUpdateAdbKeyStore() { 1268 removeMessages(AdbDebuggingHandler.MESSAGE_ADB_UPDATE_KEYSTORE); 1269 } 1270 1271 // Generates a random string of digits with size |size|. createPairingCode(int size)1272 private String createPairingCode(int size) { 1273 String res = ""; 1274 SecureRandom rand = new SecureRandom(); 1275 for (int i = 0; i < size; ++i) { 1276 res += rand.nextInt(10); 1277 } 1278 1279 return res; 1280 } 1281 sendServerConnectionState(boolean connected, int port)1282 private void sendServerConnectionState(boolean connected, int port) { 1283 Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION); 1284 intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, connected 1285 ? AdbManager.WIRELESS_STATUS_CONNECTED 1286 : AdbManager.WIRELESS_STATUS_DISCONNECTED); 1287 intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); 1288 AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); 1289 } 1290 onAdbdWifiServerConnected(int port)1291 private void onAdbdWifiServerConnected(int port) { 1292 // Send the paired devices list to the UI 1293 sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); 1294 sendServerConnectionState(true, port); 1295 } 1296 onAdbdWifiServerDisconnected(int port)1297 private void onAdbdWifiServerDisconnected(int port) { 1298 // The TLS server disconnected while we had wireless debugging enabled. 1299 // Let's disable it. 1300 mWifiConnectedKeys.clear(); 1301 showAdbConnectedNotification(false); 1302 sendServerConnectionState(false, port); 1303 } 1304 1305 /** 1306 * Returns the [bssid, ssid] of the current access point. 1307 */ getCurrentWifiApInfo()1308 private AdbConnectionInfo getCurrentWifiApInfo() { 1309 WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); 1310 WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 1311 if (wifiInfo == null || wifiInfo.getNetworkId() == -1) { 1312 Slog.i(TAG, "Not connected to any wireless network. Not enabling adbwifi."); 1313 return null; 1314 } 1315 1316 String ssid = null; 1317 if (wifiInfo.isPasspointAp() || wifiInfo.isOsuAp()) { 1318 ssid = wifiInfo.getPasspointProviderFriendlyName(); 1319 } else { 1320 ssid = wifiInfo.getSSID(); 1321 if (ssid == null || WifiManager.UNKNOWN_SSID.equals(ssid)) { 1322 // OK, it's not in the connectionInfo; we have to go hunting for it 1323 List<WifiConfiguration> networks = wifiManager.getConfiguredNetworks(); 1324 int length = networks.size(); 1325 for (int i = 0; i < length; i++) { 1326 if (networks.get(i).networkId == wifiInfo.getNetworkId()) { 1327 ssid = networks.get(i).SSID; 1328 } 1329 } 1330 if (ssid == null) { 1331 Slog.e(TAG, "Unable to get ssid of the wifi AP."); 1332 return null; 1333 } 1334 } 1335 } 1336 1337 String bssid = wifiInfo.getBSSID(); 1338 if (bssid == null || bssid.isEmpty()) { 1339 Slog.e(TAG, "Unable to get the wifi ap's BSSID."); 1340 return null; 1341 } 1342 return new AdbConnectionInfo(bssid, ssid); 1343 } 1344 verifyWifiNetwork(String bssid, String ssid)1345 private boolean verifyWifiNetwork(String bssid, String ssid) { 1346 // Check against a list of user-trusted networks. 1347 if (mAdbKeyStore.isTrustedNetwork(bssid)) { 1348 return true; 1349 } 1350 1351 // Ask user to confirm using wireless debugging on this network. 1352 startConfirmationForNetwork(ssid, bssid); 1353 return false; 1354 } 1355 onPairingResult(String publicKey)1356 private void onPairingResult(String publicKey) { 1357 if (publicKey == null) { 1358 Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); 1359 intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, AdbManager.WIRELESS_STATUS_FAIL); 1360 AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, 1361 UserHandle.ALL); 1362 } else { 1363 Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); 1364 intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, 1365 AdbManager.WIRELESS_STATUS_SUCCESS); 1366 String fingerprints = getFingerprints(publicKey); 1367 String hostname = "nouser@nohostname"; 1368 String[] args = publicKey.split("\\s+"); 1369 if (args.length > 1) { 1370 hostname = args[1]; 1371 } 1372 PairDevice device = new PairDevice(fingerprints, hostname, false); 1373 intent.putExtra(AdbManager.WIRELESS_PAIR_DEVICE_EXTRA, device); 1374 AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, 1375 UserHandle.ALL); 1376 // Add the key into the keystore 1377 mAdbKeyStore.setLastConnectionTime(publicKey, 1378 System.currentTimeMillis()); 1379 sendPersistKeyStoreMessage(); 1380 scheduleJobToUpdateAdbKeyStore(); 1381 } 1382 } 1383 sendPairingPortToUI(int port)1384 private void sendPairingPortToUI(int port) { 1385 Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); 1386 intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, 1387 AdbManager.WIRELESS_STATUS_CONNECTED); 1388 intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); 1389 AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); 1390 } 1391 sendPairedDevicesToUI(Map<String, PairDevice> devices)1392 private void sendPairedDevicesToUI(Map<String, PairDevice> devices) { 1393 Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION); 1394 // Map is not serializable, so need to downcast 1395 intent.putExtra(AdbManager.WIRELESS_DEVICES_EXTRA, (HashMap) devices); 1396 AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); 1397 } 1398 updateUIPairCode(String code)1399 private void updateUIPairCode(String code) { 1400 if (DEBUG) Slog.i(TAG, "updateUIPairCode: " + code); 1401 1402 Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); 1403 intent.putExtra(AdbManager.WIRELESS_PAIRING_CODE_EXTRA, code); 1404 intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, 1405 AdbManager.WIRELESS_STATUS_PAIRING_CODE); 1406 AdbDebuggingManager.sendBroadcastWithDebugPermission(mContext, intent, UserHandle.ALL); 1407 } 1408 } 1409 getFingerprints(String key)1410 private String getFingerprints(String key) { 1411 String hex = "0123456789ABCDEF"; 1412 StringBuilder sb = new StringBuilder(); 1413 MessageDigest digester; 1414 1415 if (key == null) { 1416 return ""; 1417 } 1418 1419 try { 1420 digester = MessageDigest.getInstance("MD5"); 1421 } catch (Exception ex) { 1422 Slog.e(TAG, "Error getting digester", ex); 1423 return ""; 1424 } 1425 1426 byte[] base64_data = key.split("\\s+")[0].getBytes(); 1427 byte[] digest; 1428 try { 1429 digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT)); 1430 } catch (IllegalArgumentException e) { 1431 Slog.e(TAG, "error doing base64 decoding", e); 1432 return ""; 1433 } 1434 for (int i = 0; i < digest.length; i++) { 1435 sb.append(hex.charAt((digest[i] >> 4) & 0xf)); 1436 sb.append(hex.charAt(digest[i] & 0xf)); 1437 if (i < digest.length - 1) { 1438 sb.append(":"); 1439 } 1440 } 1441 return sb.toString(); 1442 } 1443 startConfirmationForNetwork(String ssid, String bssid)1444 private void startConfirmationForNetwork(String ssid, String bssid) { 1445 List<Map.Entry<String, String>> extras = new ArrayList<Map.Entry<String, String>>(); 1446 extras.add(new AbstractMap.SimpleEntry<String, String>("ssid", ssid)); 1447 extras.add(new AbstractMap.SimpleEntry<String, String>("bssid", bssid)); 1448 int currentUserId = ActivityManager.getCurrentUser(); 1449 UserInfo userInfo = UserManager.get(mContext).getUserInfo(currentUserId); 1450 String componentString; 1451 if (userInfo.isAdmin()) { 1452 componentString = Resources.getSystem().getString( 1453 com.android.internal.R.string.config_customAdbWifiNetworkConfirmationComponent); 1454 } else { 1455 componentString = Resources.getSystem().getString( 1456 com.android.internal.R.string.config_customAdbWifiNetworkConfirmationComponent); 1457 } 1458 ComponentName componentName = ComponentName.unflattenFromString(componentString); 1459 if (startConfirmationActivity(componentName, userInfo.getUserHandle(), extras) 1460 || startConfirmationService(componentName, userInfo.getUserHandle(), 1461 extras)) { 1462 return; 1463 } 1464 Slog.e(TAG, "Unable to start customAdbWifiNetworkConfirmation[SecondaryUser]Component " 1465 + componentString + " as an Activity or a Service"); 1466 } 1467 startConfirmationForKey(String key, String fingerprints)1468 private void startConfirmationForKey(String key, String fingerprints) { 1469 List<Map.Entry<String, String>> extras = new ArrayList<Map.Entry<String, String>>(); 1470 extras.add(new AbstractMap.SimpleEntry<String, String>("key", key)); 1471 extras.add(new AbstractMap.SimpleEntry<String, String>("fingerprints", fingerprints)); 1472 int currentUserId = ActivityManager.getCurrentUser(); 1473 UserInfo userInfo = UserManager.get(mContext).getUserInfo(currentUserId); 1474 String componentString; 1475 if (userInfo.isAdmin()) { 1476 componentString = mConfirmComponent != null 1477 ? mConfirmComponent : Resources.getSystem().getString( 1478 com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent); 1479 } else { 1480 // If the current foreground user is not the admin user we send a different 1481 // notification specific to secondary users. 1482 componentString = Resources.getSystem().getString( 1483 R.string.config_customAdbPublicKeyConfirmationSecondaryUserComponent); 1484 } 1485 ComponentName componentName = ComponentName.unflattenFromString(componentString); 1486 if (startConfirmationActivity(componentName, userInfo.getUserHandle(), extras) 1487 || startConfirmationService(componentName, userInfo.getUserHandle(), 1488 extras)) { 1489 return; 1490 } 1491 Slog.e(TAG, "unable to start customAdbPublicKeyConfirmation[SecondaryUser]Component " 1492 + componentString + " as an Activity or a Service"); 1493 } 1494 1495 /** 1496 * @return true if the componentName led to an Activity that was started. 1497 */ startConfirmationActivity(ComponentName componentName, UserHandle userHandle, List<Map.Entry<String, String>> extras)1498 private boolean startConfirmationActivity(ComponentName componentName, UserHandle userHandle, 1499 List<Map.Entry<String, String>> extras) { 1500 PackageManager packageManager = mContext.getPackageManager(); 1501 Intent intent = createConfirmationIntent(componentName, extras); 1502 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1503 if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { 1504 try { 1505 mContext.startActivityAsUser(intent, userHandle); 1506 return true; 1507 } catch (ActivityNotFoundException e) { 1508 Slog.e(TAG, "unable to start adb whitelist activity: " + componentName, e); 1509 } 1510 } 1511 return false; 1512 } 1513 1514 /** 1515 * @return true if the componentName led to a Service that was started. 1516 */ startConfirmationService(ComponentName componentName, UserHandle userHandle, List<Map.Entry<String, String>> extras)1517 private boolean startConfirmationService(ComponentName componentName, UserHandle userHandle, 1518 List<Map.Entry<String, String>> extras) { 1519 Intent intent = createConfirmationIntent(componentName, extras); 1520 try { 1521 if (mContext.startServiceAsUser(intent, userHandle) != null) { 1522 return true; 1523 } 1524 } catch (SecurityException e) { 1525 Slog.e(TAG, "unable to start adb whitelist service: " + componentName, e); 1526 } 1527 return false; 1528 } 1529 createConfirmationIntent(ComponentName componentName, List<Map.Entry<String, String>> extras)1530 private Intent createConfirmationIntent(ComponentName componentName, 1531 List<Map.Entry<String, String>> extras) { 1532 Intent intent = new Intent(); 1533 intent.setClassName(componentName.getPackageName(), componentName.getClassName()); 1534 for (Map.Entry<String, String> entry : extras) { 1535 intent.putExtra(entry.getKey(), entry.getValue()); 1536 } 1537 return intent; 1538 } 1539 1540 /** 1541 * Returns a new File with the specified name in the adb directory. 1542 */ getAdbFile(String fileName)1543 private File getAdbFile(String fileName) { 1544 File dataDir = Environment.getDataDirectory(); 1545 File adbDir = new File(dataDir, ADB_DIRECTORY); 1546 1547 if (!adbDir.exists()) { 1548 Slog.e(TAG, "ADB data directory does not exist"); 1549 return null; 1550 } 1551 1552 return new File(adbDir, fileName); 1553 } 1554 getAdbTempKeysFile()1555 File getAdbTempKeysFile() { 1556 return getAdbFile(ADB_TEMP_KEYS_FILE); 1557 } 1558 getUserKeyFile()1559 File getUserKeyFile() { 1560 return mTestUserKeyFile == null ? getAdbFile(ADB_KEYS_FILE) : mTestUserKeyFile; 1561 } 1562 writeKey(String key)1563 private void writeKey(String key) { 1564 try { 1565 File keyFile = getUserKeyFile(); 1566 1567 if (keyFile == null) { 1568 return; 1569 } 1570 1571 FileOutputStream fo = new FileOutputStream(keyFile, true); 1572 fo.write(key.getBytes()); 1573 fo.write('\n'); 1574 fo.close(); 1575 1576 FileUtils.setPermissions(keyFile.toString(), 1577 FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP, -1, -1); 1578 } catch (IOException ex) { 1579 Slog.e(TAG, "Error writing key:" + ex); 1580 } 1581 } 1582 writeKeys(Iterable<String> keys)1583 private void writeKeys(Iterable<String> keys) { 1584 AtomicFile atomicKeyFile = null; 1585 FileOutputStream fo = null; 1586 try { 1587 File keyFile = getUserKeyFile(); 1588 1589 if (keyFile == null) { 1590 return; 1591 } 1592 1593 atomicKeyFile = new AtomicFile(keyFile); 1594 fo = atomicKeyFile.startWrite(); 1595 for (String key : keys) { 1596 fo.write(key.getBytes()); 1597 fo.write('\n'); 1598 } 1599 atomicKeyFile.finishWrite(fo); 1600 1601 FileUtils.setPermissions(keyFile.toString(), 1602 FileUtils.S_IRUSR | FileUtils.S_IWUSR | FileUtils.S_IRGRP, -1, -1); 1603 } catch (IOException ex) { 1604 Slog.e(TAG, "Error writing keys: " + ex); 1605 if (atomicKeyFile != null) { 1606 atomicKeyFile.failWrite(fo); 1607 } 1608 } 1609 } 1610 deleteKeyFile()1611 private void deleteKeyFile() { 1612 File keyFile = getUserKeyFile(); 1613 if (keyFile != null) { 1614 keyFile.delete(); 1615 } 1616 } 1617 1618 /** 1619 * When {@code enabled} is {@code true}, this allows ADB debugging and starts the ADB handler 1620 * thread. When {@code enabled} is {@code false}, this disallows ADB debugging for the given 1621 * @{code transportType}. See {@link IAdbTransport} for all available transport types. 1622 * If all transport types are disabled, the ADB handler thread will shut down. 1623 */ setAdbEnabled(boolean enabled, byte transportType)1624 public void setAdbEnabled(boolean enabled, byte transportType) { 1625 if (transportType == AdbTransportType.USB) { 1626 mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED 1627 : AdbDebuggingHandler.MESSAGE_ADB_DISABLED); 1628 } else if (transportType == AdbTransportType.WIFI) { 1629 mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MSG_ADBDWIFI_ENABLE 1630 : AdbDebuggingHandler.MSG_ADBDWIFI_DISABLE); 1631 } else { 1632 throw new IllegalArgumentException( 1633 "setAdbEnabled called with unimplemented transport type=" + transportType); 1634 } 1635 } 1636 1637 /** 1638 * Allows the debugging from the endpoint identified by {@code publicKey} either once or 1639 * always if {@code alwaysAllow} is {@code true}. 1640 */ allowDebugging(boolean alwaysAllow, String publicKey)1641 public void allowDebugging(boolean alwaysAllow, String publicKey) { 1642 Message msg = mHandler.obtainMessage(AdbDebuggingHandler.MESSAGE_ADB_ALLOW); 1643 msg.arg1 = alwaysAllow ? 1 : 0; 1644 msg.obj = publicKey; 1645 mHandler.sendMessage(msg); 1646 } 1647 1648 /** 1649 * Denies debugging connection from the device that last requested to connect. 1650 */ denyDebugging()1651 public void denyDebugging() { 1652 mHandler.sendEmptyMessage(AdbDebuggingHandler.MESSAGE_ADB_DENY); 1653 } 1654 1655 /** 1656 * Clears all previously accepted ADB debugging public keys. Any subsequent request will need 1657 * to pass through {@link #allowUsbDebugging(boolean, String)} again. 1658 */ clearDebuggingKeys()1659 public void clearDebuggingKeys() { 1660 mHandler.sendEmptyMessage(AdbDebuggingHandler.MESSAGE_ADB_CLEAR); 1661 } 1662 1663 /** 1664 * Allows wireless debugging on the network identified by {@code bssid} either once 1665 * or always if {@code alwaysAllow} is {@code true}. 1666 */ allowWirelessDebugging(boolean alwaysAllow, String bssid)1667 public void allowWirelessDebugging(boolean alwaysAllow, String bssid) { 1668 Message msg = mHandler.obtainMessage(AdbDebuggingHandler.MSG_ADBWIFI_ALLOW); 1669 msg.arg1 = alwaysAllow ? 1 : 0; 1670 msg.obj = bssid; 1671 mHandler.sendMessage(msg); 1672 } 1673 1674 /** 1675 * Denies wireless debugging connection on the last requested network. 1676 */ denyWirelessDebugging()1677 public void denyWirelessDebugging() { 1678 mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_ADBWIFI_DENY); 1679 } 1680 1681 /** 1682 * Returns the port adbwifi is currently opened on. 1683 */ getAdbWirelessPort()1684 public int getAdbWirelessPort() { 1685 AdbConnectionInfo info = getAdbConnectionInfo(); 1686 if (info == null) { 1687 return 0; 1688 } 1689 return info.getPort(); 1690 } 1691 1692 /** 1693 * Returns the list of paired devices. 1694 */ getPairedDevices()1695 public Map<String, PairDevice> getPairedDevices() { 1696 AdbKeyStore keystore = new AdbKeyStore(); 1697 return keystore.getPairedDevices(); 1698 } 1699 1700 /** 1701 * Unpair with device 1702 */ unpairDevice(String fingerprint)1703 public void unpairDevice(String fingerprint) { 1704 Message message = Message.obtain(mHandler, 1705 AdbDebuggingHandler.MSG_REQ_UNPAIR, 1706 fingerprint); 1707 mHandler.sendMessage(message); 1708 } 1709 1710 /** 1711 * Enable pairing by pairing code 1712 */ enablePairingByPairingCode()1713 public void enablePairingByPairingCode() { 1714 mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_PAIR_PAIRING_CODE); 1715 } 1716 1717 /** 1718 * Enable pairing by pairing code 1719 */ enablePairingByQrCode(String serviceName, String password)1720 public void enablePairingByQrCode(String serviceName, String password) { 1721 Bundle bundle = new Bundle(); 1722 bundle.putString("serviceName", serviceName); 1723 bundle.putString("password", password); 1724 Message message = Message.obtain(mHandler, 1725 AdbDebuggingHandler.MSG_PAIR_QR_CODE, 1726 bundle); 1727 mHandler.sendMessage(message); 1728 } 1729 1730 /** 1731 * Disables pairing 1732 */ disablePairing()1733 public void disablePairing() { 1734 mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_PAIRING_CANCEL); 1735 } 1736 1737 /** 1738 * Status enabled/disabled check 1739 */ isAdbWifiEnabled()1740 public boolean isAdbWifiEnabled() { 1741 return mAdbWifiEnabled; 1742 } 1743 1744 /** 1745 * Sends a message to the handler to persist the keystore. 1746 */ sendPersistKeyStoreMessage()1747 private void sendPersistKeyStoreMessage() { 1748 Message msg = mHandler.obtainMessage(AdbDebuggingHandler.MESSAGE_ADB_PERSIST_KEYSTORE); 1749 mHandler.sendMessage(msg); 1750 } 1751 1752 /** 1753 * Dump the USB debugging state. 1754 */ dump(DualDumpOutputStream dump, String idName, long id)1755 public void dump(DualDumpOutputStream dump, String idName, long id) { 1756 long token = dump.start(idName, id); 1757 1758 dump.write("connected_to_adb", AdbDebuggingManagerProto.CONNECTED_TO_ADB, mThread != null); 1759 writeStringIfNotNull(dump, "last_key_received", AdbDebuggingManagerProto.LAST_KEY_RECEVIED, 1760 mFingerprints); 1761 1762 try { 1763 dump.write("user_keys", AdbDebuggingManagerProto.USER_KEYS, 1764 FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null)); 1765 } catch (IOException e) { 1766 Slog.i(TAG, "Cannot read user keys", e); 1767 } 1768 1769 try { 1770 dump.write("system_keys", AdbDebuggingManagerProto.SYSTEM_KEYS, 1771 FileUtils.readTextFile(new File("/adb_keys"), 0, null)); 1772 } catch (IOException e) { 1773 Slog.i(TAG, "Cannot read system keys", e); 1774 } 1775 1776 try { 1777 dump.write("keystore", AdbDebuggingManagerProto.KEYSTORE, 1778 FileUtils.readTextFile(getAdbTempKeysFile(), 0, null)); 1779 } catch (IOException e) { 1780 Slog.i(TAG, "Cannot read keystore: ", e); 1781 } 1782 1783 dump.end(token); 1784 } 1785 1786 /** 1787 * Handles adb keys for which the user has granted the 'always allow' option. This class ensures 1788 * these grants are revoked after a period of inactivity as specified in the 1789 * ADB_ALLOWED_CONNECTION_TIME setting. 1790 */ 1791 class AdbKeyStore { 1792 private Map<String, Long> mKeyMap; 1793 private Set<String> mSystemKeys; 1794 private File mKeyFile; 1795 private AtomicFile mAtomicKeyFile; 1796 1797 private List<String> mTrustedNetworks; 1798 private static final int KEYSTORE_VERSION = 1; 1799 private static final int MAX_SUPPORTED_KEYSTORE_VERSION = 1; 1800 private static final String XML_KEYSTORE_START_TAG = "keyStore"; 1801 private static final String XML_ATTRIBUTE_VERSION = "version"; 1802 private static final String XML_TAG_ADB_KEY = "adbKey"; 1803 private static final String XML_ATTRIBUTE_KEY = "key"; 1804 private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection"; 1805 // A list of trusted networks a device can always wirelessly debug on (always allow). 1806 // TODO: Move trusted networks list into a different file? 1807 private static final String XML_TAG_WIFI_ACCESS_POINT = "wifiAP"; 1808 private static final String XML_ATTRIBUTE_WIFI_BSSID = "bssid"; 1809 1810 private static final String SYSTEM_KEY_FILE = "/adb_keys"; 1811 1812 /** 1813 * Value returned by {@code getLastConnectionTime} when there is no previously saved 1814 * connection time for the specified key. 1815 */ 1816 public static final long NO_PREVIOUS_CONNECTION = 0; 1817 1818 /** 1819 * Constructor that uses the default location for the persistent adb keystore. 1820 */ AdbKeyStore()1821 AdbKeyStore() { 1822 init(); 1823 } 1824 1825 /** 1826 * Constructor that uses the specified file as the location for the persistent adb keystore. 1827 */ AdbKeyStore(File keyFile)1828 AdbKeyStore(File keyFile) { 1829 mKeyFile = keyFile; 1830 init(); 1831 } 1832 init()1833 private void init() { 1834 initKeyFile(); 1835 mKeyMap = getKeyMap(); 1836 mTrustedNetworks = getTrustedNetworks(); 1837 mSystemKeys = getSystemKeysFromFile(SYSTEM_KEY_FILE); 1838 addUserKeysToKeyStore(); 1839 } 1840 addTrustedNetwork(String bssid)1841 public void addTrustedNetwork(String bssid) { 1842 mTrustedNetworks.add(bssid); 1843 sendPersistKeyStoreMessage(); 1844 } 1845 getPairedDevices()1846 public Map<String, PairDevice> getPairedDevices() { 1847 Map<String, PairDevice> pairedDevices = new HashMap<String, PairDevice>(); 1848 for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) { 1849 String fingerprints = getFingerprints(keyEntry.getKey()); 1850 String hostname = "nouser@nohostname"; 1851 String[] args = keyEntry.getKey().split("\\s+"); 1852 if (args.length > 1) { 1853 hostname = args[1]; 1854 } 1855 pairedDevices.put(keyEntry.getKey(), new PairDevice( 1856 hostname, fingerprints, mWifiConnectedKeys.contains(keyEntry.getKey()))); 1857 } 1858 return pairedDevices; 1859 } 1860 findKeyFromFingerprint(String fingerprint)1861 public String findKeyFromFingerprint(String fingerprint) { 1862 for (Map.Entry<String, Long> entry : mKeyMap.entrySet()) { 1863 String f = getFingerprints(entry.getKey()); 1864 if (fingerprint.equals(f)) { 1865 return entry.getKey(); 1866 } 1867 } 1868 return null; 1869 } 1870 removeKey(String key)1871 public void removeKey(String key) { 1872 if (mKeyMap.containsKey(key)) { 1873 mKeyMap.remove(key); 1874 writeKeys(mKeyMap.keySet()); 1875 sendPersistKeyStoreMessage(); 1876 } 1877 } 1878 1879 /** 1880 * Initializes the key file that will be used to persist the adb grants. 1881 */ initKeyFile()1882 private void initKeyFile() { 1883 if (mKeyFile == null) { 1884 mKeyFile = getAdbTempKeysFile(); 1885 } 1886 // getAdbTempKeysFile can return null if the adb file cannot be obtained 1887 if (mKeyFile != null) { 1888 mAtomicKeyFile = new AtomicFile(mKeyFile); 1889 } 1890 } 1891 getSystemKeysFromFile(String fileName)1892 private Set<String> getSystemKeysFromFile(String fileName) { 1893 Set<String> systemKeys = new HashSet<>(); 1894 File systemKeyFile = new File(fileName); 1895 if (systemKeyFile.exists()) { 1896 try (BufferedReader in = new BufferedReader(new FileReader(systemKeyFile))) { 1897 String key; 1898 while ((key = in.readLine()) != null) { 1899 key = key.trim(); 1900 if (key.length() > 0) { 1901 systemKeys.add(key); 1902 } 1903 } 1904 } catch (IOException e) { 1905 Slog.e(TAG, "Caught an exception reading " + fileName + ": " + e); 1906 } 1907 } 1908 return systemKeys; 1909 } 1910 1911 /** 1912 * Returns whether there are any 'always allowed' keys in the keystore. 1913 */ isEmpty()1914 public boolean isEmpty() { 1915 return mKeyMap.isEmpty(); 1916 } 1917 1918 /** 1919 * Iterates through the keys in the keystore and removes any that are beyond the window 1920 * within which connections are automatically allowed without user interaction. 1921 */ updateKeyStore()1922 public void updateKeyStore() { 1923 if (filterOutOldKeys()) { 1924 sendPersistKeyStoreMessage(); 1925 } 1926 } 1927 1928 /** 1929 * Returns the key map with the keys and last connection times from the key file. 1930 */ getKeyMap()1931 private Map<String, Long> getKeyMap() { 1932 Map<String, Long> keyMap = new HashMap<String, Long>(); 1933 // if the AtomicFile could not be instantiated before attempt again; if it still fails 1934 // return an empty key map. 1935 if (mAtomicKeyFile == null) { 1936 initKeyFile(); 1937 if (mAtomicKeyFile == null) { 1938 Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); 1939 return keyMap; 1940 } 1941 } 1942 if (!mAtomicKeyFile.exists()) { 1943 return keyMap; 1944 } 1945 try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { 1946 TypedXmlPullParser parser = Xml.resolvePullParser(keyStream); 1947 // Check for supported keystore version. 1948 XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); 1949 if (parser.next() != XmlPullParser.END_DOCUMENT) { 1950 String tagName = parser.getName(); 1951 if (tagName == null || !XML_KEYSTORE_START_TAG.equals(tagName)) { 1952 Slog.e(TAG, "Expected " + XML_KEYSTORE_START_TAG + ", but got tag=" 1953 + tagName); 1954 return keyMap; 1955 } 1956 int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION); 1957 if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) { 1958 Slog.e(TAG, "Keystore version=" + keystoreVersion 1959 + " not supported (max_supported=" 1960 + MAX_SUPPORTED_KEYSTORE_VERSION + ")"); 1961 return keyMap; 1962 } 1963 } 1964 while (parser.next() != XmlPullParser.END_DOCUMENT) { 1965 String tagName = parser.getName(); 1966 if (tagName == null) { 1967 break; 1968 } else if (!tagName.equals(XML_TAG_ADB_KEY)) { 1969 XmlUtils.skipCurrentTag(parser); 1970 continue; 1971 } 1972 String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY); 1973 long connectionTime; 1974 try { 1975 connectionTime = parser.getAttributeLong(null, 1976 XML_ATTRIBUTE_LAST_CONNECTION); 1977 } catch (XmlPullParserException e) { 1978 Slog.e(TAG, 1979 "Caught a NumberFormatException parsing the last connection time: " 1980 + e); 1981 XmlUtils.skipCurrentTag(parser); 1982 continue; 1983 } 1984 keyMap.put(key, connectionTime); 1985 } 1986 } catch (IOException e) { 1987 Slog.e(TAG, "Caught an IOException parsing the XML key file: ", e); 1988 } catch (XmlPullParserException e) { 1989 Slog.w(TAG, "Caught XmlPullParserException parsing the XML key file: ", e); 1990 // The file could be written in a format prior to introducing keystore tag. 1991 return getKeyMapBeforeKeystoreVersion(); 1992 } 1993 return keyMap; 1994 } 1995 1996 1997 /** 1998 * Returns the key map with the keys and last connection times from the key file. 1999 * This implementation was prior to adding the XML_KEYSTORE_START_TAG. 2000 */ getKeyMapBeforeKeystoreVersion()2001 private Map<String, Long> getKeyMapBeforeKeystoreVersion() { 2002 Map<String, Long> keyMap = new HashMap<String, Long>(); 2003 // if the AtomicFile could not be instantiated before attempt again; if it still fails 2004 // return an empty key map. 2005 if (mAtomicKeyFile == null) { 2006 initKeyFile(); 2007 if (mAtomicKeyFile == null) { 2008 Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); 2009 return keyMap; 2010 } 2011 } 2012 if (!mAtomicKeyFile.exists()) { 2013 return keyMap; 2014 } 2015 try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { 2016 TypedXmlPullParser parser = Xml.resolvePullParser(keyStream); 2017 XmlUtils.beginDocument(parser, XML_TAG_ADB_KEY); 2018 while (parser.next() != XmlPullParser.END_DOCUMENT) { 2019 String tagName = parser.getName(); 2020 if (tagName == null) { 2021 break; 2022 } else if (!tagName.equals(XML_TAG_ADB_KEY)) { 2023 XmlUtils.skipCurrentTag(parser); 2024 continue; 2025 } 2026 String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY); 2027 long connectionTime; 2028 try { 2029 connectionTime = parser.getAttributeLong(null, 2030 XML_ATTRIBUTE_LAST_CONNECTION); 2031 } catch (XmlPullParserException e) { 2032 Slog.e(TAG, 2033 "Caught a NumberFormatException parsing the last connection time: " 2034 + e); 2035 XmlUtils.skipCurrentTag(parser); 2036 continue; 2037 } 2038 keyMap.put(key, connectionTime); 2039 } 2040 } catch (IOException | XmlPullParserException e) { 2041 Slog.e(TAG, "Caught an exception parsing the XML key file: ", e); 2042 } 2043 return keyMap; 2044 } 2045 2046 /** 2047 * Returns the map of trusted networks from the keystore file. 2048 * 2049 * This was implemented in keystore version 1. 2050 */ getTrustedNetworks()2051 private List<String> getTrustedNetworks() { 2052 List<String> trustedNetworks = new ArrayList<String>(); 2053 // if the AtomicFile could not be instantiated before attempt again; if it still fails 2054 // return an empty key map. 2055 if (mAtomicKeyFile == null) { 2056 initKeyFile(); 2057 if (mAtomicKeyFile == null) { 2058 Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); 2059 return trustedNetworks; 2060 } 2061 } 2062 if (!mAtomicKeyFile.exists()) { 2063 return trustedNetworks; 2064 } 2065 try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { 2066 TypedXmlPullParser parser = Xml.resolvePullParser(keyStream); 2067 // Check for supported keystore version. 2068 XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); 2069 if (parser.next() != XmlPullParser.END_DOCUMENT) { 2070 String tagName = parser.getName(); 2071 if (tagName == null || !XML_KEYSTORE_START_TAG.equals(tagName)) { 2072 Slog.e(TAG, "Expected " + XML_KEYSTORE_START_TAG + ", but got tag=" 2073 + tagName); 2074 return trustedNetworks; 2075 } 2076 int keystoreVersion = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION); 2077 if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) { 2078 Slog.e(TAG, "Keystore version=" + keystoreVersion 2079 + " not supported (max_supported=" 2080 + MAX_SUPPORTED_KEYSTORE_VERSION); 2081 return trustedNetworks; 2082 } 2083 } 2084 while (parser.next() != XmlPullParser.END_DOCUMENT) { 2085 String tagName = parser.getName(); 2086 if (tagName == null) { 2087 break; 2088 } else if (!tagName.equals(XML_TAG_WIFI_ACCESS_POINT)) { 2089 XmlUtils.skipCurrentTag(parser); 2090 continue; 2091 } 2092 String bssid = parser.getAttributeValue(null, XML_ATTRIBUTE_WIFI_BSSID); 2093 trustedNetworks.add(bssid); 2094 } 2095 } catch (IOException | XmlPullParserException | NumberFormatException e) { 2096 Slog.e(TAG, "Caught an exception parsing the XML key file: ", e); 2097 } 2098 return trustedNetworks; 2099 } 2100 2101 /** 2102 * Updates the keystore with keys that were previously set to be always allowed before the 2103 * connection time of keys was tracked. 2104 */ addUserKeysToKeyStore()2105 private void addUserKeysToKeyStore() { 2106 File userKeyFile = getUserKeyFile(); 2107 boolean mapUpdated = false; 2108 if (userKeyFile != null && userKeyFile.exists()) { 2109 try (BufferedReader in = new BufferedReader(new FileReader(userKeyFile))) { 2110 long time = System.currentTimeMillis(); 2111 String key; 2112 while ((key = in.readLine()) != null) { 2113 // if the keystore does not contain the key from the user key file then add 2114 // it to the Map with the current system time to prevent it from expiring 2115 // immediately if the user is actively using this key. 2116 if (!mKeyMap.containsKey(key)) { 2117 mKeyMap.put(key, time); 2118 mapUpdated = true; 2119 } 2120 } 2121 } catch (IOException e) { 2122 Slog.e(TAG, "Caught an exception reading " + userKeyFile + ": " + e); 2123 } 2124 } 2125 if (mapUpdated) { 2126 sendPersistKeyStoreMessage(); 2127 } 2128 } 2129 2130 /** 2131 * Writes the key map to the key file. 2132 */ persistKeyStore()2133 public void persistKeyStore() { 2134 // if there is nothing in the key map then ensure any keys left in the keystore files 2135 // are deleted as well. 2136 filterOutOldKeys(); 2137 if (mKeyMap.isEmpty() && mTrustedNetworks.isEmpty()) { 2138 deleteKeyStore(); 2139 return; 2140 } 2141 if (mAtomicKeyFile == null) { 2142 initKeyFile(); 2143 if (mAtomicKeyFile == null) { 2144 Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for writing"); 2145 return; 2146 } 2147 } 2148 FileOutputStream keyStream = null; 2149 try { 2150 keyStream = mAtomicKeyFile.startWrite(); 2151 TypedXmlSerializer serializer = Xml.resolveSerializer(keyStream); 2152 serializer.startDocument(null, true); 2153 2154 serializer.startTag(null, XML_KEYSTORE_START_TAG); 2155 serializer.attributeInt(null, XML_ATTRIBUTE_VERSION, KEYSTORE_VERSION); 2156 for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) { 2157 serializer.startTag(null, XML_TAG_ADB_KEY); 2158 serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey()); 2159 serializer.attributeLong(null, XML_ATTRIBUTE_LAST_CONNECTION, 2160 keyEntry.getValue()); 2161 serializer.endTag(null, XML_TAG_ADB_KEY); 2162 } 2163 for (String bssid : mTrustedNetworks) { 2164 serializer.startTag(null, XML_TAG_WIFI_ACCESS_POINT); 2165 serializer.attribute(null, XML_ATTRIBUTE_WIFI_BSSID, bssid); 2166 serializer.endTag(null, XML_TAG_WIFI_ACCESS_POINT); 2167 } 2168 serializer.endTag(null, XML_KEYSTORE_START_TAG); 2169 serializer.endDocument(); 2170 mAtomicKeyFile.finishWrite(keyStream); 2171 } catch (IOException e) { 2172 Slog.e(TAG, "Caught an exception writing the key map: ", e); 2173 mAtomicKeyFile.failWrite(keyStream); 2174 } 2175 } 2176 filterOutOldKeys()2177 private boolean filterOutOldKeys() { 2178 boolean keysDeleted = false; 2179 long allowedTime = getAllowedConnectionTime(); 2180 long systemTime = System.currentTimeMillis(); 2181 Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator(); 2182 while (keyMapIterator.hasNext()) { 2183 Map.Entry<String, Long> keyEntry = keyMapIterator.next(); 2184 long connectionTime = keyEntry.getValue(); 2185 if (allowedTime != 0 && systemTime > (connectionTime + allowedTime)) { 2186 keyMapIterator.remove(); 2187 keysDeleted = true; 2188 } 2189 } 2190 // if any keys were deleted then the key file should be rewritten with the active keys 2191 // to prevent authorizing a key that is now beyond the allowed window. 2192 if (keysDeleted) { 2193 writeKeys(mKeyMap.keySet()); 2194 } 2195 return keysDeleted; 2196 } 2197 2198 /** 2199 * Returns the time in ms that the next key will expire or -1 if there are no keys or the 2200 * keys will not expire. 2201 */ getNextExpirationTime()2202 public long getNextExpirationTime() { 2203 long minExpiration = -1; 2204 long allowedTime = getAllowedConnectionTime(); 2205 // if the allowedTime is 0 then keys never expire; return -1 to indicate this 2206 if (allowedTime == 0) { 2207 return minExpiration; 2208 } 2209 long systemTime = System.currentTimeMillis(); 2210 Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator(); 2211 while (keyMapIterator.hasNext()) { 2212 Map.Entry<String, Long> keyEntry = keyMapIterator.next(); 2213 long connectionTime = keyEntry.getValue(); 2214 // if the key has already expired then ensure that the result is set to 0 so that 2215 // any scheduled jobs to clean up the keystore can run right away. 2216 long keyExpiration = Math.max(0, (connectionTime + allowedTime) - systemTime); 2217 if (minExpiration == -1 || keyExpiration < minExpiration) { 2218 minExpiration = keyExpiration; 2219 } 2220 } 2221 return minExpiration; 2222 } 2223 2224 /** 2225 * Removes all of the entries in the key map and deletes the key file. 2226 */ deleteKeyStore()2227 public void deleteKeyStore() { 2228 mKeyMap.clear(); 2229 mTrustedNetworks.clear(); 2230 deleteKeyFile(); 2231 if (mAtomicKeyFile == null) { 2232 return; 2233 } 2234 mAtomicKeyFile.delete(); 2235 } 2236 2237 /** 2238 * Returns the time of the last connection from the specified key, or {@code 2239 * NO_PREVIOUS_CONNECTION} if the specified key does not have an active adb grant. 2240 */ getLastConnectionTime(String key)2241 public long getLastConnectionTime(String key) { 2242 return mKeyMap.getOrDefault(key, NO_PREVIOUS_CONNECTION); 2243 } 2244 2245 /** 2246 * Sets the time of the last connection for the specified key to the provided time. 2247 */ setLastConnectionTime(String key, long connectionTime)2248 public void setLastConnectionTime(String key, long connectionTime) { 2249 setLastConnectionTime(key, connectionTime, false); 2250 } 2251 2252 /** 2253 * Sets the time of the last connection for the specified key to the provided time. If force 2254 * is set to true the time will be set even if it is older than the previously written 2255 * connection time. 2256 */ setLastConnectionTime(String key, long connectionTime, boolean force)2257 public void setLastConnectionTime(String key, long connectionTime, boolean force) { 2258 // Do not set the connection time to a value that is earlier than what was previously 2259 // stored as the last connection time unless force is set. 2260 if (mKeyMap.containsKey(key) && mKeyMap.get(key) >= connectionTime && !force) { 2261 return; 2262 } 2263 // System keys are always allowed so there's no need to keep track of their connection 2264 // time. 2265 if (mSystemKeys.contains(key)) { 2266 return; 2267 } 2268 // if this is the first time the key is being added then write it to the key file as 2269 // well. 2270 if (!mKeyMap.containsKey(key)) { 2271 writeKey(key); 2272 } 2273 mKeyMap.put(key, connectionTime); 2274 } 2275 2276 /** 2277 * Returns the connection time within which a connection from an allowed key is 2278 * automatically allowed without user interaction. 2279 */ getAllowedConnectionTime()2280 public long getAllowedConnectionTime() { 2281 return Settings.Global.getLong(mContext.getContentResolver(), 2282 Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 2283 Settings.Global.DEFAULT_ADB_ALLOWED_CONNECTION_TIME); 2284 } 2285 2286 /** 2287 * Returns whether the specified key should be authroized to connect without user 2288 * interaction. This requires that the user previously connected this device and selected 2289 * the option to 'Always allow', and the time since the last connection is within the 2290 * allowed window. 2291 */ isKeyAuthorized(String key)2292 public boolean isKeyAuthorized(String key) { 2293 // A system key is always authorized to connect. 2294 if (mSystemKeys.contains(key)) { 2295 return true; 2296 } 2297 long lastConnectionTime = getLastConnectionTime(key); 2298 if (lastConnectionTime == NO_PREVIOUS_CONNECTION) { 2299 return false; 2300 } 2301 long allowedConnectionTime = getAllowedConnectionTime(); 2302 // if the allowed connection time is 0 then revert to the previous behavior of always 2303 // allowing previously granted adb grants. 2304 if (allowedConnectionTime == 0 || (System.currentTimeMillis() < (lastConnectionTime 2305 + allowedConnectionTime))) { 2306 return true; 2307 } else { 2308 return false; 2309 } 2310 } 2311 2312 /** 2313 * Returns whether the specified bssid is in the list of trusted networks. This requires 2314 * that the user previously allowed wireless debugging on this network and selected the 2315 * option to 'Always allow'. 2316 */ isTrustedNetwork(String bssid)2317 public boolean isTrustedNetwork(String bssid) { 2318 return mTrustedNetworks.contains(bssid); 2319 } 2320 } 2321 } 2322