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