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> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
//構造一個NativeInputManagera對象
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(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>& looper) :
mLooper(looper), mInteractive(true) {
//構造一個EventHub對象,最原始的輸入事件都是通過它收集並且粗加工然後給到InputReader對象
sp<EventHub> 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<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& 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<NativeInputManager*>(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機制,後續再研究