• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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