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