Android输入子系统之启动过程分析

平台:Android6.0
为了使整个流程更清晰,函数的代码只保留跟本文分析相关的部分,并且将一些错误判断相关的代码也去掉了,如有兴趣,可以查阅源码。

Android的输入子系统是在InputManagerService中启动的,而InputManagerService是在system_server中启动的。我们先看下整个启动过程的序列图,然后根据序列图来一步步分析。

Step 1. SystemServer.startOtherServices

函数定义在frameworks/base/services/java/com/android/server/SystemServer.java中

//启动核心服务private void startCoreServices() {}//启动其他的服务private void startOtherServices() {    //初始化一个InputManagerService对象    inputManager = new InputManagerService(context);    wm = WindowManagerService.main(context, inputManager,            mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,            !mFirstBoot, mOnlyCore);    //将WindowManagerService加入到ServiceManager中    ServiceManager.addService(Context.WINDOW_SERVICE, wm);    //将InputManagerService加入到ServiceManager中    ServiceManager.addService(Context.INPUT_SERVICE, inputManager);    inputManager.setWindowManagerCallbacks(wm.getInputMonitor());    inputManager.start();}

在SystemServer中先构造了一个InputManagerService对象和一个WindowManagerService对象,然后将InputManagerService对象传给WindowManagerService对象,WindowManagerService中初始化了一个InputMonitor对象,调用InputManagerService.setWindowManagerCallbacks函数将InputMonitor传进去,后面native层回调时会调用到该InputMonitor对象。

Step 2. InputManagerService.init

InputManagerService.java的构造函数定义在
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public class InputManagerService {    public InputManagerService(Context context) {        this.mContext = context;        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());        //调用nativeInit来执行C++层的初始化操作        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());        LocalServices.addService(InputManagerInternal.class, new LocalService());    }}

构造函数调用nativeInit来执行C++层的初始化操作

Step 3. InputManagerService.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) {    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);    //构造一个NativeInputManagera对象    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,            messageQueue->getLooper());    im->incStrong(0);    return reinterpret_cast(im);}

这个函数主要作用是创建一个NativeInputManager实例,并将其作为返回值保存在InputManagerService.java中的mPtr字段中。

Step 4. NativeInputManager.init

NativeInputManager构造函数定义在frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp文件中

NativeInputManager::NativeInputManager(jobject contextObj,        jobject serviceObj, const sp& looper) :        mLooper(looper), mInteractive(true) {    //构造一个EventHub对象,最原始的输入事件都是通过它收集并且粗加工然后给到InputReader对象    sp eventHub = new EventHub();    //构造一个InputManager对象    mInputManager = new InputManager(eventHub, this, this);}

NativeInputManager构造函数中创建了一个EventHub实例,并且将这个实例作为参数来创建一个InputManager对象,这个对象会做一些初始化的操作。

Step 5. InputManager.init

InputManager的构造函数定义在
frameworks/native/services/inputflinger/InputManager.cpp

InputManager::InputManager(        const sp& eventHub,           const sp& readerPolicy,        const sp& dispatcherPolicy) {    mDispatcher = new InputDispatcher(dispatcherPolicy);     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);    initialize();}

这里创建了InputDispatcher对象用于分发按键给当前focus的窗口的,同时创建了一个InputReader用于从EventHub中读取键盘事件。

Step 6. InputManager.initialize

void InputManager::initialize() {    mReaderThread = new InputReaderThread(mReader);    mDispatcherThread = new InputDispatcherThread(mDispatcher);}

这里创建了一个InputReaderThread和InputDispatcherThread对象,前面构造函数中创建的InputReader实际上是通过InputReaderThread来读取键盘事件,而InputDispatcher实际通过InputDispatcherThread来分发键盘事件

Step 7. InputManagerService.start

InputManagerService.java中start函数定义在
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public void start() {    Slog.i(TAG, "Starting input manager");    nativeStart(mPtr);    ...} 

该函数主要调用了nativeStart进入native层启动

Step 8. InputManagerService.nativeStart

该函数定义在
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {    NativeInputManager* im = reinterpret_cast(ptr);    status_t result = im->getInputManager()->start();}

实际调用了InputManager的start函数

Step 9. InputManager.start

start函数定义在
frameworks/native/services/inputflinger/InputManager.cpp

status_t InputManager::start() {    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);    return OK; }

这个函数实际启动了一个InputReaderThread和InputDispatcherThread来从读取和分发键盘消息,调用它们的run方法后,就会进入threadLoop函数中,只要threadLoop函数返回true,该函数就会循环执行。

Step 10. InputDispatcherThread.threadLoop

该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中

bool InputDispatcherThread::threadLoop() {    mDispatcher->dispatchOnce();    return true;}

这里调用前面在Step 5中创建的实例InputDispatcher的dispatchOnce函数进行一次按键分发

Step 11. InputDispatcher.dispatchOnce

这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 中

void InputDispatcher::dispatchOnce() {    nsecs_t nextWakeupTime = LONG_LONG_MAX;    { // acquire lock        AutoMutex _l(mLock);        mDispatcherIsAliveCondition.broadcast();        // Run a dispatch loop if there are no pending commands.        // The dispatch loop might enqueue commands to run afterwards.        if (!haveCommandsLocked()) {            dispatchOnceInnerLocked(&nextWakeupTime);        }        // Run all pending commands if there are any.        // If any commands were run then force the next poll to wake up immediately.        if (runCommandsLockedInterruptible()) {            nextWakeupTime = LONG_LONG_MIN;        }    } // release lock    // Wait for callback or timeout or wake.  (make sure we round up, not down)    nsecs_t currentTime = now();    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);    mLooper->pollOnce(timeoutMillis);}

上述函数主要是调用dispatchOnceInnerLocked来进行一次按键分发,当没有按键消息时会走到mLooper->pollOnce(timeoutMillis);这个函数会进入睡眠状态,当有按键消息发生时该函数会返回,然后走到dispatchOnceInnerLocked函数。这里mLooper->pollOnce为何会睡眠涉及到Android的Handler机制,后续再研究

更多相关文章

  1. View类
  2. Handler Looper源码解析(Android消息传递机制)
  3. Android(安卓)最全面试题汇总(问题+答案+详解链接)
  4. 从Android(安卓)8.0源码的角度剖析Android系统启动过程(1)
  5. Android(安卓)Audio Subsystem - AudioTrack - play
  6. Android之Service
  7. Android(安卓)KeyListener
  8. 箭头函数的基础使用
  9. 类和 Json对象

随机推荐

  1. Gradle Error: Connection timed out 无
  2. android 判断时间是否已过期
  3. Android叠加更新
  4. android JNI简单的C调java
  5. android study
  6. Android 之 发送邮件
  7. Android通过onTouch事件实现单击,双击,长按
  8. Android 8.0 启动后台service 出错 Illeg
  9. android 编译问题解决
  10. android 打开word pdf excle 进行预览 (