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