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