Android应用程序键盘(Keyboard)消息处理机制分析(2)
Step 6. InputManager.nativeInit
这个函数定义在frameworks/base/services/jni$ vi com_android_server_InputManager.cpp文件中:
- staticvoidandroid_server_InputManager_nativeInit(JNIEnv*env,jclassclazz,
- jobjectcallbacks){
- if(gNativeInputManager==NULL){
- gNativeInputManager=newNativeInputManager(callbacks);
- }else{
- LOGE("Inputmanageralreadyinitialized.");
- jniThrowRuntimeException(env,"Inputmanageralreadyinitialized.");
- }
- }
这个函数的作用是创建一个NativeInputManager实例,并保存在gNativeInputManager变量中。由于是第一次调用到这里,因此,gNativeInputManager为NULL,于是就会new一个NativeInputManager对象出来,这样就会执行NativeInputManager类的构造函数来执其它的初始化操作。
Step 7. NativeInputManager<init>
NativeInputManager类的构造函数定义在frameworks/base/services/jni$ vi com_android_server_InputManager.cpp文件中:
- NativeInputManager::NativeInputManager(jobjectcallbacksObj):
- mFilterTouchEvents(-1),mFilterJumpyTouchEvents(-1),mVirtualKeyQuietTime(-1),
- mMaxEventsPerSecond(-1),
- mDisplayWidth(-1),mDisplayHeight(-1),mDisplayOrientation(ROTATION_0){
- JNIEnv*env=jniEnv();
- mCallbacksObj=env->NewGlobalRef(callbacksObj);
- sp<EventHub>eventHub=newEventHub();
- mInputManager=newInputManager(eventHub,this,this);
- }
这里只要是创建了一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。注意,这里的InputManager类是定义在C++层的,和前面在Java层的InputManager不一样,不过它们是对应关系。EventHub类是真正执行监控键盘事件操作的地方,后面我们会进一步分析到,现在我们主要关心InputManager实例的创建过程,它会InputManager类的构造函数里面执行一些初始化操作。
Step 8. InputManager<init>@C++
C++层的InputManager类的构造函数定义在frameworks/base/libs/ui/InputManager.cpp文件中:
- InputManager::InputManager(
- constsp<EventHubInterface>&eventHub,
- constsp<InputReaderPolicyInterface>&readerPolicy,
- constsp<InputDispatcherPolicyInterface>&dispatcherPolicy){
- mDispatcher=newInputDispatcher(dispatcherPolicy);
- mReader=newInputReader(eventHub,readerPolicy,mDispatcher);
- initialize();
- }
Step 9. InputManager.initialize
这个函数定义在frameworks/base/libs/ui/InputManager.cpp文件中:
- voidInputManager::initialize(){
- mReaderThread=newInputReaderThread(mReader);
- mDispatcherThread=newInputDispatcherThread(mDispatcher);
- }
至此,InputManager的初始化工作就完成了,在回到Step 3中继续分析InputManager的进一步启动过程之前,我们先来作一个小结,看看这个初始化过程都做什么事情:
A. 在Java层中的WindowManagerService中创建了一个InputManager对象,由它来负责管理Android应用程序框架层的键盘消息处理;
B. 在C++层也相应地创建一个InputManager本地对象来负责监控键盘事件;
C. 在C++层中的InputManager对象中,分别创建了一个InputReader对象和一个InputDispatcher对象,前者负责读取系统中的键盘消息,后者负责把键盘消息分发出去;
D.InputReader对象和一个InputDispatcher对象分别是通过InputReaderThread线程实例和InputDispatcherThread线程实例来实键盘消息的读取和分发的。
有了这些对象之后,万事就俱备了,回到Step 3中,调用InputManager类的start函数来执行真正的启动操作。
Step 10. InputManager.start
这个函数定义在frameworks/base/services/java/com/android/server/InputManager.java文件中:
- publicclassInputManager{
- ......
- publicvoidstart(){
- Slog.i(TAG,"Startinginputmanager");
- nativeStart();
- }
- ......
- }
Step 11. InputManager.nativeStart
这个函数定义在frameworks/base/services/jni$ vi com_android_server_InputManager.cpp文件中:
- staticvoidandroid_server_InputManager_nativeStart(JNIEnv*env,jclassclazz){
- if(checkInputManagerUnitialized(env)){
- return;
- }
- status_tresult=gNativeInputManager->getInputManager()->start();
- if(result){
- jniThrowRuntimeException(env,"Inputmanagercouldnotbestarted.");
- }
- }
这里的gNativeInputManager对象是在前面的Step 6中创建的,通过它的getInputManager函数可以返回C++层的InputManager对象,接着调用这个InputManager对象的start函数。
Step 12. InputManager.start
这个函数定义在frameworks/base/libs/ui/InputManager.cpp文件中:
- status_tInputManager::start(){
- status_tresult=mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);
- if(result){
- LOGE("CouldnotstartInputDispatcherthreadduetoerror%d.",result);
- returnresult;
- }
- result=mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
- if(result){
- LOGE("CouldnotstartInputReaderthreadduetoerror%d.",result);
- mDispatcherThread->requestExit();
- returnresult;
- }
- returnOK;
- }
我们先来分析InputDispatcherThread线程分发消息的过程,然后再回过头来分析InputReaderThread线程读取消息的过程。
Step 13.InputDispatcherThread.threadLoop
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- boolInputDispatcherThread::threadLoop(){
- mDispatcher->dispatchOnce();
- returntrue;
- }
Step 14. InputDispatcher.dispatchOnce
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::dispatchOnce(){
- nsecs_tkeyRepeatTimeout=mPolicy->getKeyRepeatTimeout();
- nsecs_tkeyRepeatDelay=mPolicy->getKeyRepeatDelay();
- nsecs_tnextWakeupTime=LONG_LONG_MAX;
- {//acquirelock
- AutoMutex_l(mLock);
- dispatchOnceInnerLocked(keyRepeatTimeout,keyRepeatDelay,&nextWakeupTime);
- if(runCommandsLockedInterruptible()){
- nextWakeupTime=LONG_LONG_MIN;//forcenextpolltowakeupimmediately
- }
- }//releaselock
- //Waitforcallbackortimeoutorwake.(makesureweroundup,notdown)
- nsecs_tcurrentTime=now();
- int32_ttimeoutMillis;
- if(nextWakeupTime>currentTime){
- uint64_ttimeout=uint64_t(nextWakeupTime-currentTime);
- timeout=(timeout+999999LL)/1000000LL;
- timeoutMillis=timeout>INT_MAX?-1:int32_t(timeout);
- }else{
- timeoutMillis=0;
- }
- mLooper->pollOnce(timeoutMillis);
- }
这个函数很简单,把键盘消息交给dispatchOnceInnerLocked函数来处理,这个过程我们在后面再详细分析,然后调用mLooper->pollOnce函数等待下一次键盘事件的发生。这里的成员变量mLooper的类型为Looper,它定义在C++层中,具体可以参考前面Android应用程序消息处理机制(Looper、Handler)分析一文。
更多相关文章
- Android Audio代码分析21 - 创建AudioEffect对象
- Android Training精要(六)如何防止Bitmap对象出现OOM
- android listview 与 一般多线程配合产生的错误,资料汇总
- Android Audio代码分析2 - 函数getMinBufferSize
- android关于fragment的构造函数用法建议
- 文件多线程下载实现
- Android Audio代码分析18 - setSampleRate函数
- android使用多线程处理