Android 源码 InputManagerService 初始化

InputManagerService 是在 SystemServer 中启动的。它包装了 C++ InputManager 并提供其回调。它分为 Java 层和 Native 层两部分。Java 层负责与 WindowManagerService 的通信。而 Native 层则是 InputReader 和 InputDispatcher 两个输入系统关键组件的运行容器。

InputManagerService 在 startOtherServices() 方法中启动,先创建 InputManagerService 对象,接着创建了 WindowManagerService 对象,创建 WindowManagerService 对象时传入了 InputManagerService 对象的引用,而 InputManagerService 对象调用了 setWindowManagerCallbacks 和 WindowManagerService 建立了联系。其中 ActivityManagerService 对象也调用了 setWindowManager 传入了 WindowManagerService 对象的引用从而建立了联系。最后调用 InputManagerService start 方法启动它。

frameworks/base/services/java/com/android/server/SystemServer.java

public final class SystemServer {
    ......
    public static void main(String[] args) {
        new SystemServer().run();
    }
    ......
    private void run() {
        ......
        try {
            ......
            startOtherServices();
        } catch (Throwable ex) {
            ......
        }
        ......
    }
    ......
    private void startOtherServices() {
        ......
        WindowManagerService wm = null;
        ......
        InputManagerService inputManager = null;
        ......
        try {
            ......
            Slog.i(TAG, "Input Manager");
            // 1. 创建 InputManagerService 对象
            inputManager = new InputManagerService(context);
            
            Slog.i(TAG, "Window Manager");
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
            
            mActivityManagerService.setWindowManager(wm);

            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
            // 2.启动 InputManagerService
            inputManager.start();
            ......
        } catch (RuntimeException e) {
            ......
        }
    }
    ......
}

创建 InputManagerService 对象的时候,传入了参数 context,它代表 SystemServer 上下文。接着创建 InputManagerHandler 对象,通过这个 Handler 可以向 DisplayThread 线程发送消息。然后调用 nativeInit 完成 native 初始化。

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

public class InputManagerService extends IInputManager.Stub
        implements Watchdog.Monitor {
    ......
    public InputManagerService(Context context) {
        this.mContext = context;
        // 1.创建 InputManagerHandler Handler 类型对象,注意 Looper 是从 DisplayThread 获取的。
        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
        // 是否将 dev/input/event 或 uevent 子系统用于音频插孔。
        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        // 2.native 初始化,返回指向本地输入管理器服务对象的指针。
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

        LocalServices.addService(InputManagerInternal.class, new LocalService());
    }   
    ......
}

nativeInit 方法中首先将传递来的 messageQueueObj java 对象转化为 native MessageQueue 对象。接着创建了 NativeInputManager 对象。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

下面是 NativeInputManager 构造函数完成的主要工作:

1.将 contextObj 和 serviceObj 提升为 jni 全局变量;

2.Locked 结构体赋值;

3.创建 EventHub 对象——需要重点关注!

4.InputManager 对象创建。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();
    // 将 contextObj 和 serviceObj 提升为 jni 全局变量
    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    }
    mInteractive = true;

    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}

NativeInputManager 类继承了 RefBase、InputReaderPolicyInterface、InputDispatcherPolicyInterface 和 PointerControllerPolicyInterface。可实现引用计数,以及相关策略。Locked 是其私有结构体。

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

class NativeInputManager : public virtual RefBase,
    public virtual InputReaderPolicyInterface,
    public virtual InputDispatcherPolicyInterface,
    public virtual PointerControllerPolicyInterface {
    ......
private:
    ......
    struct Locked {
        // 显示尺寸信息
        DisplayViewport internalViewport;
        DisplayViewport externalViewport;

        // 系统 UI 可见性
        int32_t systemUiVisibility;

        // 指针速度。
        int32_t pointerSpeed;

        // 如果启用指针手势,则为真。
        bool pointerGesturesEnabled;

        // 显示触摸功能启用/禁用。
        bool showTouches;

        // SpriteController 单例
        sp<SpriteController> spriteController;

        // PointerController 单例
        wp<PointerController> pointerController;
    } mLocked;
    ......
};

