1. SystemServer 中启动 IMS
上一章节中,介绍了输入事件的整体架构设计和 java 层 InputManagerService 的启动,接下来将从源码中详细跟踪 IMS 的启动;首先从 SystemServer.java 中 startOtherServices() 方法开始:
private void startOtherServices() {
// 创建 IMS
inputManager = new InputManagerService(context); // 见1.2
// 创建 WMS
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
mActivityManagerService.setWindowManager(wm);
// wm.getInputMonitor() 获取到的是InputMonitor
inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); // IMS 和 WMS 相互关联 见 1.1
inputManager.start(); // 见1.2
}
1.1 InputMonitor:通信桥梁的建立 (InputMonitor 是 IMS 和 WMS 之间的纽带,在是在 WMS 中初始化的);
final InputMonitor mInputMonitor = new InputMonitor(this);
public InputMonitor getInputMonitor() {
return mInputMonitor;
}
关于 InputMonitor 是 IMS 和 WMS 之间的纽带,其具体的交互是通过 InputDispatcher 完成的,在源码中具体表现为两个方面:InputDispatcher -> InputMonitor -> WMS 和 WMS -> InputMonitor -> InputDispatcher;
// InputDispatcher -> InputMonitor -> WMS:实现了 IMS 中的 WindowManagerCallbalck 接口
public interface WindowManagerCallbacks {
public void notifyConfigurationChanged(); // 配置变更
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen); // LID 开关
public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
// 连接 InputDispatcher 与应用的 socket 连接;
public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);
// ANR
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason);
// 以下三个回调接口是 WMS 处理事件时优先
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
// 事件在整个处理流程均未处理时,与 WMS 协商解决
public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
KeyEvent event, int policyFlags);
public int getPointerLayer();
}
// 当IMS接收到相应输入事件后,会通过mWindowManagerCallbacks 来调用mInputMonitor对象方法:
// return mWindowManagerCallbacks.notifyConfigurationChanged();
// return mWindowManagerCallbacks.notifyANR();
// ...
// WMS -> InputMonitor -> InputDispatcher:通过 InputMonitor 向 WMS 提供访问一系列访问 InputDistacher 的接口;
// 比如 InputDispatcher 中的当前窗口焦点,就是WMS 通过 InputMonitor 中的 updateInputWindowsLw() 通知的;
在这里先预留两个问题:InputDispatcher 时如何通知应用程序窗口有事件产生,又是如何与目标窗口(InputTaget)之间进行通信的?
1.2 InputManagerService 的初始化和 start() 方法:IMS 从 java 层到 native 层的启动;
(1)InputManagerService.java 的构造函数:从 InputManagerService.java 构造函数开始,初始化 input 输入事件关键类;
//(1)InputManagerService.java中:构造函数
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
// native方法,com_android_server_input_InputManagerService.cpp中
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
//(2)nativeInit():native方法,com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// MessageQueue的指针
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// native 层的 NativeInputManager 对象,并返回该对象的指针,赋值给 Java 层的 mPtr;
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
// reinterpret_cast() 用在任意指针(或引用)类型之间的转换
return reinterpret_cast(im);
}
//(3)native 层 NativeInputManager的构造函数:com_android_server_input_InputManagerService.cpp 中
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp& looper) :
mLooper(looper), mInteractive(true) {
// ...
sp eventHub = new EventHub();
// 这就是 input 输入事件番外2 中提到的 mInputManager(输入事件的几个关键类都在其中)
mInputManager = new InputManager(eventHub, this, this);
}
//(4)native 层 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(); // 执行下方的 initialize() 方法
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
(2)InputManagerService.java 的 start() 方法:
(a)input 输入事件从 java 层 的启动到 native 方法 nativeStart(mPtr) 的执行;
(b)nativeStart(mPtr) 方法启动处理线程:处理线程启动后,就代表 IMS 在 native 层成功启动;
//(a)InputManagerService.java 的 start() 方法:从 java 层启动 IMS
public void start() {
Slog.i(TAG, "Starting input manager");
// 在 InputManagerService 的对象 inputManager 初始化过程中执行的 nativeInit() 已经对 mPtr 赋值;
nativeStart(mPtr); // 关键方法
// 将inputmanagerservice添加到 Wathcdog中,Watchdog检测service是否正常工作
Watchdog.getInstance().addMonitor(this);
// 监听Settings.System.POINTER_SPEED、Settings.System.SHOW_TOUCHES 的变化,并通知native层
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
// 接收 ACTION_USER_SWITCHED,这是关于多用户切换的操作
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
//(b)nativeStart(mPtr):com_android_server_input_InputManagerService.cpp 中
static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
// 将传入的 mPtr 强转为 NativeInputManager 对象;reinterpret_cast() 方法上面有介绍过
NativeInputManager* im = reinterpret_cast(ptr);
// 执行的是 InputManager 的 start() 方法;
// 1.2 的代码块 c 中:在初始化 NativeInputManager 时(构造函数中),也对成员变量 mInputManager 进行了初始化
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
status_t InputManager::start() {
// 执行 mDispatcherThread 和 mReaderThread 的 run() 方法,启动处理线程; 详见 2 中的分析;
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;
}
至此,IMS 在 native 层的启动过程基本完成,接下来分析线程启动后,做了哪些事情、事件的读取与分发又是如何完成的 (涉及到后续章节,待更新);
2. 处理线程的分析
Thread 类是 Android 为线程操作而做的一个封装,其内部封装了 pthread 线程工具,提供了与 Java 层Thread 类相似的 API;Thread 类提供了一个名为 threadLoop() 的纯虚函数,当线程开始运行后,将会在内建的线程循环中不断地调用 threadLoop(),直到此函数返回 false,则退出线程循环,从而结束线程。
2.1 线程类简介:
(1)Thread 类的构造函数:
Thread::Thread(bool canCallJava) //注意这里需要传入的参数 canCallJava
: mCanCallJava(canCallJava),
mThread(thread_id_t(-1)),
mLock("Thread::mLock"),
mStatus(NO_ERROR),
mExitPending(false), mRunning(false)
#ifdef HAVE_ANDROID_OS
, mTid(-1)
#endif
{
}
(2)Thread 类的 run() 方法:
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
// reset status and exitPending to their default value, so we can
// try again after an error happened (either below, or in readyToRun())
mStatus = NO_ERROR;
mExitPending = false;
mThread = thread_id_t(-1);
// hold a strong reference on ourself
mHoldSelf = this;
mRunning = true;
bool res;
//如果mCanCallJava为真,则调用createThreadEtc函数,线程函数是_threadLoop。
//_threadLoop是Thread.cpp中定义的一个函数。
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
mHoldSelf.clear(); // "this" may have gone away after this.
return UNKNOWN_ERROR;
}
(3)_threadLoop(void* user) 方法:循环调用 threadLoop();
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast(user);
sp strong(self->mHoldSelf);
wp weak(strong);
self->mHoldSelf.clear();
// ...
bool first = true;
do { // 循环调用 threadLoop()
bool result;
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPending()) {
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}
{
Mutex::Autolock _l(self->mLock);
if (result == false || self->mExitPending) { // threadLoop() 返回为 false 时,结束线程
self->mExitPending = true;
self->mRunning = false;
self->mThread = thread_id_t(-1);
// note that interested observers blocked in requestExitAndWait are
// awoken by broadcast, but blocked on mLock until break exits scope
self->mThreadExitedCondition.broadcast();
break;
}
}
strong.clear(); // 释放引用
// And immediately, re-acquire a strong reference for the next loop
strong = weak.promote();
} while(strong != 0);
return 0;
}
这里对线程只是做了简单的介绍,如果想进一步了解,可以参考 framework 线程类;
2.2 事件读取线程 InputReaderThread 和分发线程 InputDispatcherThread:
(1)InputDispatcherThread:
构造函数:这里只是构建出 InputDispatcherThread 的实例;
InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
循环执行任务:通过上面可知,nativeStart(mPtr) -> InputManager::start() 中执行了分发线程的 run() 方法,而 run() 方法中循环执行 threadLoop() 方法,接下来看看这个方法:
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce(); // 这里也很简单,也就是循环执行 mDispatcher 的 dispatchOnce() 方法;
return true; // return true 表示一直循环执行
}
(2)InputReaderThread:与 InputDispatcherThread 一致,比较简单;
// 构造函数
InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
// 循环执行任务
bool InputReaderThread::threadLoop() {
mReader->loopOnce(); // 循环执行 mReader的 loopOnce() 方法;
return true;
}
小结:
SystemServer.java 中 startOtherServices():创建 java 层的 IMS(inputManager),同时创建 WMS(wm),并通过inputManager.setWindowManagerCallbacks(wm.getInputMonitor()) 进行相互关联;最后执行 inputManager.start() 启动 IMS;
(1)InputManagerService.java 中的构造函数:调用 mPtr = nativeInit(...),创建 native 层的 NativeInputManager,并保存其返回的指针于 mPtr 中;
(2)InputManagerService.java 的 start() 方法:调用 nativeStart(mPtr),IMS 在 native 层启动;nativeInit() 方法:创建 NativeInputManager 对象并返回其指针,同时创建 InputManager 的对象和输入事件所需几个关键类的对象(EventHub, InputDispatcher, InputDispatcherThread, InputReader, InputReaderThread) ;
nativeStart(mPtr) 方法:执行了事件分发线程(mDispatcherThread) 和 事件读取线程(mReaderThread)的 run() 方法,至此 native 层 IMS 的启动完成;