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