EventHub 构造函数中出现了 INotify 与 Epoll,以及管道 Pipe,在理解下面代码前,需要复习 INotify 与 Epoll,以及管道 Pipe 知识点。

1.INotify 介绍与使用

INotify 是一个 Linux 内核所提供的一种文件系统变化通知机制。它可以为应用程序监控文件系统的变化,如文件的新建、删除和读写等。INotify 机制有两个基本对象,分别为 inotify 对象与 watch 对象,都使用文件描述符表示。

inotify 对象对应了一个队列,应用程序可以向 inotify 对象添加多个监听。当被监听的事件发生时,可以通过 read() 函数从 inotify 对象中将事件信息读取出来。Inotify 对象可以通过以下方式创建:

int inotifyFd = inotify_init();

而 watch 对象则用来描述文件系统的变化事件的监听。它是一个二元组,包括监听目标和事件掩码两个元素。监听目标是文件系统的一个路径,可以是文件也可以是文件夹。而事件掩码则表示了需要需要监听的事件类型,掩码中的每一位代表一种事件。可以监听的事件种类很多,其中就包括文件的创建(IN_CREATE)与删除(IN_DELETE)等。以下代码即可将一个用于监听输入设备节点的创建与删除的 watch 对象添加到 inotify 对象中:

int wd = inotify_add_watch (inotifyFd, "/dev/input/*", IN_CREATE | IN_DELETE);

完成上述 watch 对象的添加后,当 /dev/input/ 下的设备节点发生创建与删除操作时,都会将相应的事件信息写入到 inotifyFd 所描述的 inotify 对象中,此时可以通过 read() 函数从 inotifyFd 描述符中将事件信息读取出来。

事件信息使用结构体 inotify_event 进行描述:

struct inotify_event {
    __s32 wd;/* 事件对应的 Watch 对象的描述符 */
    __u32 mask;/* 事件类型,例如文件被删除,此处值为 IN_DELETE */
    __u32 cookie;
    __u32 len;/* name 字段的长度 */
    char name[0]; /* 可变长的字段,用于存储产生此事件的文件路径*/
};

当没有监听事件发生时,可以通过如下方式将一个或多个未读取的事件信息读取出来:

size_t len = read (inotifyFd, events_buf, BUF_LEN);

其中 events_buf 是 inotify_event 的数组指针,能够读取的事件数量由取决于数组的长度。成功读取事件信息后,便可根据 inotify_event 结构体的字段判断事件类型以及产生事件的文件路径了。

总结一下 INotify 机制的使用过程:

通过 inotify_init() 创建一个 inotify 对象。

通过 inotify_add_watch 将一个或多个监听添加到 inotify 对象中。

通过 read() 函数从 inotify 对象中读取监听事件。当没有新事件发生时,inotify 对象中无任何可读数据。

INotify 机制并不是通过回调的方式通知事件,而需要使用者主动从 inotify 对象中进行事件读取。那么何时才是读取的最佳时机呢?这就需要借助 Linux 的另一个机制 Epoll 了。

2.Epoll 介绍与使用

无论是从设备节点中获取原始输入事件还是从 inotify 对象中读取文件系统事件,都面临一个问题,就是这些事件都是偶发的。也就是说,大部分情况下设备节点、inotify 对象这些文件描述符中都是无数据可读的,同时又希望有事件到来时可以尽快地对事件作出反应。为解决这个问题,我们不希望不断地轮询这些描述符,也不希望为每个描述符创建一个单独的线程进行阻塞时的读取,因为这都将会导致资源的极大浪费。

此时最佳的办法是使用 Epoll 机制。Epoll 可以使用一次等待监听多个描述符的可读/可写状态。等待返回时携带了可读的描述符或自定义的数据,使用者可以据此读取所需的数据后可以再次进入等待。因此不需要为每个描述符创建独立的线程进行阻塞读取,避免了资源浪费的同时又可以获得较快的响应速度。

