欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 允许USB调试弹窗是怎么弹出来的

程序员文章站 2022-03-07 11:58:06
通过 adb 调试直接安装应用到真机上,简单方便。adb connect 192.168.1.1adb connect 192.168.1.1:5555 //指定端口为 5555在 AN 8.0 上,用上述命令adb调试真机时,首次连接会出现 “允许USB调试吗” 的弹窗在串口调试工具敲命令 dumpsys activity activities | grep mResumedActivity 得知,这个页面是 com.android.systemui/.usb.UsbDebugging...

通过 adb 调试直接安装应用到真机上,简单方便。

adb connect 192.168.1.1
adb connect 192.168.1.1:5555 //指定端口为 5555

在 AN 8.0 上,用上述命令adb调试真机时,首次连接会出现 “允许USB调试吗” 的弹窗,这个弹窗怎么出来的,源码一探究竟。
Android 允许USB调试弹窗是怎么弹出来的
在串口调试工具敲命令 dumpsys activity activities | grep mResumedActivity 得知,
这个页面是 com.android.systemui/.usb.UsbDebuggingActivity
源码路径

frameworks/base/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java

关注 onClick 方法,调用了 IUsbManagerallowUsbDebugging 方法。

@Override
    public void onClick(DialogInterface dialog, int which) {
        boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
        boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
        try {
            IBinder b = ServiceManager.getService(USB_SERVICE);
            IUsbManager service = IUsbManager.Stub.asInterface(b);
            if (allow) {
                service.allowUsbDebugging(alwaysAllow, mKey);
            } else {
                service.denyUsbDebugging();
            }
        } catch (Exception e) {
            Log.e(TAG, "Unable to notify Usb service", e);
        }
        finish();
    }

相关联的文件为:

frameworks/base/services/usb/java/com/android/server/usb/UsbService.java
frameworks/base/core/java/android/hardware/usb/IUsbManager.aidl
frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java
frameworks/base/services/usb/java/com/android/server/usb/UsbDebuggingManager.java

1 查看 UsbService.java ,实际调用的是 UsbDeviceManager.allowUsbDebugging(alwaysAllow, publicKey)

private UsbDeviceManager mDeviceManager;

@Override
    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
    }

2 查看 frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java ,实际调用 UsbDebuggingManager.allowUsbDebugging(boolean alwaysAllow, String publicKey)

private UsbDebuggingManager mDebuggingManager;

public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
        if (mDebuggingManager != null) {
            mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
        }
    }

3 查看 frameworks/base/services/usb/java/com/android/server/usb/UsbDebuggingManager.java ,发出了 MESSAGE_ADB_ALLOW 消息;

public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
        Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW);
        msg.arg1 = alwaysAllow ? 1 : 0;
        msg.obj = publicKey;
        mHandler.sendMessage(msg);
    }

UsbDebuggingHandler 内容如下,启动了 UsbDebuggingThread 以及 Handler 收发消息流程。

class UsbDebuggingHandler extends Handler {
        private static final int MESSAGE_ADB_ENABLED = 1;
        private static final int MESSAGE_ADB_DISABLED = 2;
        private static final int MESSAGE_ADB_ALLOW = 3;
        private static final int MESSAGE_ADB_DENY = 4;
        private static final int MESSAGE_ADB_CONFIRM = 5;
        private static final int MESSAGE_ADB_CLEAR = 6;

        public UsbDebuggingHandler(Looper looper) {
            super(looper);
        }

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_ADB_ENABLED:
                    if (mAdbEnabled)
                        break;

                    mAdbEnabled = true;

                    mThread = new UsbDebuggingThread();
                    mThread.start();

                    break;

                case MESSAGE_ADB_DISABLED:
                    if (!mAdbEnabled)
                        break;

                    mAdbEnabled = false;

                    if (mThread != null) {
                        mThread.stopListening();
                        mThread = null;
                    }

                    break;

                case MESSAGE_ADB_ALLOW: {
                    String key = (String)msg.obj;
                    String fingerprints = getFingerprints(key);

                    if (!fingerprints.equals(mFingerprints)) {
                        Slog.e(TAG, "Fingerprints do not match. Got "
                                + fingerprints + ", expected " + mFingerprints);
                        break;
                    }

                    if (msg.arg1 == 1) {
                        writeKey(key);
                    }

                    if (mThread != null) {
                        mThread.sendResponse("OK");
                    }
                    break;
                }

                case MESSAGE_ADB_DENY:
                    if (mThread != null) {
                        mThread.sendResponse("NO");
                    }
                    break;

