14e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby/*
24e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * Copyright (C) 2012 The Android Open Source Project
34e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby *
44e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * Licensed under the Apache License, Version 2.0 (the "License");
54e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * you may not use this file except in compliance with the License.
64e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * You may obtain a copy of the License at
74e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby *
84e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby *      http://www.apache.org/licenses/LICENSE-2.0
94e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby *
104e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * Unless required by applicable law or agreed to in writing, software
114e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * distributed under the License is distributed on an "AS IS" BASIS,
124e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * See the License for the specific language governing permissions an
144e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby * limitations under the License.
154e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby */
164e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
174e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobypackage com.android.server.usb;
184e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
194e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.content.ActivityNotFoundException;
204e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.content.Context;
214e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.content.Intent;
224e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.net.LocalSocket;
234e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.net.LocalSocketAddress;
244e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.os.Handler;
254e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.os.Environment;
264e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.os.FileUtils;
274e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.os.Looper;
284e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.os.Message;
294e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.os.SystemClock;
304e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.util.Slog;
314e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport android.util.Base64;
328d044e8bc287c1a567d82aedbe30085b011544c3Dianne Hackbornimport com.android.server.FgThread;
334e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
344e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.lang.Thread;
354e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.File;
364e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.FileDescriptor;
374e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.FileOutputStream;
384e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.IOException;
394e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.InputStream;
404e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.OutputStream;
414e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.io.PrintWriter;
424e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.security.MessageDigest;
434e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobyimport java.util.Arrays;
444e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
454e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Gobypublic class UsbDebuggingManager implements Runnable {
464e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private static final String TAG = "UsbDebuggingManager";
474e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private static final boolean DEBUG = false;
484e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
494e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private final String ADBD_SOCKET = "adbd";
504e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private final String ADB_DIRECTORY = "misc/adb";
514e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private final String ADB_KEYS_FILE = "adb_keys";
524e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private final int BUFFER_SIZE = 4096;
534e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
544e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private final Context mContext;
554e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private final Handler mHandler;
56509bf2d2cf60201149b4e7711bbcdede8b744791Benoit Goby    private Thread mThread;
574e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private boolean mAdbEnabled = false;
584e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private String mFingerprints;
594e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private LocalSocket mSocket = null;
604e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private OutputStream mOutputStream = null;
614e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
624e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    public UsbDebuggingManager(Context context) {
638d044e8bc287c1a567d82aedbe30085b011544c3Dianne Hackborn        mHandler = new UsbDebuggingHandler(FgThread.get().getLooper());
644e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        mContext = context;
654e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
664e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
674e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private void listenToSocket() throws IOException {
684e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
694e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            byte[] buffer = new byte[BUFFER_SIZE];
704e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
714e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                                         LocalSocketAddress.Namespace.RESERVED);
724e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            InputStream inputStream = null;
734e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
744e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            mSocket = new LocalSocket();
754e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            mSocket.connect(address);
764e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
774e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            mOutputStream = mSocket.getOutputStream();
784e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            inputStream = mSocket.getInputStream();
794e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
804e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            while (true) {
814e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                int count = inputStream.read(buffer);
824e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                if (count < 0) {
834e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    Slog.e(TAG, "got " + count + " reading");
844e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    break;
854e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                }
864e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
874e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                if (buffer[0] == 'P' && buffer[1] == 'K') {
884e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    String key = new String(Arrays.copyOfRange(buffer, 2, count));
894e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    Slog.d(TAG, "Received public key: " + key);
904e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
914e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    msg.obj = key;
924e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mHandler.sendMessage(msg);
934e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                }
944e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                else {
954e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2))));
964e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    break;
974e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                }
984e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            }
994e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (IOException ex) {
1004e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "Communication error: ", ex);
1014e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            throw ex;
1024e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } finally {
1034e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            closeSocket();
1044e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
1054e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
1064e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1074e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    @Override
1084e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    public void run() {
1094e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        while (mAdbEnabled) {
1104e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            try {
1114e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                listenToSocket();
1124e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            } catch (Exception e) {
1134e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                /* Don't loop too fast if adbd dies, before init restarts it */
1144e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                SystemClock.sleep(1000);
1154e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            }
1164e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
1174e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
1184e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1194e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private void closeSocket() {
1204e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
1214e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            mOutputStream.close();
1224e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (IOException e) {
1234e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "Failed closing output stream: " + e);
1244e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
1254e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1264e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
1274e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            mSocket.close();
1284e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (IOException ex) {
1294e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "Failed closing socket: " + ex);
1304e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
1314e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
1324e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1334e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private void sendResponse(String msg) {
1344e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        if (mOutputStream != null) {
1354e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            try {
1364e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                mOutputStream.write(msg.getBytes());
1374e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            }
1384e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            catch (IOException ex) {
1394e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                Slog.e(TAG, "Failed to write response:", ex);
1404e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            }
1414e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
1424e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
1434e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1444e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    class UsbDebuggingHandler extends Handler {
1454e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        private static final int MESSAGE_ADB_ENABLED = 1;
1464e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        private static final int MESSAGE_ADB_DISABLED = 2;
1474e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        private static final int MESSAGE_ADB_ALLOW = 3;
1484e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        private static final int MESSAGE_ADB_DENY = 4;
1494e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        private static final int MESSAGE_ADB_CONFIRM = 5;
150cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby        private static final int MESSAGE_ADB_CLEAR = 6;
1514e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1524e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        public UsbDebuggingHandler(Looper looper) {
1534e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            super(looper);
1544e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
1554e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1564e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        public void handleMessage(Message msg) {
1574e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            switch (msg.what) {
1584e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                case MESSAGE_ADB_ENABLED:
1594e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    if (mAdbEnabled)
1604e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                        break;
1614e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1624e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mAdbEnabled = true;
1634e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
164efa92b2182ab581873aa8e75d596e2e363bd5e6dDianne Hackborn                    mThread = new Thread(UsbDebuggingManager.this, TAG);
1654e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mThread.start();
1664e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1674e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    break;
1684e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1694e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                case MESSAGE_ADB_DISABLED:
1704e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    if (!mAdbEnabled)
1714e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                        break;
1724e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1734e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mAdbEnabled = false;
1744e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    closeSocket();
1754e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1764e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    try {
1774e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                        mThread.join();
1784e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    } catch (Exception ex) {
1794e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    }
1804e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
181509bf2d2cf60201149b4e7711bbcdede8b744791Benoit Goby                    mThread = null;
1824e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mOutputStream = null;
1834e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mSocket = null;
18437ce5c5d5e8216f02230aeb89b147c0395e18329Benoit Goby                    break;
1854e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1864e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                case MESSAGE_ADB_ALLOW: {
1874e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    String key = (String)msg.obj;
1884e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    String fingerprints = getFingerprints(key);
1894e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1904e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    if (!fingerprints.equals(mFingerprints)) {
1914e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                        Slog.e(TAG, "Fingerprints do not match. Got "
1924e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                                + fingerprints + ", expected " + mFingerprints);
1934e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                        break;
1944e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    }
1954e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
1964e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    if (msg.arg1 == 1) {
1974e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                        writeKey(key);
1984e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    }
1994e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2004e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    sendResponse("OK");
2014e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    break;
2024e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                }
2034e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2044e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                case MESSAGE_ADB_DENY:
2054e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    sendResponse("NO");
2064e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    break;
2074e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2084e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                case MESSAGE_ADB_CONFIRM: {
2094e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    String key = (String)msg.obj;
2104e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    mFingerprints = getFingerprints(key);
2114e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    showConfirmationDialog(key, mFingerprints);
2124e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    break;
2134e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                }
214cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby
215cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby                case MESSAGE_ADB_CLEAR:
216cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby                    deleteKeyFile();
217cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby                    break;
2184e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            }
2194e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2204e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
2214e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2224e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private String getFingerprints(String key) {
2234e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        String hex = "0123456789ABCDEF";
2244e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        StringBuilder sb = new StringBuilder();
2254e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        MessageDigest digester;
2264e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2274e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
2284e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            digester = MessageDigest.getInstance("MD5");
2294e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (Exception ex) {
2304e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "Error getting digester: " + ex);
2314e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            return "";
2324e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2334e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2344e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        byte[] base64_data = key.split("\\s+")[0].getBytes();
2354e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
2364e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2374e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        for (int i = 0; i < digest.length; i++) {
2384e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            sb.append(hex.charAt((digest[i] >> 4) & 0xf));
2394e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            sb.append(hex.charAt(digest[i] & 0xf));
2404e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            if (i < digest.length - 1)
2414e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                sb.append(":");
2424e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2434e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        return sb.toString();
2444e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
2454e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2464e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    private void showConfirmationDialog(String key, String fingerprints) {
2474e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        Intent dialogIntent = new Intent();
2484e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2494e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        dialogIntent.setClassName("com.android.systemui",
2504e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                "com.android.systemui.usb.UsbDebuggingActivity");
2514e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2524e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        dialogIntent.putExtra("key", key);
2534e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        dialogIntent.putExtra("fingerprints", fingerprints);
2544e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
2554e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            mContext.startActivity(dialogIntent);
2564e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (ActivityNotFoundException e) {
2574e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "unable to start UsbDebuggingActivity");
2584e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2594e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
2604e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
261cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    private File getUserKeyFile() {
2624e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        File dataDir = Environment.getDataDirectory();
2634e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        File adbDir = new File(dataDir, ADB_DIRECTORY);
2644e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2654e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        if (!adbDir.exists()) {
2664e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "ADB data directory does not exist");
267cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby            return null;
2684e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2694e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
270cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby        return new File(adbDir, ADB_KEYS_FILE);
271cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    }
272cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby
273cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    private void writeKey(String key) {
2744e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
275cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby            File keyFile = getUserKeyFile();
276cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby
277cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby            if (keyFile == null) {
278cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby                return;
279cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby            }
2804e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2814e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            if (!keyFile.exists()) {
2824e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                keyFile.createNewFile();
2834e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                FileUtils.setPermissions(keyFile.toString(),
2844e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    FileUtils.S_IRUSR | FileUtils.S_IWUSR |
2854e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                    FileUtils.S_IRGRP, -1, -1);
2864e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            }
2874e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
2884e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            FileOutputStream fo = new FileOutputStream(keyFile, true);
2894e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            fo.write(key.getBytes());
2904e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            fo.write('\n');
2914e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            fo.close();
2924e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2934e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        catch (IOException ex) {
2944e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            Slog.e(TAG, "Error writing key:" + ex);
2954e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
2964e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
2974e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
298cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    private void deleteKeyFile() {
299cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby        File keyFile = getUserKeyFile();
300cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby        if (keyFile != null) {
301cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby            keyFile.delete();
302cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby        }
303cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    }
3044e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
3054e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    public void setAdbEnabled(boolean enabled) {
3064e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        mHandler.sendEmptyMessage(enabled ? UsbDebuggingHandler.MESSAGE_ADB_ENABLED
3074e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby                                          : UsbDebuggingHandler.MESSAGE_ADB_DISABLED);
3084e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
3094e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
3104e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
3114e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW);
3124e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        msg.arg1 = alwaysAllow ? 1 : 0;
3134e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        msg.obj = publicKey;
3144e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        mHandler.sendMessage(msg);
3154e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
3164e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
3174e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    public void denyUsbDebugging() {
3184e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_DENY);
3194e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
3204e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
321cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    public void clearUsbDebuggingKeys() {
322cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby        mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_CLEAR);
323cd7a17c645761ac0b64c75346b159dd30cbcb01cBenoit Goby    }
3244e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby
3254e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    public void dump(FileDescriptor fd, PrintWriter pw) {
3264e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        pw.println("  USB Debugging State:");
3274e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        pw.println("    Connected to adbd: " + (mOutputStream != null));
3284e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        pw.println("    Last key received: " + mFingerprints);
3294e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        pw.println("    User keys:");
3304e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
3314e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
3324e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (IOException e) {
3334e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            pw.println("IOException: " + e);
3344e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
3354e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        pw.println("    System keys:");
3364e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        try {
3374e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null));
3384e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        } catch (IOException e) {
3394e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby            pw.println("IOException: " + e);
3404e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby        }
3414e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby    }
3424e68bd420b6cfdbeadb5e69aa6448665b2da762bBenoit Goby}
343