Epoll机制的接口只有三个函数:

epoll_create(int max_fds):创建一个 epoll 对象的描述符,之后对 epoll 的操作均使用这个描述符完成。max_fds 参数表示了此 epoll 对象可以监听的描述符的最大数量。

epoll_ctl(int epfd, int op,int fd, struct epoll_event *event):用于管理注册事件的函数。这个函数可以增加/删除/修改事件的注册。

int epoll_wait(int epfd, structepoll_event * events, int maxevents, int timeout):用于等待事件的到来。当此函数返回时,events 数组参数中将会包含产生事件的文件描述符。

接下来以监控若干描述符可读事件为例介绍一下 epoll 的用法。

(1) 创建 epoll 对象

首先通过 epoll_create() 函数创建一个epoll对象:

int epfd = epoll_create(MAX_FDS)

(2) 填充epoll_event结构体

接着为每一个需监控的描述符填充 epoll_event 结构体,以描述监控事件,并通 过epoll_ctl() 函数将此描述符与 epoll_event 结构体注册进 epoll 对象。epoll_event 结构体的定义如下:

struct epoll_event {
     __uint32_tevents; /* 事件掩码,指明了需要监听的事件种类*/
    epoll_data_t data; /* 使用者自定义的数据,当此事件发生时该数据将原封不动地返回给使用者 */
};

epoll_data_t 联合体的定义如下,当然,同一时间使用者只能使用一个字段:

typedef union epoll_data {
    void*ptr;
    int fd;
    __uint32_t u32;
    __uint64_t u64;
} epoll_data_t;

epoll_event 结构中的 events 字段是一个事件掩码,用以指明需要监听的事件种类,同 INotify 一样,掩码的每一位代表了一种事件。常用的事件有 EPOLLIN(可读),EPOLLOUT(可写),EPOLLERR(描述符发生错误),EPOLLHUP(描述符被挂起)等。

data 字段是一个联合体,它让使用者可以将一些自定义数据加入到事件通知中,当此事件发生时,用户设置的 data 字段将会返回给使用者。在实际使用中常设置 epoll_event.data.fd 为需要监听的文件描述符,事件发生时便可以根据 epoll_event.data.fd 得知引发事件的描述符。

填充 epoll_event 的方法如下:

struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN | EPOLLERR | EPOLLHUP; // 监听描述符可读以及出错的事件
eventItem.data.fd= listeningFd; // 填写自定义数据为需要监听的描述符

接下来就可以使用 epoll_ctl() 将事件注册进 epoll 对象。epoll_ctl() 的参数有四个:

epfd 是由 epoll_create() 函数所创建的 epoll 对象的描述符。

op 表示了何种操作,包括 EPOLL_CTL_ADD/DEL/MOD 三种,分别表示增加/删除/修改注册事件。

fd 表示了需要监听的描述符。

event 参数是描述了监听事件的详细信息的 epoll_event 结构体。

注册方法如下:

// 将事件监听添加到epoll对象中去
result = epoll_ctl(epfd, EPOLL_CTL_ADD, listeningFd, &eventItem);

重复这个步骤可以将多个文件描述符的多种事件监听注册到 epoll 对象中。完成了监听的注册之后,便可以通过 epoll_wait() 函数等待事件的到来了。

(3) 使用 epoll_wait() 函数等待事件

epoll_wait() 函数将会使调用者陷入等待状态,直到其注册的事件之一发生之后才会返回,并且携带了刚刚发生的事件的详细信息。其签名如下:

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epfd 是由 epoll_create() 函数所创建的 epoll 对象描述符。

events 是一个 epoll_event 的数组,此函数返回时,事件的信息将被填充至此。

maxevents 表示此次调用最多可以获取多少个事件,当然,events 参数必须能够足够容纳这么多事件。

timeout 表示等待超时的事件。

