Android 12.0源码系列之IMS(一)InputManagerService

Android 12.0源码系列之IMS(一)InputManagerService

本篇涉及到的主要代码:

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 12.0.0_r3源码对系统框架服务的重点流程进行解读,旨在加深对Android体系结构的理解,了解框架层运行原理,进而深入研究系统性能分析/系统优化/架构设计。

从功能上看,InputManagerService的责任相对来讲比较单一,根据注释Wraps the C++ InputManager and provides its callbacks可以看出其主要作用在于对nativeInputManager的封装以及为java层提供回调;从代码行数来讲,ActivityManagerService-17212行(Android P为27245行,从Android Q开始解耦出ActivityTaskManagerService后减少了代码量),PackageManagerService-28946行,WindowManagerService-8613行,InputManagerService-3479行,其中InputManagerService的代码量最少,相对来讲入手比较容易,所以本系列将从InputManagerService入手一步步分析JavaInputManagerServiceNativeInputManager的创建,Input事件(Motion/Key等)的读取和分发流程,Input超时触发ANR的原理等,希望通过本系列的总结能够加深对框架的理解,遇到更多疑难杂症时可以站在更高的视野,从更多的角度来分析和解决问题。

1. SystemServer.startOtherServices

同其他系统服务一样,InputManagerService也是在开机时由SystemServer创建并以input为别名添加到ServiceManager中进行管理,鉴于篇幅限制仅列出与主要业务相关的代码(后面的系列和章节亦如此);

[-> SystemServer.java]

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

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

    // WindowManagerService依赖InputManagerService的创建
    wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
            new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
    // 将名为"window"的系统服务添加到ServiceManager进行管理
    ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
            DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
    // 将名为"input"的系统服务添加到ServiceManager进行管理
    ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
            /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);  

    // 为InputManagerService注册WindowManagerCallbacks[见第3小节]
    inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
    // 执行InputManagerService的start()方法[见第4小节]
    inputManager.start();

    try {
        // 为InputManagerService设置无线耳机设备变化的监听
        inputManager.setWiredAccessoryCallbacks(
                new WiredAccessoryManager(context, inputManager));
    } catch (Throwable e) {
        reportWtf("starting WiredAccessoryManager", e);
    }

    final InputManagerService inputManagerF = inputManager;
    mActivityManagerService.systemReady(() -> {
        Slog.i(TAG, "Making services ready");
        t.traceBegin("StartActivityManagerReadyPhase");
        mSystemServiceManager.startBootPhase(t, SystemService.PHASE_ACTIVITY_MANAGER_READY);
        t.traceEnd();
        // ActivityManagerService执行完systemReady之后,调用InputManagerService.systemRunning()
        try {
            if (inputManagerF != null) {
                // InputManagerService的准备工作已经基本完成,可以开始运行[见第5小节]        
                inputManagerF.systemRunning();
            }
        } catch (Throwable e) {
            reportWtf("Notifying InputManagerService running", e);
        }
    }
}

2. InputManagerService.constructor

[-> InputManagerService.java]

/*
 * Wraps the C++ InputManager and provides its callbacks.
 */
public class InputManagerService extends IInputManager.Stub
        implements Watchdog.Monitor {
    static final String TAG = "InputManager";

    // Pointer to native input manager service object.
    private final long mPtr;

    private final Context mContext;
    private final InputManagerHandler mHandler;

    // native方法
    private static native long nativeInit(InputManagerService service,
            Context context, MessageQueue messageQueue);

    public InputManagerService(Context context) {
        // system context
        this.mContext = context;
        // InputManagerHandler绑定android.display线程, 主要用于处理输入设备变化,键盘布局变化等事件
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
        // 调用native方法初始化NativeInputManager, 并保存返回的指针, 我们在下一章会进行详细介绍
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

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

    private final class LocalService extends InputManagerInternal {
        @Override
        public boolean injectInputEvent(InputEvent event, int mode) {
            return injectInputEventInternal(event, mode);
        }
    }
}

DisplayThread是一个主要处理显示任务的单例线程,对时延的要求很高,所以优先级高于后台线程(THREAD_PRIORITY_BACKGROUND)和前台线程(THREAD_PRIORITY_FOREGROUND),基本只用于DisplayManagerServiceWindowManagerServiceInputManagerService

InputManagerInternal是一个抽象类并声明了一些接口,InputManagerService的内部类LocalService继承并实现了这些接口,用于system_server进程内部其他服务调用InputManagerService

3. InputManagerService.setWindowManagerCallbacks

[-> WindowMangerService.java]

final InputManagerCallback mInputManagerCallback = new InputManagerCallback(this);

public InputManagerCallback getInputManagerCallback() {
    return mInputManagerCallback;
}

WindowManagerCallbacksInputManagerService内部定义的一个接口类,用于WindowManagerServiceInputManagerService之间的交互,由InputManagerCallback实现包括通知ANR,通知系统配置变更,通知焦点改变,拦截按键/触屏消息的分发等在内的接口功能,可以通过WindowManagerService.getInputManagerCallback()获取;

[-> InputManagerService.java]

// WindowManagerService策略类,由PhoneWindowManager实现
WindowManagerPolicy mPolicy;

private WindowManagerCallbacks mWindowManagerCallbacks;

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

// Native callback.
private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
    return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
}

[-> InputManagerCallback.java]

@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}

这里以interceptKeyBeforeDispatching为例说明:native层在分发按键消息时会调用Java层此方法,而InputManagerService并不直接处理而是交由之前设置的InputManagerCallback来处理,它又会将此事件交由WindowManagerService的策略类PhoneWindowManager进行专门处理。

4. InputManagerService.start

[-> InputManagerService.java]

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

    // InputManagerService实现了Watchdog.Monitor接口并重写了monitor()方法
    // WatchDog会定期调用monitor方法检查系统服务是否发生死锁
    Watchdog.getInstance().addMonitor(this);

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

    // 由于每个用户可以有自己的设置, 所以需要监听用户切换的广播,并更新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");
    updateMaximumObscuringOpacityForTouchFromSettings();
    // 获取屏蔽不受任务的触摸事件的设置项,并将其设置到InputDispatcher用于拦截触摸事件的上报
    updateBlockUntrustedTouchesModeFromSettings();    
}

这里继续通过nativeStart创建InputDispatcherInputReader,增加Watchdog的监听和SettingsProvider的更新和监听,相比较Android 11.0增加了屏蔽不受信任的触摸事件这一新特性(https://developer.android.google.cn/about/versions/12/behavior-changes-all#untrusted-touch-events);

// State for the currently installed input filter.
final Object mInputFilterLock = new Object();
private final Object mAssociationsLock = new Object();
private final Object mLidSwitchLock = new Object();

@Override
public void monitor() {
    synchronized (mInputFilterLock) { }
    synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
    synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
    nativeMonitor(mPtr);
}

Watchdog会定时监听mInputFilterLockmAssociationsLockmLidSwitchLock这三个对象是否发生死锁,同时通过nativeMonitor监听nativeInputDispatcherInputReader是否发生死锁;

5. InputManagerService.systemRunning

[-> 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);

    // 通知WiredAccessoryManager.systemReady
    if (mWiredAccessoryCallbacks != null) {
        mWiredAccessoryCallbacks.systemReady();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值