                case MESSAGE_ADB_CONFIRM: {
                    if ("trigger_restart_min_framework".equals(
                            SystemProperties.get("vold.decrypt"))) {
                        Slog.d(TAG, "Deferring adb confirmation until after vold decrypt");
                        if (mThread != null) {
                            mThread.sendResponse("NO");
                        }
                        break;
                    }
                    String key = (String)msg.obj;
                    String fingerprints = getFingerprints(key);
                    if ("".equals(fingerprints)) {
                        if (mThread != null) {
                            mThread.sendResponse("NO");
                        }
                        break;
                    }
                    mFingerprints = fingerprints;
                    startConfirmation(key, mFingerprints);
                    break;
                }

                case MESSAGE_ADB_CLEAR:
                    deleteKeyFile();
                    break;
            }
        }
    }

其中 if (msg.arg1 == 1) { writeKey(key); } 就是如果勾选了 “一律允许这台计算机进行调试” ,则将对应的 key 保存到 data/misc/adb/adb_keys 文件里。

说到这里,弹窗的逻辑实现就知道了。
不对啊,还是没说弹窗怎么出来的。别急,继续。

UsbDebuggingManager.java 的 log 开关打开,

-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;

首次执行 adb connect 会出现如下 log :

07-06 16:34:58.167  1570  2615 D UsbDebuggingManager: Received public key: QAAAAGkQ5x8ngNhLRdKw3vO6i8jRUZeQzah1weiQuMq1z1sjaB8Otto2ISD66X+sxmjxIj4CpTqIlGJxsfmn74yylU0menZepnLE4031e5E4sOT/07MAW+JtVipMTS1JareqAv5PCVof1tTzS5iy2L4iudG7POBMki39r4OCUKmpOlmMdZQBhR1ADpcK/rystSgJm9mpbWv38UN4KcNS+x5w0sKx/bNp3yJ/oY1hLWnWbHJDL0KMVChr7+Fb7hc9VwOUS5G4V1YkNaa7LTM7PHGN6WknevqIp2SxCvkE5J6/1FbtBWk/HGrf3fuPKoQEQmKQdVzm+ysN0ErZ1L6JnKu6mtZofb6wVEAODhVMWrWY3YhFt/IHucDTWkCByXcmERmHpkcLtGk6w8nq+6COpfFkRoX2ZP4IZUyn8aqI5Mm4xf95RwK6vVwNhFsYzp8RctD2qVWq5nL5iCwqp9n2i4etShmjNH/VFIpaoP/H5YXP8bMBnYjPfTU9kUYn0kpRgHHQ8kkiXrLJ5XFwrKFAv0pSK9W0kDJFsaRvkLb2H3EebqJnZdWEeTq0haBAMjoesbUI0lmxtJ9zaE5rsbh/NWXs/SlFHMvY3wH99b7ZH8UqBc4bJGDQd4oi8gKeXHLh574EmGf9G6/I+eV2zKgknL+RJtnhyc8FvS+SV8Suh9o5PjF6OVA4pwEAAQA= @unknown

依据 Received public key 关键字找到 UsbDebuggingManager --> UsbDebuggingThread

class UsbDebuggingThread extends Thread {
        private boolean mStopped;
        private LocalSocket mSocket;
        private OutputStream mOutputStream;
        private InputStream mInputStream;

        UsbDebuggingThread() {
            super(TAG);
        }

        @Override
        public void run() {
            if (DEBUG) Slog.d(TAG, "Entering thread");
            while (true) {
                synchronized (this) {
                    if (mStopped) {
                        if (DEBUG) Slog.d(TAG, "Exiting thread");
                        return;
                    }
                    try {
                        openSocketLocked();
                    } catch (Exception e) {
                        /* Don't loop too fast if adbd dies, before init restarts it */
                        SystemClock.sleep(1000);
                    }
                }
                try {
                    listenToSocket();
                } catch (Exception e) {
                    /* Don't loop too fast if adbd dies, before init restarts it */
                    SystemClock.sleep(1000);
                }
            }
        }

