Android 11.0源码系列之IMSInputManagerService

Posted bubbleben

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 11.0源码系列之IMSInputManagerService相关的知识,希望对你有一定的参考价值。

本篇涉及到的主要代码:

frameworks\\base\\services\\core\\java\\com\\android\\server\\SystemServer.java

frameworks\\base\\services\\core\\java\\com\\android\\server\\wm\\WindowManagerService.java

frameworks\\base\\services\\core\\java\\com\\android\\server\\input\\InputManagerService.java

众所周知Android系统框架提供了众多的系统服务,比如管理四大组件的AMS(ActivityManagerService),管理窗口的WMS(WindowManagerService),管理应用安装, 卸载和更新的PMS(PackageManagerService),管理输入事件和输入设备的IMS(InputManagerService)等等,本系列将基于Android 11.0.0_r1代码,从上到下(java->jni->native)对这几大服务进行逐一解读,旨在加深对Android整个体系结构的理解,了解框架层各组件的运行原理,为以后深入性能分析/系统优化/架构设计等打下坚实的基础。

从功能上看,InputManagerService的责任相对来讲比较单一,根据注释Wraps the C++ InputManager and provides its callbacks可以看出其主要作用仅在于对native层InputManager的封装,以及为java层提供相应的回调;从代码行数来讲,AMS-20372行(部分代码解耦到ActivityTaskManagerService中,减少了AMS的代码量),PMS-25663行,WMS-8276行,IMS-2509行,其中IMS的代码量最少,相对来讲入手比较容易;从个人角度来讲,自己曾经在实际工作中遇到过不少input timeout类型的ANR问题,当时曾经基于Android 9.0阅读源码分析过原因,但是由于最近的两个Android大版本改动较大,而且时间久远并且未深入到native,所以本系列将从IMS入手一步步分析Java层InputManagerService和Native层InputManager的创建,Input事件(Motion/Key等)的读取和分发流程,Input超时触发ANR的原理等,希望通过本系列能够加深对框架的理解,在遇到更多疑难杂症时可以从更高的视野以及更多的角度来分析和解决问题。

1.1 InputManagerService的创建

同其他系统服务一样,InputManagerService也是在开机时由SystemServer创建并以"input"为名添加到ServiceManager中的,以下只截取与InputManagerService相关的部分代码;

[-> SystemServer.java]

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    InputManagerService inputManager = null;
    WindowManagerService wm = null;

    // 初始化InputManagerService对象[见1.2小节]
    inputManager = new InputManagerService(context);

    // WindowManagerService会持有InputManagerService的引用,所以InputManagerService要先初始化完成
    wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
            new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
    // 将名为"window"的系统服务添加到Binder大管家ServiceManager
    ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
            DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
    // 将名为"input"的系统服务添加到Binder大管家ServiceManager
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
            /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);  

    // 为InputManagerService设置WindowManagerCallbacks[见1.3小节]
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    // 调用InputManagerService的start()方法[见1.4小节]
    inputManager.start();

    // InputManagerService的准备工作已经基本完成,可以开始运行[见1.5小节]
    try {
        // TODO(BT) Pass parameter to input manager
        if (inputManagerF != null) {
            inputManagerF.systemRunning();
        }
    } catch (Throwable e) {
        reportWtf("Notifying InputManagerService running", e);
    }        
}
1.2 InputManagerService的初始化

[-> InputManagerService.java]

public InputManagerService(Context context) {
    this.mContext = context;
    // 运行在"android.display"线程并创建对应的Handler
    this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
    // InputManagerService构造函数主要就是调用native方法初始化出native层的NativeInputManager,并将其指针赋值给mPtr
    // 后面调用其他native方法时会用到它
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

    // 将InputManagerInternal添加到LocalServices中,方便SystemServer中的其他服务调用
    LocalServices.addService(InputManagerInternal.class, new LocalService());
}
1.3 InputManagerService的窗口回调

[-> WindowMangerService.java]

final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);

public InputManagerCallback getInputManagerCallback() {
    return mInputManagerCallback;
}

WindowManagerCallbacksInputManagerService内部的一个接口类,通过WindowManagerService.getInputManagerCallback()获取,即InputManagerCallback实现了WindowManagerCallbacks包括通知ANR,通知系统配置变更,通知焦点改变,拦截按键/触屏消息的分发等在内的所有接口方法;

[-> InputManagerService.java]

private WindowManagerCallbacks mWindowManagerCallbacks;

public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
    mWindowManagerCallbacks = callbacks;
}

// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
        String reason) {
    return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
            token, reason);
}

这里以notifyANR为例说明:真正触发input超时的逻辑在native层,它会调用Java层InputManagerService.notifyANR,而InputManagerService并不直接处理而是交由之前设置的WindowManagerServiceInputManagerCallback来处理,在后面关于input超时的文章中会详细介绍ANR从native层触发到弹出无响应对话框的整个过程,这里就不作展开。

1.4 InputManagerService的启动

[-> InputManagerService.java]

public void start() {
    // 通过nativeInit拿到的指针mPtr继续调用jni方法nativeStart,启动native层的InputReader和InputDispatcher两条线程
    nativeStart(mPtr);

    // InputManagerService实现了Watchdog.Monitor接口并重写了monitor()方法
    // WatchDog会定期调用monitor方法检查mInputFilterLock和mAssociationsLock这2把锁是否发生死锁
    // Add ourself to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this);

    // 通过ContentObserver监听SettingsProvider中input相关设置项的值
    registerPointerSpeedSettingObserver();
    registerShowTouchesSettingObserver();
    registerAccessibilityLargePointerSettingObserver();
    registerLongPressTimeoutObserver();

    // 监听用户切换的广播,并更新SettingsProvider中input相关设置项的值
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
            updateAccessibilityLargePointerFromSettings();
            updateDeepPressStatusFromSettings("user switched");
        }
    }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

    // InputManagerService创建时会主动触发一次input相关设置项的刷新
    updatePointerSpeedFromSettings();
    updateShowTouchesFromSettings();
    updateAccessibilityLargePointerFromSettings();
    updateDeepPressStatusFromSettings("just booted");
}
1.5 InputManagerService的运行

[-> InputManagerService.java]

public void systemRunning() {
    // 监听安装包移除/更新/替换的广播, 并在接收到广播时更新键盘布局
    IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
    filter.addDataScheme("package");
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateKeyboardLayouts();
        }
    }, filter, null, mHandler);

    // 监听远程蓝牙设备别名改变的广播, 并在收到广播时重新加载所有远程设备的别名
    filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            reloadDeviceAliases();
        }
    }, filter, null, mHandler);
    
    // 往android.display线程发送消息重新加载设备别名和更新键盘布局
    mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
    mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
}
总结

本篇主要介绍java层InputManagerService的创建,可以看出它是对native层InputManager的封装,其主要工作都是由native层来完成,通过native层的回调对外提供包括通知ANR,通知系统配置变更,通知焦点改变,拦截按键/触屏消息等在内的一些功能,下一篇我们会详细分析native层InputManager的创建以及其工作流程。

以上是关于Android 11.0源码系列之IMSInputManagerService的主要内容,如果未能解决你的问题,请参考以下文章

Android 11.0源码系列之PMSinstalld

Android 11.0源码系列之IMSInputManagerService

Android 11.0源码系列之IMSInputManager

Android 11.0源码系列之IMSInputDispatcher

Android 11.0源码系列之PMSPackageManagerService的创建

Android 11.0源码系列之IMSInputReader