epoll_wait() 函数返回值表示获取了多少个事件。

(4)处理事件

epoll_wait 返回后,便可以根据 events 数组中所保存的所有 epoll_event 结构体的 events 字段与 data 字段识别事件的类型与来源。

Epoll 的使用步骤总结如下:

通过 epoll_create() 创建一个 epoll 对象。

为需要监听的描述符填充 epoll_events 结构体,并使用 epoll_ctl() 注册到 epoll 对象中。

使用 epoll_wait() 等待事件的发生。

根据 epoll_wait() 返回的 epoll_events 结构体数组判断事件的类型与来源并进行处理。

继续使用 epoll_wait() 等待新事件的发生。

3. Pipe 介绍

管道是一种最基本的 IPC 机制,作用于有血缘关系的进程之间,完成数据传递。调用 pipe 系统函数即可创建一个管道。有如下特质:

1.其本质是一个伪文件(实为内核缓冲区)

2.由两个文件描述符引用,一个表示读端,一个表示写端。

3.规定数据从管道的写端流入管道,从读端流出。

管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区实现。

管道的局限性:

1.数据自己读不能自己写;

2.数据一旦被读走,便不在管道中存在,不可反复读取;

3.由于管道采用半双工通信方式。因此,数据只能在一个方向上流动;

4.只能在有公共祖先的进程间使用管道。

创建管道:

int pipe(int pipefd[2]); //成功:0;失败:-1,设置 errno

函数调用成功返回 r/w 两个文件描述符。无需 open,但需手动 close。规定:fd[0] → r; fd[1] → w,就像 0 对应标准输入,1 对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。

管道创建成功以后,创建该管道的进程(父进程)同时掌握着管道的读端和写端。如何实现父子进程间通信呢?通常可以采用如下步骤:
在这里插入图片描述
1.父进程调用 pipe 函数创建管道,得到两个文件描述符 fd[0]、fd[1] 指向管道的读端和写端。

2.父进程调用 fork 创建子进程,那么子进程也有两个文件描述符指向同一管道。

3.父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。

frameworks/native/services/inputflinger/EventHub.cpp

EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
    // 创建一个 epoll 对象的描述符
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance.  errno=%d", errno);

    // 创建一个 inotify 对象
    mINotifyFd = inotify_init();
    // 通过 inotify_add_watch 将一个或多个监听添加到 inotify 对象中
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
    LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s.  errno=%d",
            DEVICE_PATH, errno);
    // 填充 epoll_event
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;// 监听可读事件
    eventItem.data.u32 = EPOLL_ID_INOTIFY;// 自定义 ID,当事件返回时可知是以上定义的 inotify 相关
    // 将 inotify 事件监听添加到 epoll 对象中去
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance.  errno=%d", errno);

    int wakeFds[2];
    // 创建管道
    result = pipe(wakeFds);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
    // 读端文件描述符
    mWakeReadPipeFd = wakeFds[0];
    // 写端文件描述符
    mWakeWritePipeFd = wakeFds[1];
    // 将管道读端设为非阻塞模式
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking.  errno=%d",
            errno);
    // 将管道写端设为非阻塞模式
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking.  errno=%d",
            errno);

    eventItem.data.u32 = EPOLL_ID_WAKE;// 自定义 ID,当事件返回时可知是以上定义的 Pipe 相关
    // 将管道事件监听添加到 epoll 对象中去
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
    LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance.  errno=%d",
            errno);

    int major, minor;
    // 获取内核版本号
    getLinuxRelease(&major, &minor);
    // EPOLLWAKEUP 是内核 3.5 中引入的
    mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}

以上代码中注释详尽的说明了创建 EventHub 对象都干了什么?接下来分析 InputManager 对象创建。

InputManager 是系统事件处理的核心,它使用了两个线程。

1.InputReaderThread(称为“ InputReader”)读取并预处理原始输入事件,应用策略,并将消息发布到由 DispatcherThread 管理的队列中。

