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