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