Android7 Input(一)Android Input服务初始化
本系列博客主要描述Android 7.1系统中输入管理服务InputManagerService的源码分析。
概述
本文主要描述了InputManagerService服务的初始化和启动,在Android7系统上InputManagerService服务的框架如下所示:
注:箭头的方向,并不能真实代表数据流向方向。
1、FrameWorks层:inputManagerService对外提供服务的模块;
2、JNI层:因为InputManagerService要去管理底层硬件输入设备,而在Android 7系统的所有与硬件相关的部分,都会涉及到JNI层。用C++代码去管理硬件设备;
3、Inputfliger: 是InputManager事件处理的核心事件,包括事件的获取和分发等;
4、kernel层,主要涉及的input输入驱动,并且将设备产生的事件通过inpu子系统上传给C++ inputflinger层;
5、硬件层,具体的输入设备,因为输入设备的类型很过,这里只是大概罗列出了嵌入式设备上常用的几个;
InputManagerService服务的初始化和启动比较简单,由SystemServer服务创建并拉起。
源码路径
本文描述中涉及的源码有:
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
framesworks/native/services/inputflinger/inputManager.cpp
InputManagerServie服务的初始化
java层的服务初始化
在系统核心服务SystemServer初始化中,在启动其他服务startOtherService方法中,会创建InputManagerService服务。代码片段如下所示:
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
......
traceBeginAndSlog("StartInputManagerService");
/* 创建InputManagerService服务 */
inputManager = new InputManagerService(context);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
traceBeginAndSlog("StartWindowManagerService");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
/* 注册InputManagerServie服务 */
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
if (!disableVrManager) {
traceBeginAndSlog("StartVrManagerService");
mSystemServiceManager.startService(VrManagerService.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
mActivityManagerService.setWindowManager(wm);
/* 设置InputManagerService的窗口回调接口 */
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
......
}
1、在systemServer的服务中创建InputManagerService;
2、设置InputManagerService的窗口回调接口,因此最终的事件要传递给上层App的Windows窗口去处理;
创建InputManagerService并进入它的构造方法继续初始化,代码片段如下所示:
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputManagerService(Context context) {
this.mContext = context;
/* 创建Handler, 并使用displayThead现成的Looper */
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
/* 调用InputManagerService服务的JNI方法nativeInit继续初始化 */
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
在构造方法中:
1、创建InputManagerHander,并使用DisplayThread线程的Looper处理Handler消息;
2、调用InputManagerService服务的JNI方法nativeInit()方法继续初始化,并且将mHandler.getLooper().getQueue()队列传递给JNI层,在前面的初始化中InputManagerService自己的Handler使用了DisplayThread的Looper, 也就是说,在这个地方等同于将DisplayThread线程的消息队列传递给了InputManagerService的JNI层;
native层的初始化
根据前面的描述,InputManagerService服务的Java层调用nativeInit方法,继续初始化Native层,初始化代码片段,如下所示:
a、nativeInit()
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
/* 将java层的messageQueue对象转化到对应的native层的messageQueue对象 */
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
/* 创建NativeInputManager输入管理 */
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
/* 将native层的对象指针返回java层 */
return reinterpret_cast<jlong>(im);
}
1、将java层的MessageQueue对象转化到它对应native层的C++对象,这个比较管理,涉及到后面的事件处理,暂时先不描述;
2、创建NativeInputManager对象;
3、返回JNI创建的C++对象的指针返回java层;
b、NativeInputManger的初始化
NativeInputManager的初始化,关键代码片段如下所示:
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
......
/* 创建EventHub() 事件获取*/
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
1、创建EventHub()对象,该对象,主要就是获取输入事件(各种输入设备产生的事件和软件模拟产生的事件);
2、创建InputManager对象;
c、InputManager对象的初始化
framesworks/native/services/inputflinger/inputManager.cpp
InputManager对象初始化中如下所示:
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
/* 创建事件分发对象 */
mDispatcher = new InputDispatcher(dispatcherPolicy);
/* 创建事件获取对象 */
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
1、创建事件分发对象;
2、创建事件获取对象;
3、创建事件分发和事件获取线程,如下所示:
void InputManager::initialize() {
/* 创建事件获取线程 */
mReaderThread = new InputReaderThread(mReader);
/* 创建事件分发线程 */
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
至此,InputManagerService服务从java层的初始化过程到JNI层的初始化过程,描述完成.
InputManagerService服务启动
Java层的启动
InputManagerSerivice服务在Java层的启动,也是在SystemServer服务中完成。非常简单。执行代码片段如下所示:
frameworks/base/services/java/com/android/server/SystemServer.java
/* 设置InputManagerService的窗口回调接口 */
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
/* 启动InputManagerService服务 */
inputManager.start();
然后调用InputManagerService中的start方法,关键执行代码片段如下:
public void start() {
Slog.i(TAG, "Starting input manager");
/* 调用JNI层nativeStart */
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
1、直接调用jni层的nativeStart的接口;
Native层的启动
jni层的启动,关键代码片段如下所示:
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
最终调用InputManager的start方法
framesworks/native/services/inputflinger/inputManager.cpp
status_t InputManager::start() {
/* 开启分发线程 */
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
/* 开启事件获取线程 */
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
总结
1、InputManagerService服务的注册和启动都在SystemServer服务中完成;
2、InputManagerservice服务初始化过程中会在native层注册事件获取和分发的线程;
3、整个初始化过程中,从Java层到native层都传递了DisplayThread线程的Looper的MessageQueue;