2.InputDispatcherThread(称为“ InputDispatcher”)线程在队列上等待新事件,并异步将其分配给应用程序。

根据设计,InputReaderThread 类和 InputDispatcherThread 类不共享任何内部状态。而且,所有通信都是从 InputReaderThread 到 InputDispatcherThread 的一种方式,绝不会反转。但是,这两个类都可以与 InputDispatchPolicy 交互。

InputManager 类从不对 Java 本身进行任何调用。相反,InputDispatchPolicy 负责执行与系统的所有外部交互,包括调用 DVM 服务。

frameworks/native/services/inputflinger/InputManager.h

namespace android {
class InputManagerInterface : public virtual RefBase {
protected:
    InputManagerInterface() { }
    virtual ~InputManagerInterface() { }

public:
    /* 启动 InputManager 线程 */
    virtual status_t start() = 0;
    /* 停止 InputManager 线程并等待它们退出 */
    virtual status_t stop() = 0;
    /* 获取 InputReader */
    virtual sp<InputReaderInterface> getReader() = 0;
    /* 获取 InputDispatcher */
    virtual sp<InputDispatcherInterface> getDispatcher() = 0;
};

class InputManager : public InputManagerInterface {
protected:
    virtual ~InputManager();

public:
    InputManager(
            const sp<EventHubInterface>& eventHub,
            const sp<InputReaderPolicyInterface>& readerPolicy,
            const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
    // (测试目的)
    InputManager(
            const sp<InputReaderInterface>& reader,
            const sp<InputDispatcherInterface>& dispatcher);

    virtual status_t start();
    virtual status_t stop();

    virtual sp<InputReaderInterface> getReader();
    virtual sp<InputDispatcherInterface> getDispatcher();

private:
    sp<InputReaderInterface> mReader;
    sp<InputReaderThread> mReaderThread;

    sp<InputDispatcherInterface> mDispatcher;
    sp<InputDispatcherThread> mDispatcherThread;

    void initialize();
};

} // namespace android

在 InputManager 构造器中创建了 InputDispatcher 和 InputReader 对象,initialize 方法启动了两个线程 InputReaderThread 和 InputDispatcherThread。

frameworks/native/services/inputflinger/InputManager.cpp

namespace android {

InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    // 1.创建 InputDispatcher 对象
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    // 2.创建 InputReader 对象
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

......
void InputManager::initialize() {
    // 3.创建 InputReaderThread 对象
    mReaderThread = new InputReaderThread(mReader);
    // 4.创建 InputDispatcherThread 对象
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
......

} // namespace android

1.创建 InputDispatcher 对象,初始化了一系列属性,新建了一个 Looper 对象。

frameworks/native/services/inputflinger/InputDispatcher.cpp

namespace android {
......
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
    mLooper = new Looper(false);

    mKeyRepeatState.lastKeyEntry = NULL;

    policy->getDispatcherConfiguration(&mConfig);
}
......
}

2.创建 InputReader 对象,初始化了一系列属性,创建 QueuedInputListener 对象(排队并推迟解码事件的派发,直到刷新为止),刷新配置,并更新了全局 MetaState。

frameworks/native/services/inputflinger/InputReader.cpp

InputReader::InputReader(const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& policy,
        const sp<InputListenerInterface>& listener) :
        mContext(this), mEventHub(eventHub), mPolicy(policy),
        mGlobalMetaState(0), mGeneration(1),
        mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    mQueuedListener = new QueuedInputListener(listener);

    { // acquire lock
        AutoMutex _l(mLock);

        refreshConfigurationLocked(0);
        updateGlobalMetaStateLocked();
    } // release lock
}

3.创建 InputReaderThread 对象

frameworks/native/services/inputflinger/InputReader.cpp

InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
        Thread(/*canCallJava*/ true), mReader(reader) {
}

4.创建 InputDispatcherThread 对象

frameworks/native/services/inputflinger/InputDispatcher.cpp

InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
        Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}

类图总结一下这些类之间的关系:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TYYJ-洪伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值