1 /* 2 * Copyright (C) 2018 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 package com.android.server.adb; 17 18 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 19 20 import android.annotation.NonNull; 21 import android.annotation.UserIdInt; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.pm.PackageManager; 25 import android.database.ContentObserver; 26 import android.debug.AdbManagerInternal; 27 import android.debug.AdbTransportType; 28 import android.debug.FingerprintAndPairDevice; 29 import android.debug.IAdbCallback; 30 import android.debug.IAdbManager; 31 import android.debug.IAdbTransport; 32 import android.debug.PairDevice; 33 import android.hardware.usb.UsbManager; 34 import android.net.Uri; 35 import android.net.wifi.WifiManager; 36 import android.os.Binder; 37 import android.os.IBinder; 38 import android.os.ParcelFileDescriptor; 39 import android.os.RemoteCallbackList; 40 import android.os.RemoteException; 41 import android.os.SystemProperties; 42 import android.provider.Settings; 43 import android.service.adb.AdbServiceDumpProto; 44 import android.util.ArrayMap; 45 import android.util.ArraySet; 46 import android.util.Slog; 47 import android.util.proto.ProtoOutputStream; 48 49 import com.android.internal.util.DumpUtils; 50 import com.android.internal.util.IndentingPrintWriter; 51 import com.android.internal.util.Preconditions; 52 import com.android.internal.util.dump.DualDumpOutputStream; 53 import com.android.server.FgThread; 54 import com.android.server.LocalServices; 55 import com.android.server.SystemService; 56 import com.android.server.testharness.TestHarnessModeService; 57 58 import java.io.File; 59 import java.io.FileDescriptor; 60 import java.io.PrintWriter; 61 import java.util.Collections; 62 import java.util.Map; 63 64 /** 65 * The Android Debug Bridge (ADB) service. This controls the availability of ADB and authorization 66 * of devices allowed to connect to ADB. 67 */ 68 public class AdbService extends IAdbManager.Stub { 69 /** 70 * Adb native daemon. 71 */ 72 static final String ADBD = "adbd"; 73 74 /** 75 * Command to start native service. 76 */ 77 static final String CTL_START = "ctl.start"; 78 79 /** 80 * Command to start native service. 81 */ 82 static final String CTL_STOP = "ctl.stop"; 83 84 private final RemoteCallbackList<IAdbCallback> mCallbacks = new RemoteCallbackList<>(); 85 /** 86 * Manages the service lifecycle for {@code AdbService} in {@code SystemServer}. 87 */ 88 public static class Lifecycle extends SystemService { 89 private AdbService mAdbService; 90 Lifecycle(Context context)91 public Lifecycle(Context context) { 92 super(context); 93 } 94 95 @Override onStart()96 public void onStart() { 97 mAdbService = new AdbService(getContext()); 98 publishBinderService(Context.ADB_SERVICE, mAdbService); 99 } 100 101 @Override onBootPhase(int phase)102 public void onBootPhase(int phase) { 103 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 104 mAdbService.systemReady(); 105 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { 106 FgThread.getHandler().sendMessage(obtainMessage( 107 AdbService::bootCompleted, mAdbService)); 108 } 109 } 110 } 111 112 private class AdbManagerInternalImpl extends AdbManagerInternal { 113 @Override registerTransport(IAdbTransport transport)114 public void registerTransport(IAdbTransport transport) { 115 mTransports.put(transport.asBinder(), transport); 116 } 117 118 @Override unregisterTransport(IAdbTransport transport)119 public void unregisterTransport(IAdbTransport transport) { 120 mTransports.remove(transport.asBinder()); 121 } 122 123 @Override isAdbEnabled(byte transportType)124 public boolean isAdbEnabled(byte transportType) { 125 if (transportType == AdbTransportType.USB) { 126 return mIsAdbUsbEnabled; 127 } else if (transportType == AdbTransportType.WIFI) { 128 return mIsAdbWifiEnabled; 129 } 130 throw new IllegalArgumentException( 131 "isAdbEnabled called with unimplemented transport type=" + transportType); 132 } 133 134 @Override getAdbKeysFile()135 public File getAdbKeysFile() { 136 return mDebuggingManager.getUserKeyFile(); 137 } 138 139 @Override getAdbTempKeysFile()140 public File getAdbTempKeysFile() { 141 return mDebuggingManager.getAdbTempKeysFile(); 142 } 143 144 @Override notifyKeyFilesUpdated()145 public void notifyKeyFilesUpdated() { 146 mDebuggingManager.notifyKeyFilesUpdated(); 147 } 148 149 @Override startAdbdForTransport(byte transportType)150 public void startAdbdForTransport(byte transportType) { 151 FgThread.getHandler().sendMessage(obtainMessage( 152 AdbService::setAdbdEnabledForTransport, AdbService.this, true, transportType)); 153 } 154 155 @Override stopAdbdForTransport(byte transportType)156 public void stopAdbdForTransport(byte transportType) { 157 FgThread.getHandler().sendMessage(obtainMessage( 158 AdbService::setAdbdEnabledForTransport, AdbService.this, false, transportType)); 159 } 160 } 161 registerContentObservers()162 private void registerContentObservers() { 163 try { 164 // register observer to listen for settings changes 165 mObserver = new AdbSettingsObserver(); 166 mContentResolver.registerContentObserver( 167 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), 168 false, mObserver); 169 mContentResolver.registerContentObserver( 170 Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED), 171 false, mObserver); 172 } catch (Exception e) { 173 Slog.e(TAG, "Error in registerContentObservers", e); 174 } 175 } 176 containsFunction(String functions, String function)177 private static boolean containsFunction(String functions, String function) { 178 int index = functions.indexOf(function); 179 if (index < 0) return false; 180 if (index > 0 && functions.charAt(index - 1) != ',') return false; 181 int charAfter = index + function.length(); 182 if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; 183 return true; 184 } 185 186 private class AdbSettingsObserver extends ContentObserver { 187 private final Uri mAdbUsbUri = Settings.Global.getUriFor(Settings.Global.ADB_ENABLED); 188 private final Uri mAdbWifiUri = Settings.Global.getUriFor(Settings.Global.ADB_WIFI_ENABLED); 189 AdbSettingsObserver()190 AdbSettingsObserver() { 191 super(null); 192 } 193 194 @Override onChange(boolean selfChange, @NonNull Uri uri, @UserIdInt int userId)195 public void onChange(boolean selfChange, @NonNull Uri uri, @UserIdInt int userId) { 196 Slog.d("AdbSettingsObserver", "onChange " + uri.toString()); 197 if (mAdbUsbUri.equals(uri)) { 198 boolean shouldEnable = (Settings.Global.getInt(mContentResolver, 199 Settings.Global.ADB_ENABLED, 0) > 0); 200 FgThread.getHandler().sendMessage(obtainMessage( 201 AdbService::setAdbEnabled, AdbService.this, shouldEnable, 202 AdbTransportType.USB)); 203 } else if (mAdbWifiUri.equals(uri)) { 204 boolean shouldEnable = (Settings.Global.getInt(mContentResolver, 205 Settings.Global.ADB_WIFI_ENABLED, 0) > 0); 206 FgThread.getHandler().sendMessage(obtainMessage( 207 AdbService::setAdbEnabled, AdbService.this, shouldEnable, 208 AdbTransportType.WIFI)); 209 } 210 } 211 } 212 213 private static final String TAG = AdbService.class.getSimpleName(); 214 215 /** 216 * The persistent property which stores whether adb is enabled or not. 217 * May also contain vendor-specific default functions for testing purposes. 218 */ 219 private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; 220 static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable"; 221 222 private final Context mContext; 223 private final ContentResolver mContentResolver; 224 private final ArrayMap<IBinder, IAdbTransport> mTransports = new ArrayMap<>(); 225 226 private boolean mIsAdbUsbEnabled; 227 private boolean mIsAdbWifiEnabled; 228 private final AdbDebuggingManager mDebuggingManager; 229 230 private ContentObserver mObserver; 231 AdbService(Context context)232 private AdbService(Context context) { 233 mContext = context; 234 mContentResolver = context.getContentResolver(); 235 mDebuggingManager = new AdbDebuggingManager(context); 236 237 registerContentObservers(); 238 LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl()); 239 } 240 241 /** 242 * Called in response to {@code SystemService.PHASE_ACTIVITY_MANAGER_READY} from {@code 243 * SystemServer}. 244 */ systemReady()245 public void systemReady() { 246 Slog.d(TAG, "systemReady"); 247 248 /* 249 * Use the normal bootmode persistent prop to maintain state of adb across 250 * all boot modes. 251 */ 252 mIsAdbUsbEnabled = containsFunction( 253 SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""), 254 UsbManager.USB_FUNCTION_ADB); 255 boolean shouldEnableAdbUsb = mIsAdbUsbEnabled 256 || SystemProperties.getBoolean( 257 TestHarnessModeService.TEST_HARNESS_MODE_PROPERTY, false); 258 mIsAdbWifiEnabled = "1".equals( 259 SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0")); 260 261 // make sure the ADB_ENABLED setting value matches the current state 262 try { 263 Settings.Global.putInt(mContentResolver, 264 Settings.Global.ADB_ENABLED, shouldEnableAdbUsb ? 1 : 0); 265 Settings.Global.putInt(mContentResolver, 266 Settings.Global.ADB_WIFI_ENABLED, mIsAdbWifiEnabled ? 1 : 0); 267 } catch (SecurityException e) { 268 // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed. 269 Slog.d(TAG, "ADB_ENABLED is restricted."); 270 } 271 } 272 273 /** 274 * Called in response to {@code SystemService.PHASE_BOOT_COMPLETED} from {@code SystemServer}. 275 */ bootCompleted()276 public void bootCompleted() { 277 Slog.d(TAG, "boot completed"); 278 mDebuggingManager.setAdbEnabled(mIsAdbUsbEnabled, AdbTransportType.USB); 279 mDebuggingManager.setAdbEnabled(mIsAdbWifiEnabled, AdbTransportType.WIFI); 280 } 281 282 @Override allowDebugging(boolean alwaysAllow, @NonNull String publicKey)283 public void allowDebugging(boolean alwaysAllow, @NonNull String publicKey) { 284 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 285 Preconditions.checkStringNotEmpty(publicKey); 286 mDebuggingManager.allowDebugging(alwaysAllow, publicKey); 287 } 288 289 @Override denyDebugging()290 public void denyDebugging() { 291 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 292 mDebuggingManager.denyDebugging(); 293 } 294 295 @Override clearDebuggingKeys()296 public void clearDebuggingKeys() { 297 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 298 mDebuggingManager.clearDebuggingKeys(); 299 } 300 301 /** 302 * @return true if the device supports secure ADB over Wi-Fi or Ethernet. 303 * @hide 304 */ 305 @Override isAdbWifiSupported()306 public boolean isAdbWifiSupported() { 307 mContext.enforceCallingPermission( 308 android.Manifest.permission.MANAGE_DEBUGGING, "AdbService"); 309 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) || 310 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_ETHERNET); 311 } 312 313 /** 314 * @return true if the device supports secure ADB over Wi-Fi and device pairing by 315 * QR code. 316 * @hide 317 */ 318 @Override isAdbWifiQrSupported()319 public boolean isAdbWifiQrSupported() { 320 mContext.enforceCallingPermission( 321 android.Manifest.permission.MANAGE_DEBUGGING, "AdbService"); 322 return isAdbWifiSupported() && mContext.getPackageManager().hasSystemFeature( 323 PackageManager.FEATURE_CAMERA_ANY); 324 } 325 326 @Override allowWirelessDebugging(boolean alwaysAllow, @NonNull String bssid)327 public void allowWirelessDebugging(boolean alwaysAllow, @NonNull String bssid) { 328 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 329 Preconditions.checkStringNotEmpty(bssid); 330 mDebuggingManager.allowWirelessDebugging(alwaysAllow, bssid); 331 } 332 333 @Override denyWirelessDebugging()334 public void denyWirelessDebugging() { 335 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 336 mDebuggingManager.denyWirelessDebugging(); 337 } 338 339 @Override getPairedDevices()340 public FingerprintAndPairDevice[] getPairedDevices() { 341 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 342 Map<String, PairDevice> map = mDebuggingManager.getPairedDevices(); 343 FingerprintAndPairDevice[] ret = new FingerprintAndPairDevice[map.size()]; 344 int i = 0; 345 for (Map.Entry<String, PairDevice> entry : map.entrySet()) { 346 ret[i] = new FingerprintAndPairDevice(); 347 ret[i].keyFingerprint = entry.getKey(); 348 ret[i].device = entry.getValue(); 349 i++; 350 } 351 return ret; 352 } 353 354 @Override unpairDevice(@onNull String fingerprint)355 public void unpairDevice(@NonNull String fingerprint) { 356 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 357 Preconditions.checkStringNotEmpty(fingerprint); 358 mDebuggingManager.unpairDevice(fingerprint); 359 } 360 361 @Override enablePairingByPairingCode()362 public void enablePairingByPairingCode() { 363 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 364 mDebuggingManager.enablePairingByPairingCode(); 365 } 366 367 @Override enablePairingByQrCode(@onNull String serviceName, @NonNull String password)368 public void enablePairingByQrCode(@NonNull String serviceName, @NonNull String password) { 369 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 370 Preconditions.checkStringNotEmpty(serviceName); 371 Preconditions.checkStringNotEmpty(password); 372 mDebuggingManager.enablePairingByQrCode(serviceName, password); 373 } 374 375 @Override disablePairing()376 public void disablePairing() { 377 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 378 mDebuggingManager.disablePairing(); 379 } 380 381 @Override getAdbWirelessPort()382 public int getAdbWirelessPort() { 383 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); 384 return mDebuggingManager.getAdbWirelessPort(); 385 } 386 387 @Override registerCallback(IAdbCallback callback)388 public void registerCallback(IAdbCallback callback) throws RemoteException { 389 Slog.d(TAG, "Registering callback " + callback); 390 mCallbacks.register(callback); 391 } 392 393 @Override unregisterCallback(IAdbCallback callback)394 public void unregisterCallback(IAdbCallback callback) throws RemoteException { 395 Slog.d(TAG, "Unregistering callback " + callback); 396 mCallbacks.unregister(callback); 397 } 398 startAdbd()399 private void startAdbd() { 400 SystemProperties.set(CTL_START, ADBD); 401 } 402 stopAdbd()403 private void stopAdbd() { 404 if (!mIsAdbUsbEnabled && !mIsAdbWifiEnabled) { 405 SystemProperties.set(CTL_STOP, ADBD); 406 } 407 } 408 setAdbdEnabledForTransport(boolean enable, byte transportType)409 private void setAdbdEnabledForTransport(boolean enable, byte transportType) { 410 if (transportType == AdbTransportType.USB) { 411 mIsAdbUsbEnabled = enable; 412 } else if (transportType == AdbTransportType.WIFI) { 413 mIsAdbWifiEnabled = enable; 414 } 415 if (enable) { 416 startAdbd(); 417 } else { 418 stopAdbd(); 419 } 420 } 421 422 private WifiManager.MulticastLock mAdbMulticastLock = null; 423 acquireMulticastLock()424 private void acquireMulticastLock() { 425 if (mAdbMulticastLock == null) { 426 WifiManager wifiManager = (WifiManager) 427 mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 428 mAdbMulticastLock = wifiManager.createMulticastLock("AdbMulticastLock"); 429 } 430 431 if (!mAdbMulticastLock.isHeld()) { 432 mAdbMulticastLock.acquire(); 433 Slog.d(TAG, "Acquired multicast lock"); 434 } 435 } 436 releaseMulticastLock()437 private void releaseMulticastLock() { 438 if (mAdbMulticastLock != null && mAdbMulticastLock.isHeld()) { 439 mAdbMulticastLock.release(); 440 Slog.d(TAG, "Released multicast lock"); 441 } 442 } 443 setAdbEnabled(boolean enable, byte transportType)444 private void setAdbEnabled(boolean enable, byte transportType) { 445 Slog.d(TAG, "setAdbEnabled(" + enable + "), mIsAdbUsbEnabled=" + mIsAdbUsbEnabled 446 + ", mIsAdbWifiEnabled=" + mIsAdbWifiEnabled + ", transportType=" + transportType); 447 448 if (transportType == AdbTransportType.USB && enable != mIsAdbUsbEnabled) { 449 mIsAdbUsbEnabled = enable; 450 } else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) { 451 mIsAdbWifiEnabled = enable; 452 if (mIsAdbWifiEnabled) { 453 // Start adb over WiFi. 454 SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); 455 acquireMulticastLock(); 456 } else { 457 // Stop adb over WiFi. 458 SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"); 459 releaseMulticastLock(); 460 } 461 } else { 462 // No change 463 return; 464 } 465 466 if (enable) { 467 startAdbd(); 468 } else { 469 stopAdbd(); 470 } 471 472 for (IAdbTransport transport : mTransports.values()) { 473 try { 474 transport.onAdbEnabled(enable, transportType); 475 } catch (RemoteException e) { 476 Slog.w(TAG, "Unable to send onAdbEnabled to transport " + transport.toString()); 477 } 478 } 479 480 mDebuggingManager.setAdbEnabled(enable, transportType); 481 482 Slog.d(TAG, "Broadcasting enable = " + enable + ", type = " + transportType); 483 mCallbacks.broadcast((callback) -> { 484 Slog.d(TAG, "Sending enable = " + enable + ", type = " + transportType + " to " 485 + callback); 486 try { 487 callback.onDebuggingChanged(enable, transportType); 488 } catch (RemoteException ex) { 489 Slog.w(TAG, "Unable to send onDebuggingChanged:", ex); 490 } 491 }); 492 } 493 494 @Override handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args)495 public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, 496 ParcelFileDescriptor err, String[] args) { 497 return new AdbShellCommand(this).exec( 498 this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), 499 args); 500 } 501 502 @Override dump(FileDescriptor fd, PrintWriter writer, String[] args)503 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 504 if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return; 505 506 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 507 final long ident = Binder.clearCallingIdentity(); 508 try { 509 ArraySet<String> argsSet = new ArraySet<>(); 510 Collections.addAll(argsSet, args); 511 512 boolean dumpAsProto = false; 513 if (argsSet.contains("--proto")) { 514 dumpAsProto = true; 515 } 516 517 if (argsSet.size() == 0 || argsSet.contains("-a") || dumpAsProto) { 518 DualDumpOutputStream dump; 519 if (dumpAsProto) { 520 dump = new DualDumpOutputStream(new ProtoOutputStream(fd)); 521 } else { 522 pw.println("ADB MANAGER STATE (dumpsys adb):"); 523 524 dump = new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")); 525 } 526 527 mDebuggingManager.dump(dump, "debugging_manager", 528 AdbServiceDumpProto.DEBUGGING_MANAGER); 529 dump.flush(); 530 } else { 531 pw.println("Dump current ADB state"); 532 pw.println(" No commands available"); 533 } 534 } finally { 535 Binder.restoreCallingIdentity(ident); 536 } 537 } 538 } 539