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