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