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