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