android /inputmanager-jni,Android InputManager分析

本篇为鸡生蛋系列第二篇文章

主要讲一下inputmanager相关的,即驱动把数据上报到用户空间后,用户空间到应用这么个流程,

在上一遍讲内核的input子系统时候,我们采取的反向分析,即由驱动出发,最后到input core,input子系统架构这么个由点到面的分析方法,

那分析inputmanager是否可采用这种方法如何呢?实际上,对于Android上层(Native framework/framework, c++/java)的分析,我一般

采用的是由上而下的分析,即从其初始化(main,构造,onFirstRef())开始, 通常在其初始化时候,会重一些很重要的上下层的连接,如果由下往上看,会麻烦点,

然后再结合实例,看看他的数据流向是如何的,或者一些重要的API, 例如对于Audio来说,可以结合播放音乐流程来分析整个系统架构。

简单说来,input到应用的流程为

EventHub监控并读取/dev/input下数据 --> 给InputReader 加工处理 --> 到InputDispacher --> 找到focused窗口并通过input channel发出去

相关代码目录:

Android 9.0 http://androidxref.com/9.0.0_r3/

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

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

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

frameworks/native/services/inputflinger/

1.1 初始化frameworks/base/services/java/com/android/server/SystemServer.java

startOtherServices() {

inputManager = new InputManagerService(context);

....

wm = WindowManagerService.main(context, inputManager,

ServiceManager.addService(Context.INPUT_SERVICE, inputManager,

/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);

....

inputManager.setWindowManagerCallbacks(wm.getInputMonitor());

inputManager.start();

......

}

IMS(InputManagerService)的初始化,是从SystemServer开始的,通过搜索代码(如上),我们可以看到构造了一个实例,

并做为参数传给了WMS, 由此我们也猜想,会和WMS有紧密的关系,然后

IMS设置了setWindowManagerCallbacks()并通过start()函数启动了,

SystemServer里有关IMS的就这么几个地方,我们再看下构造和start()具体的流程,与WMS的关联不分析。frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

// Pointer to native input manager service object.

private final long mPtr;

public InputManagerService(Context context) {

this.mContext = context;

this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

// config_useDevInputEventForAudioJack配置为true, 耳机事件可通过input上报

mUseDevInputEventForAudioJack =

context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);

......

mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());

......

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

}

public void start() {

Slog.i(TAG, "Starting input manager");

nativeStart(mPtr);

....

}

InputManagerService构造和start()主要也是调到JNI的 nativeInit() nativeStart().frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,

jobject serviceObj, jobject contextObj, jobject messageQueueObj) {

....

NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,

messageQueue->getLooper());

im->incStrong(0);

return reinterpret_cast(im);

}

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {

......

status_t result = im->getInputManager()->start();

......

}

nativeInit()又构造了一个 NativeInputManager(),该类可认为是上层JAVA和下层EventHub InputManager的桥梁,

nativeStart()通过 NativeInputManager最终调到 InputManager 的 start()方法NativeInputManager::NativeInputManager(jobject contextObj,

jobject serviceObj, const sp& looper) :

mLooper(looper), mInteractive(true) {

......

sp eventHub = new EventHub();

mInputManager = new InputManager(eventHub, this, this);

}

NativeInputManager()的构造又new了 EventHub 和 InputManager , 其中

eventHub做为参数传给了 InputManager()frameworks/native/services/inputflinger/EventHub.cpp

EventHub::EventHub(void) :

......{

acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

mEpollFd = epoll_create(EPOLL_SIZE_HINT); // epoll机制

LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);

mINotifyFd = inotify_init(); // inotify机制

int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); // 利用inotify监控 DEVICE_PATH(/dev/input)创建和删除

......

eventItem.events = EPOLLIN;

eventItem.data.u32 = EPOLL_ID_INOTIFY;

result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); // 将inotify的fd添加到Epoll监控中

LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);

int wakeFds[2];

result = pipe(wakeFds); //读写pipe, InputReader有事件时唤醒

LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);

mWakeReadPipeFd = wakeFds[0];

mWakeWritePipeFd = wakeFds[1];

......

result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);

......

}

EventHub相当于一个集线器,把底层的USB, TOUCH,鼠标等事件统一收集上来,再给上层。

其构造函数当中利用inotify机制监控"/dev/input" 目录下设备的创建和删除,这样当有设备变更时就可以收到通知了,

构造函数也创建了所需要的mEpollFd,这个作为IO多路复用的机制,不清楚的可以查下如何使用,

构造里将mINotifyFd添加到了epoll里,在后续input设备创建的时候,也会把input设备的fd添加进去,这样当有数据或者设备变化时,

EventHub就可获取这些事件,进一步处理。

构造还创建了两个pipe,作为wakeup的读端和写端,当InputReader.cpp有事件(配置变更,monitor, 超时请求等)唤醒EventHub处理。InputManager::InputManager(

const sp& eventHub,

const sp& readerPolicy,

const sp& dispatcherPolicy) {

mDispatcher = new InputDispatcher(dispatcherPolicy);

mReader = new InputReader(eventHub, readerPolicy, mDispatcher); // eventHub又传给了 InputReader,最终他们俩是紧密联系在一起的

initialize(); // eventHub又传给了

}

void InputManager::initialize() {

mReaderThread = new InputReaderThread(mReader);

mDispatcherThread = new InputDispatcherThread(mDispatcher);

}

InputManager(),创建了InputDispatcher和InputReader实例并与对应的InputDispatcherThread InputReaderThread 线程关联

具体的我们不往下跟了,有兴趣的可以再看看,

至此,初始化流程告一段落。

InputManagerService.java的 start方法,最终到InputManager::start(),status_t InputManager::start() {

status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);

......

result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);

......

}

start() 方法目的就是让这两个线程跑起来,这样就可以不断的获取,处理消息了。

1.2 小结startOtherServices()/SystemServer.java

+ new InputManagerService(context) --> nativeInit(...) --> new NativeInputManager(...)

+ + new EventHub() --> inotify监控/dev/input + epoll + wake pipe

+ + new InputManager(eventHub,...)

+ + new InputDispatcher()

+ + new InputReader(eventHub,...)

+ + initialize()

+ + new InputReaderThread(mReader)

+ + new InputDispatcherThread(mDispatcher)

+

+ ^

+ +

+ inputManager.start() --> nativeStart(mPtr) --> im->getInputManager()->start() --> mDispatcherThread->run() mReaderThread->run()

2. 读取数据bool InputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

bool InputDispatcherThread::threadLoop() {

mDispatcher->dispatchOnce();

return true;

}

上一小节讲到IMS通过start()函数,最终让InputReaderThread InputDispatcherThread两个线程跑起来了,

线程跑起来后,他们因为返回值为true, 所以他们会不断的loop, 即不断的读取,分发,读取,分发……

看上面几行代码,觉得整个过程很简单清晰,然而当我们继续跟下去看细节的时候,你能 哇~~哇~~哇~~

这一节我们看看 mReader->loopOnce(), 下一节继续看Dispatcher过程void InputReader::loopOnce() {

......

size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

......

if (count) {

processEventsLocked(mEventBuffer, co

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值