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