抚顺市城市建设档案馆网站,seo公司排名榜,电商网站维护,北京住房和建设部网站IMS初始化
一、简介
当用户触摸屏幕或者按键操作#xff0c;首次触发的是硬件驱动#xff0c;驱动收到事件后#xff0c;将该相应事件写入到输入设备节点#xff0c; 这便产生了最原生态的内核事件。接着#xff0c;输入系统取出原生态的事件#xff0c;经过层层封装后…IMS初始化
一、简介
当用户触摸屏幕或者按键操作首次触发的是硬件驱动驱动收到事件后将该相应事件写入到输入设备节点 这便产生了最原生态的内核事件。接着输入系统取出原生态的事件经过层层封装后成为KeyEvent或者MotionEvent 最后交付给相应的目标窗口(Window)来消费该输入事件
二、对象介绍
frameworks/native/services/inputflinger/reader/InputReader.cppframeworks/native/services/inputflinger/reader/EventHub.cppframeworks/base/services/core/java/com/android/server/input/InputManagerService.javaframeworks/native/services/inputflinger/dispatcher/InputDispatcher.cppframeworks/base/services/core/jni/com_android_server_input_InputManagerService.cppframeworks/native/services/inputflinger/InputManager.cpp
三**、IMS初始化分析**
InputManagerService位于SystemServer.java#startOtherServices方法中被启动源码如下
private void startOtherServices(NonNull TimingsTraceAndSlog t) {...InputManagerService inputManager null;...t.traceBegin(StartInputManagerService);inputManager new InputManagerService(context);t.traceEnd();...// WMS与InputManagerService/ActivityTaskManager/PhoneWindowManager相互绑定// WMS创建时会基于DisplayThread也就是WMS是运行在android.display线程中wm WindowManagerService.main(context, **inputManager**, !mFirstBoot, mOnlyCore,new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);// 将IMS加入ServiceManager中统一管理ServiceManager.addService(Context.INPUT_SERVICE, inputManager);...inputManager.start();
所以IMS的执行顺序为new InputManagerService(context);、inputManager.start();并且属于systemServer线程继续看构造方法
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) {this.mContext context;// 运行在android.display线程,这个handler很重要this.mHandler new InputManagerHandler(DisplayThread.get().getLooper());...//初始化native对象mPtr nativeInit(this, mContext, mHandler.getLooper().getQueue());...LocalServices.addService(InputManagerInternal.class, new LocalService());}this.mHandler是非常重要的运行在android.display线程上跟WMS所处的线程一样主要用于以下几个方面
接收和处理输入事件mHandler会接收来自底层硬件如触摸屏、按键等的原始输入事件并将其封装成消息发送给mHandler处理。这样可以将输入事件的处理从主线程转移到后台线程android.display**分发输入事件**mHandler会将接收到的输入事件分发给相应的窗口或应用程序进行处理。通过消息的处理和分发机制确保输入事件能够顺利传递给正确的目标实现用户输入的精确响应。**处理输入事件队列**mHandler会维护一个输入事件队列将接收到的输入事件按照一定的顺序存储在队列中并逐个处理。这样可以保证输入事件的有序性避免输入事件的丢失或混乱。
总而言之mHandler在InputManagerService中的作用是接收、处理和分发输入事件实现用户输入的响应和传递。通过将输入事件的处理从主线程转移到android.display线程systemServer线程会等待display线程处理完成后才会继续执行
继续看看nativeInit方法位于frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
类名叫NativeInputManager
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,jobject serviceObj/*IMS*/, jobject contextObj/*context*/, jobject messageQueueObj/*MessageQueue*/) {// messageQueueObj就是上层调用的mHandler.getLooper().getQueue()// 该handler属于android.display线程// 这段代码定义了一个名为sp的变量它的类型是一个智能指针指向一个MessageQueue对象。智能指针是一种封装了指针的对象// 它具有自动管理内存的能力即在不需要使用该指针时会自动释放它所指向的内存空间// 避免了内存泄漏的问题。这里使用的是Android系统提供的sp智能指针它是一个引用计数智能指针可以在多个线程间安全地传递和共享// 这里获取了Message队列spMessageQueue messageQueue android_os_MessageQueue_getMessageQueue(env, messageQueueObj);if (messageQueue nullptr) {jniThrowRuntimeException(env, MessageQueue is not initialized.);return 0;}//NativeInputManager中创建了InputManagerNativeInputManager* im new NativeInputManager(contextObj, serviceObj,messageQueue-getLooper());im-incStrong(0);return reinterpret_castjlong(im);
}先介绍一下方法里的形参
JNIEnv* envJNI对象native方法必须也有的该参数无需开发者去关心只有JNI开发时会用到里面的参数和方法此处不做关心serviceObjInputManagerService.java的实例对象contextObjIMS中的context上下文messageQueueObjmHandler中Looper里管理的队列
以上代码只关注获取了messageQueue和创建了NativeInputManager对象
NativeInputManager::NativeInputManager(jobject contextObj,jobject serviceObj, const spLooper looper/*messageQueue的looper*/) :mLooper(looper), mInteractive(true) {JNIEnv* env jniEnv();// mServiceObj就是InputManagerServicemServiceObj env-NewGlobalRef(serviceObj);{AutoMutex _l(mLock);mLocked.systemUiLightsOut false;mLocked.pointerSpeed 0;mLocked.pointerGesturesEnabled true;mLocked.showTouches false;mLocked.pointerDisplayId ADISPLAY_ID_DEFAULT;}mInteractive true;// 初始化InputManager创建InputManager对象InputManager* im new InputManager(this, this);mInputManager im;defaultServiceManager()-addService(String16(inputflinger), im);
}然后继续创建了InputManager对象并将im加入服务队列中继续看看IM对象的构造方法
frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(const spInputReaderPolicyInterface readerPolicy,const spInputDispatcherPolicyInterface dispatcherPolicy) {// 创建InputDispatcher// 创建InputReader// InputReader读取/dev/input节点然后将数据传递给InputDispatcher// 由InputDispatcher来分发事件到window// readerPolicy和dispatcherPolicy都是NativeInputManager对象NativeInputManager实现了这两个接口// 就饿可以通过Policy来回调数据给NativeInputManager了mDispatcher createInputDispatcher(dispatcherPolicy);mClassifier new InputClassifier(mDispatcher);// 包含了EventHub和InputListenerInterface及readerPolicymReader createInputReader(readerPolicy, mClassifier);
}// 创建InputReader并创建了EventHub
spInputReaderInterface createInputReader(const spInputReaderPolicyInterface policy,const spInputListenerInterface listener) {return new InputReader(std::make_uniqueEventHub(), policy, listener);
}// 创建InputDispatcher
spInputDispatcherInterface createInputDispatcher(const spInputDispatcherPolicyInterface policy) {return new android::inputdispatcher::InputDispatcher(policy);
}1.记住两个重要的接口InputReaderPolicyInterface、InputDispatcherPolicyInterface他们的具体实现在NativeInputManager中也就是com_android_server_input_InputManagerService.cpp中。
2.然后创建了InputDispatcher和InputReader并在InputReader创建过程中同步创建了EventHub
3.InputReader读取/dev/input节点然后将数据传递给InputDispatcher
4.InputDispatcher接收来自InputReader的事件然后由InputDispatcher来分发事件到window
继续看看EventHub的构造方法看看有什么作用
frameworks/native/services/inputflinger/reader/EventHub.cpp
EventHub::EventHub(void): mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),mNextDeviceId(1),mControllerNumbers(),mNeedToSendFinishedDeviceScan(false),mNeedToReopenDevices(false),mNeedToScanDevices(true),mPendingEventCount(0),mPendingEventIndex(0),mPendingINotify(false) {ensureProcessCanBlockSuspend();mEpollFd epoll_create1(EPOLL_CLOEXEC);LOG_ALWAYS_FATAL_IF(mEpollFd 0, Could not create epoll instance: %s, strerror(errno));// inotify是Linux内核提供的一种文件系统监控机制它可以监测文件或目录的变化并通过特定的事件通知机制通知进程mINotifyFd inotify_init();// 此处DEVICE_PATH为/dev/input监听该设备节点创建与删除操作// 屏幕的所有事件都会经过处理存放进/dev/input内核态mInputWd inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);LOG_ALWAYS_FATAL_IF(mInputWd 0, Could not register INotify for %s: %s, DEVICE_PATH,strerror(errno));if (isV4lScanningEnabled()) {mVideoWd inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);LOG_ALWAYS_FATAL_IF(mVideoWd 0, Could not register INotify for %s: %s,VIDEO_DEVICE_PATH, strerror(errno));} else {mVideoWd -1;ALOGI(Video device scanning disabled);}struct epoll_event eventItem {};eventItem.events EPOLLIN | EPOLLWAKEUP;eventItem.data.fd mINotifyFd;// 将mINotifyFd添加到fd池中int 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];// 调用了 pipe() 函数来创建一个无名管道并将管道的读取端口和写入端口的文件描述符分别存储在 wakeFds[0] 和 wakeFds[1] 中。// 这个管道可以用于进程间通信其中一个进程将数据写入管道而另一个进程则可以从管道中读取这些数据。result pipe(wakeFds);LOG_ALWAYS_FATAL_IF(result ! 0, Could not create wake pipe. errno%d, errno);mWakeReadPipeFd wakeFds[0];mWakeWritePipeFd wakeFds[1];// 将pipe的读设置为非阻塞方式result fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);LOG_ALWAYS_FATAL_IF(result ! 0, Could not make wake read pipe non-blocking. errno%d,errno);// 将pipe的写设置为非阻塞方式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.fd mWakeReadPipeFd;// 添加管道的读端到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);
}作用总结创建文件系统监控机制它可以监测/dev/input的变化因为从屏幕触碰的事件都会存入这个驱动节点中创建管道用于进程间通信文件描述符存放到wakeFds[0] 和 wakeFds[1]中其中一个进程将数据写入管道而另一个进程则可以从管道中读取这些数据 再将pipe的读/写设置为非阻塞方式。
创建监控驱动节点变化的文件描述符通过监听驱动节点的内容将内容放入管道进行两端通信
frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptrEventHubInterface eventHub/*eventHub*/,const spInputReaderPolicyInterface policy/*NativeInputManager*/,const spInputListenerInterface listener): mContext(this),mEventHub(eventHub),mPolicy(policy)...{// 创建了QueuedInputListener---创建输入监听对象// 此处mQueuedListener的成员变量mInnerListener便是InputDispatcher对象。mQueuedListener new QueuedInputListener(listener);...
}QueuedInputListener::QueuedInputListener(const spInputListenerInterface innerListener) :mInnerListener(innerListener) {
}创建了QueuedInputListener里面有个成员变量mInnerListenerInputListenerInterface指向的回调就是InputDispatcher对象InputListenerInterface接口很重要用于将输入事件封装成NotifyKeyArgs对象回调给InputDispatcher
再来看看rameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const spInputDispatcherPolicyInterface policy): mPolicy(policy),mPendingEvent(nullptr),mLastDropReason(DropReason::NOT_DROPPED),mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),mAppSwitchSawKeyDown(false),mAppSwitchDueTime(LONG_LONG_MAX),mNextUnblockedEvent(nullptr),mDispatchEnabled(false),mDispatchFrozen(false),mInputFilterEnabled(false),// mInTouchMode will be initialized by the WindowManager to the default device config.// To avoid leaking stack in case that call never comes, and for tests,// initialize it here anyways.mInTouchMode(true),mMaximumObscuringOpacityForTouch(1.0f),mFocusedDisplayId(ADISPLAY_ID_DEFAULT),mWindowTokenWithPointerCapture(nullptr),mLatencyAggregator(),mLatencyTracker(mLatencyAggregator),mCompatService(getCompatService()) {// 创建一个loopermLooper new Looper(false);mReporter createInputReporter();mKeyRepeatState.lastKeyEntry nullptr;// 获取分发超时参数policy-getDispatcherConfiguration(mConfig);
}创建属于自己线程的Looper对象配置超时机制超时参数来自于IMS参数默认值keyRepeatTimeout 500keyRepeatDelay 50。keyRepeatTimeout的值为500 * 1000000LL即500毫秒。这个值表示当用户按住一个键不放时系统会在这个键按下后的500毫秒之后开始重复这个键的事件keyRepeatDelay的值为50 * 1000000LL即50毫秒。这个值表示当用户按住一个键不放时系统会在这个键按下后的50毫秒之后开始发送第一个重复事件
初始化就算完成了再来总结一下首先通过上层的IMS进入native层创建NativeInputManager—InputManager然后创建了EventHubInputReaderInputDispatcherEventHub用于创建文件描述符来监听/dev/input驱动节点的内容再通过管道形式进行数据传递InputReader创建了事件输入的监听器QueuedInputListenerInputDispatcher创建了属于自己的looper和配置了超时机制。以上的输入事件均运行在android.display线程因为looper是由IMS传递下来的在这里插入代码片