• 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 an
14  * limitations under the License.
15  */
16 
17 package com.android.server.usb;
18 
19 import android.content.ActivityNotFoundException;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.net.LocalSocket;
23 import android.net.LocalSocketAddress;
24 import android.os.Handler;
25 import android.os.Environment;
26 import android.os.FileUtils;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.os.SystemClock;
30 import android.util.Slog;
31 import android.util.Base64;
32 import com.android.server.FgThread;
33 
34 import java.lang.Thread;
35 import java.io.File;
36 import java.io.FileDescriptor;
37 import java.io.FileOutputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.OutputStream;
41 import java.io.PrintWriter;
42 import java.security.MessageDigest;
43 import java.util.Arrays;
44 
45 public class UsbDebuggingManager implements Runnable {
46     private static final String TAG = "UsbDebuggingManager";
47     private static final boolean DEBUG = false;
48 
49     private final String ADBD_SOCKET = "adbd";
50     private final String ADB_DIRECTORY = "misc/adb";
51     private final String ADB_KEYS_FILE = "adb_keys";
52     private final int BUFFER_SIZE = 4096;
53 
54     private final Context mContext;
55     private final Handler mHandler;
56     private Thread mThread;
57     private boolean mAdbEnabled = false;
58     private String mFingerprints;
59     private LocalSocket mSocket = null;
60     private OutputStream mOutputStream = null;
61 
UsbDebuggingManager(Context context)62     public UsbDebuggingManager(Context context) {
63         mHandler = new UsbDebuggingHandler(FgThread.get().getLooper());
64         mContext = context;
65     }
66 
listenToSocket()67     private void listenToSocket() throws IOException {
68         try {
69             byte[] buffer = new byte[BUFFER_SIZE];
70             LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
71                                          LocalSocketAddress.Namespace.RESERVED);
72             InputStream inputStream = null;
73 
74             mSocket = new LocalSocket();
75             mSocket.connect(address);
76 
77             mOutputStream = mSocket.getOutputStream();
78             inputStream = mSocket.getInputStream();
79 
80             while (true) {
81                 int count = inputStream.read(buffer);
82                 if (count < 0) {
83                     Slog.e(TAG, "got " + count + " reading");
84                     break;
85                 }
86 
87                 if (buffer[0] == 'P' && buffer[1] == 'K') {
88                     String key = new String(Arrays.copyOfRange(buffer, 2, count));
89                     Slog.d(TAG, "Received public key: " + key);
90                     Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
91                     msg.obj = key;
92                     mHandler.sendMessage(msg);
93                 }
94                 else {
95                     Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2))));
96                     break;
97                 }
98             }
99         } catch (IOException ex) {
100             Slog.e(TAG, "Communication error: ", ex);
101             throw ex;
102         } finally {
103             closeSocket();
104         }
105     }
106 
107     @Override
run()108     public void run() {
109         while (mAdbEnabled) {
110             try {
111                 listenToSocket();
112             } catch (Exception e) {
113                 /* Don't loop too fast if adbd dies, before init restarts it */
114                 SystemClock.sleep(1000);
115             }
116         }
117     }
118 
closeSocket()119     private void closeSocket() {
120         try {
121             mOutputStream.close();
122         } catch (IOException e) {
123             Slog.e(TAG, "Failed closing output stream: " + e);
124         }
125 
126         try {
127             mSocket.close();
128         } catch (IOException ex) {
129             Slog.e(TAG, "Failed closing socket: " + ex);
130         }
131     }
132 
sendResponse(String msg)133     private void sendResponse(String msg) {
134         if (mOutputStream != null) {
135             try {
136                 mOutputStream.write(msg.getBytes());
137             }
138             catch (IOException ex) {
139                 Slog.e(TAG, "Failed to write response:", ex);
140             }
141         }
142     }
143 
144     class UsbDebuggingHandler extends Handler {
145         private static final int MESSAGE_ADB_ENABLED = 1;
146         private static final int MESSAGE_ADB_DISABLED = 2;
147         private static final int MESSAGE_ADB_ALLOW = 3;
148         private static final int MESSAGE_ADB_DENY = 4;
149         private static final int MESSAGE_ADB_CONFIRM = 5;
150         private static final int MESSAGE_ADB_CLEAR = 6;
151 
UsbDebuggingHandler(Looper looper)152         public UsbDebuggingHandler(Looper looper) {
153             super(looper);
154         }
155 
handleMessage(Message msg)156         public void handleMessage(Message msg) {
157             switch (msg.what) {
158                 case MESSAGE_ADB_ENABLED:
159                     if (mAdbEnabled)
160                         break;
161 
162                     mAdbEnabled = true;
163 
164                     mThread = new Thread(UsbDebuggingManager.this, TAG);
165                     mThread.start();
166 
167                     break;
168 
169                 case MESSAGE_ADB_DISABLED:
170                     if (!mAdbEnabled)
171                         break;
172 
173                     mAdbEnabled = false;
174                     closeSocket();
175 
176                     try {
177                         mThread.join();
178                     } catch (Exception ex) {
179                     }
180 
181                     mThread = null;
182                     mOutputStream = null;
183                     mSocket = null;
184                     break;
185 
186                 case MESSAGE_ADB_ALLOW: {
187                     String key = (String)msg.obj;
188                     String fingerprints = getFingerprints(key);
189 
190                     if (!fingerprints.equals(mFingerprints)) {
191                         Slog.e(TAG, "Fingerprints do not match. Got "
192                                 + fingerprints + ", expected " + mFingerprints);
193                         break;
194                     }
195 
196                     if (msg.arg1 == 1) {
197                         writeKey(key);
198                     }
199 
200                     sendResponse("OK");
201                     break;
202                 }
203 
204                 case MESSAGE_ADB_DENY:
205                     sendResponse("NO");
206                     break;
207 
208                 case MESSAGE_ADB_CONFIRM: {
209                     String key = (String)msg.obj;
210                     mFingerprints = getFingerprints(key);
211                     showConfirmationDialog(key, mFingerprints);
212                     break;
213                 }
214 
215                 case MESSAGE_ADB_CLEAR:
216                     deleteKeyFile();
217                     break;
218             }
219         }
220     }
221 
getFingerprints(String key)222     private String getFingerprints(String key) {
223         String hex = "0123456789ABCDEF";
224         StringBuilder sb = new StringBuilder();
225         MessageDigest digester;
226 
227         try {
228             digester = MessageDigest.getInstance("MD5");
229         } catch (Exception ex) {
230             Slog.e(TAG, "Error getting digester: " + ex);
231             return "";
232         }
233 
234         byte[] base64_data = key.split("\\s+")[0].getBytes();
235         byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
236 
237         for (int i = 0; i < digest.length; i++) {
238             sb.append(hex.charAt((digest[i] >> 4) & 0xf));
239             sb.append(hex.charAt(digest[i] & 0xf));
240             if (i < digest.length - 1)
241                 sb.append(":");
242         }
243         return sb.toString();
244     }
245 
showConfirmationDialog(String key, String fingerprints)246     private void showConfirmationDialog(String key, String fingerprints) {
247         Intent dialogIntent = new Intent();
248 
249         dialogIntent.setClassName("com.android.systemui",
250                 "com.android.systemui.usb.UsbDebuggingActivity");
251         dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
252         dialogIntent.putExtra("key", key);
253         dialogIntent.putExtra("fingerprints", fingerprints);
254         try {
255             mContext.startActivity(dialogIntent);
256         } catch (ActivityNotFoundException e) {
257             Slog.e(TAG, "unable to start UsbDebuggingActivity");
258         }
259     }
260 
getUserKeyFile()261     private File getUserKeyFile() {
262         File dataDir = Environment.getDataDirectory();
263         File adbDir = new File(dataDir, ADB_DIRECTORY);
264 
265         if (!adbDir.exists()) {
266             Slog.e(TAG, "ADB data directory does not exist");
267             return null;
268         }
269 
270         return new File(adbDir, ADB_KEYS_FILE);
271     }
272 
writeKey(String key)273     private void writeKey(String key) {
274         try {
275             File keyFile = getUserKeyFile();
276 
277             if (keyFile == null) {
278                 return;
279             }
280 
281             if (!keyFile.exists()) {
282                 keyFile.createNewFile();
283                 FileUtils.setPermissions(keyFile.toString(),
284                     FileUtils.S_IRUSR | FileUtils.S_IWUSR |
285                     FileUtils.S_IRGRP, -1, -1);
286             }
287 
288             FileOutputStream fo = new FileOutputStream(keyFile, true);
289             fo.write(key.getBytes());
290             fo.write('\n');
291             fo.close();
292         }
293         catch (IOException ex) {
294             Slog.e(TAG, "Error writing key:" + ex);
295         }
296     }
297 
deleteKeyFile()298     private void deleteKeyFile() {
299         File keyFile = getUserKeyFile();
300         if (keyFile != null) {
301             keyFile.delete();
302         }
303     }
304 
setAdbEnabled(boolean enabled)305     public void setAdbEnabled(boolean enabled) {
306         mHandler.sendEmptyMessage(enabled ? UsbDebuggingHandler.MESSAGE_ADB_ENABLED
307                                           : UsbDebuggingHandler.MESSAGE_ADB_DISABLED);
308     }
309 
allowUsbDebugging(boolean alwaysAllow, String publicKey)310     public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
311         Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW);
312         msg.arg1 = alwaysAllow ? 1 : 0;
313         msg.obj = publicKey;
314         mHandler.sendMessage(msg);
315     }
316 
denyUsbDebugging()317     public void denyUsbDebugging() {
318         mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_DENY);
319     }
320 
clearUsbDebuggingKeys()321     public void clearUsbDebuggingKeys() {
322         mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_CLEAR);
323     }
324 
dump(FileDescriptor fd, PrintWriter pw)325     public void dump(FileDescriptor fd, PrintWriter pw) {
326         pw.println("  USB Debugging State:");
327         pw.println("    Connected to adbd: " + (mOutputStream != null));
328         pw.println("    Last key received: " + mFingerprints);
329         pw.println("    User keys:");
330         try {
331             pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
332         } catch (IOException e) {
333             pw.println("IOException: " + e);
334         }
335         pw.println("    System keys:");
336         try {
337             pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null));
338         } catch (IOException e) {
339             pw.println("IOException: " + e);
340         }
341     }
342 }
343