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