        private void openSocketLocked() throws IOException {
            try {
                LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
                        LocalSocketAddress.Namespace.RESERVED);
                mInputStream = null;

                if (DEBUG) Slog.d(TAG, "Creating socket");
                mSocket = new LocalSocket();
                mSocket.connect(address);

                mOutputStream = mSocket.getOutputStream();
                mInputStream = mSocket.getInputStream();
            } catch (IOException ioe) {
                closeSocketLocked();
                throw ioe;
            }
        }

        private void listenToSocket() throws IOException {
            try {
                byte[] buffer = new byte[BUFFER_SIZE];
                while (true) {
                    int count = mInputStream.read(buffer);
                    if (count < 0) {
                        break;
                    }

                    if (buffer[0] == 'P' && buffer[1] == 'K') {
                        String key = new String(Arrays.copyOfRange(buffer, 2, count));
                        Slog.d(TAG, "Received public key: " + key);
                        Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
                        msg.obj = key;
                        mHandler.sendMessage(msg);
                    } else {
                        Slog.e(TAG, "Wrong message: "
                                + (new String(Arrays.copyOfRange(buffer, 0, 2))));
                        break;
                    }
                }
            } finally {
                synchronized (this) {
                    closeSocketLocked();
                }
            }
        }

        private void closeSocketLocked() {
            if (DEBUG) Slog.d(TAG, "Closing socket");
            try {
                if (mOutputStream != null) {
                    mOutputStream.close();
                    mOutputStream = null;
                }
            } catch (IOException e) {
                Slog.e(TAG, "Failed closing output stream: " + e);
            }

            try {
                if (mSocket != null) {
                    mSocket.close();
                    mSocket = null;
                }
            } catch (IOException ex) {
                Slog.e(TAG, "Failed closing socket: " + ex);
            }
        }

        /** Call to stop listening on the socket and exit the thread. */
        void stopListening() {
            synchronized (this) {
                mStopped = true;
                closeSocketLocked();
            }
        }

        void sendResponse(String msg) {
            synchronized (this) {
                if (!mStopped && mOutputStream != null) {
                    try {
                        mOutputStream.write(msg.getBytes());
                    }
                    catch (IOException ex) {
                        Slog.e(TAG, "Failed to write response:", ex);
                    }
                }
            }
        }
    }

代码流程为 UsbDebuggingThread 通过 openSocketLocked() 开启 Socket 连接并且监听 listenToSocket()
收到 adb connect 消息后,发出 msg UsbDebuggingHandler.MESSAGE_ADB_CONFIRM ,
查看 UsbDebuggingHandler 可知,调用了 startConfirmation(key, mFingerprints);

private void startConfirmation(String key, String fingerprints) {
        int currentUserId = ActivityManager.getCurrentUser();
        UserHandle userHandle =
                UserManager.get(mContext).getUserInfo(currentUserId).getUserHandle();
        String componentString;
        if (currentUserId == UserHandle.USER_OWNER) {
            componentString = Resources.getSystem().getString(
                    com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent);
        } else {
            // If the current foreground user is not the primary user we send a different
            // notification specific to secondary users.
            componentString = Resources.getSystem().getString(
                    R.string.config_customAdbPublicKeyConfirmationSecondaryUserComponent);
        }
        ComponentName componentName = ComponentName.unflattenFromString(componentString);
        if (startConfirmationActivity(componentName, userHandle, key, fingerprints)
                || startConfirmationService(componentName, userHandle, key, fingerprints)) {
            return;
        }
        Slog.e(TAG, "unable to start customAdbPublicKeyConfirmation[SecondaryUser]Component "
                + componentString + " as an Activity or a Service");
    }

	/**
     * @returns true if the componentName led to an Activity that was started.
     */
    private boolean startConfirmationActivity(ComponentName componentName, UserHandle userHandle,
            String key, String fingerprints) {
        PackageManager packageManager = mContext.getPackageManager();
        Intent intent = createConfirmationIntent(componentName, key, fingerprints);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
            try {
                mContext.startActivityAsUser(intent, userHandle);
                return true;
            } catch (ActivityNotFoundException e) {
                Slog.e(TAG, "unable to start adb whitelist activity: " + componentName, e);
            }
        }
        return false;
    }

其中,com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent
文件 frameworks/base/core/res/res/values/config.xml 中,值为

<!-- Name of the activity or service that prompts the user to reject, accept, or whitelist
         an adb host's public key, when an unwhitelisted host connects to the local adbd.
         Can be customized for other product types -->
    <string name="config_customAdbPublicKeyConfirmationComponent"
            >com.android.systemui/com.android.systemui.usb.UsbDebuggingActivity</string>

    <!-- Name of the activity that prompts the secondary user to acknowledge she/he needs to
         switch to the primary user to enable USB debugging.
         Can be customized for other product types -->
    <string name="config_customAdbPublicKeyConfirmationSecondaryUserComponent"
            >com.android.systemui/com.android.systemui.usb.UsbDebuggingSecondaryUserActivity</string>

这样就清楚了,最终根据包名信息 com.android.systemui/com.android.systemui.usb.UsbDebuggingActivity 打开了“允许USB调试吗” 页面。

总结如下:

1.开机后启动 UsbService ,UsbDebuggingThread 一直检测 adb 消息;
2.收到 adb connect 消息后,通过 UsbDebuggingHandler 调起 SystemUI 的 UsbDebuggingActivity 页面。

本文地址:https://blog.csdn.net/weixin_44021334/article/details/107161201