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

53 篇文章 2 订阅

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

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

在 AN 8.0 上,用上述命令adb调试真机时,首次连接会出现 “允许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 页面。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值