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