前言
上一篇我们简单介绍了Android系统输入事件的常见类型和事件的传递流程,输入事件的传递流程主要分三个部分,输入系统处理部分、WMS处理部分、View处理部分。
其中输入系统处理部分细分为输入子系统处理部分和InputManagerService处理部分,输入子系统主要是对事件源的原始信息进行采集,而InputManagerService则是监听dev/input下的所有设备节点,当设备节点有数据时会将数据进行加工处理并分发给合适的窗口,在讲解InputManagerService具体是如何处理输入事件的之前,我们需要先来认识一下InputManagerService这个服务。
一、IMS的启动
系统启动后会启动JVM虚拟机,SystemServer 是虚拟机的第一个进程,由init 进程fork 产生,主要用来启动frameworks层中的服务。和其他服务一样,InputManagerService服务也是在这里被启动的,下面我们简单列出SystemServer中和IMS启动相关的源码。
1.1 SystemServer阶段
frameworks/base/service/java/com/android/server/SystemServer.java
public final class SystemServer {
private DisplayManagerService mDisplayManagerService;
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...代码省略...
try {
t.traceBegin("StartServices");
startBootstrapServices(t);//引导服务
startCoreServices(t);//核心服务
startOtherServices(t);//其他服务
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
...代码省略...
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...代码省略...
WindowManagerService wm = null;
InputManagerService inputManager = null;
...代码省略...
t.traceBegin("StartInputManagerService");
inputManager = new InputManagerService(context);//注释1,创建InputManagerService对象
t.traceEnd();
...代码省略...
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
//注释2,WindowManagerService作为输入系统的中转站,其内部持有InputManagerService的引用
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
//将WindowManagerService添加到ServiceManager
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
//将InputManagerService添加到ServiceManager
ServiceManager.addService(Context.INPUT_SERVICE, inputManager, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
...代码省略...
t.traceBegin("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();//注释3,启动IMS服务
t.traceEnd();
...代码省略...
}
}
SystemServer的startOtherServices方法先是在注释1处创建InputManagerService对象,接着在注释2处把IMS作为参数传给WMS以便其创建的实例对象包含有IMS的引用,然后将WMS和IMS都添加到了ServiceManager中进行统一管理,然后还会调用IMS的setWindowManagerCallbacks方法将输入事件回调和WMS进行关联,最后在注释3处调用IMS的start方法启动IMS。
1.2 InputManagerService的创建
1.2.1 InputManagerService构造方法
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor {
private final long mPtr;
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());//注释1,创建InputManagerHandler对象
mStaticAssociations = loadStaticInputPortAssociations();
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());//注释2,调用nativeInit方法
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
}
注释1处使用android.display线程的Looper创建了InputManagerHandler,这样InputManagerHandler便会运行在android.display线程中,android.display线程是系统共享的单例前台线程,这个线程内部执行了WMS的创建。
注释2处调用了nativeInit方法,此方法是一个Native方法,该方法会返回一个NativeInputManager对象指针地址,将该地址赋值给属性变量mPtr,这个属性变量后面后面我们还会提到。
1.2.2 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);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//注释1,创建NativeInputManager对象
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);//注释2,返回对象指针
}
// --- NativeInputManager ---
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface {
protected:
virtual ~NativeInputManager();
public:
NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper);
inline sp<InputManagerInterface> getInputManager() const { return mInputManager; //返回对象实例 }
private:
sp<InputManagerInterface> mInputManager;//InputManager对象
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mServiceObj = 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;
//注释3,创建InputManager对象
InputManager* im = new InputManager(this, this);
mInputManager = im;
defaultServiceManager()->addService(String16("inputflinger"), im);
}
在注释1处会创建NativeInputManager对象,然后在NativeInputManager的构造方法中,也就是注释3处,会创建InputManager对象,进一步通过inputManager来读取设备节点的增删事件和原始输入事件。最后nativeInit方法会调用reinterpret_cast方法,在C++中,reinterpret_cast 是一种类型转换操作符,用于在不同类型之间进行低级别的转换,它提供了一种不安全但非常强大的转换方式,通常用于将一个指针或引用类型转换为另一种类型,**这种转换只是将指针的表示重新解释为另一种类型,不改变指针所指向的内存内容。**这里将该对象指针返回给了java层, 这是为了打通java和native层,下次需要使用native层的NativeInputManager对象的时候,直接传递这个对象指针就可以访问了。
1.2.3 InputManager的构造方法
>frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//注释1,创建inputDispatcher对象
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
//注释2,创建InputReader对象,其内部持有mDispatcher的引用
mReader = createInputReader(readerPolicy, mClassifier);
}
>frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cpp
sp<InputDispatcherInterface> createInputDispatcher(
const sp<InputDispatcherPolicyInterface>& policy) {
//创建InputDispatcher对象
return new android::inputdispatcher::InputDispatcher(policy);
}
>frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
//创建InputReader对象
return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
在注释1处创建InputDispatcher类对象mDispatcher,然后在注释2处创建InputReader类对象mReader,其内部持有mDispatcher的引用,InputReader会不断循环读取EventHub中的原始输入事件,在对这些原始输入事件进行加工后交给InputDispatcher,由于WMS会将所有的窗口信息实时更新到InputDispatcher中,这样InputDispatcher就可以将输入事件派发给合适的窗口。
1.3 InputManagerService的启动
SystemServer的startOtherServices方法中关于IMS的最后一步是调用IMS的start方法。
1.3.1 InputManagerService的start方法
public class InputManagerService extends IInputManager.Stub
implements Watchdog.Monitor {
private final long mPtr;
private static native void nativeStart(long ptr);
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart(mPtr);//注释1,调用nativeStart方法
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);//注释2,将自身添加到看门狗中进行监控
...代码省略...
}
}
在注释1处调用nativeStart方法,此方法同样是一个Native方法,这里调用该方法的时候,还将前面在InputManagerService构造方法中创建的NativeInputManager对象指针传递了进来。在注释2处将自身添加到watchdog中进行监控,用户定时检测系统关键服务是否可能发生死锁。
1.3.2 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);//注释1,获取NativeInputManager对象指针
status_t result = im->getInputManager()->start();//注释2,调用InputManager的start方法
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
// --- NativeInputManager ---
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface {
public:
NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper);
inline sp<InputManagerInterface> getInputManager() const { return mInputManager; //注释3,返回对象实例 }
private:
sp<InputManagerInterface> mInputManager;
在注释1处,将存储在Java层的NativeInputManager对象指针重新转化成Native层需要的对象指针,然后调用NativeInputManager的getInputManager方法获取其内部持有的InputManager对象,并调用InputManager对象的start方法。
1.3.3 InputManager的start方法
>frameworks/native/services/inputflinger/InputManager.cpp
status_t InputManager::start() {
status_t result = mDispatcher->start();//注释1,调用inputdispatcher的start方法
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReader->start();//注释2,调用InputReader的start方法
if (result) {
ALOGE("Could not start InputReader due to error %d.", result);
mDispatcher->stop();
return result;
}
return OK;
}
在注释1处调用InputDispatcher的start方法,该方法内部会开启一个名为InputDispatcher的事件分发线程,在注释2处调用InputDispatcher的start方法,该方法内部会开启一个名为InputReader的事件读取线程。
1.3.3.1 Thread
在分析InputDispatcher和InputReader两个线程之前,我们需要先来看下Thread的run方法。
>system/core/libutils/Threads.cpp
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
...代码省略...
//调用createThreadEtc方法
res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread);
...代码省略...
}
int Thread::_threadLoop(void* user)
Thread* const self = static_cast<Thread*>(user);
...代码省略...
do {
bool result;
result = self->threadLoop();
...代码省略...
if (result == false || self->mExitPending) {
...代码省略...
break;
}
...代码省略...
} while(strong != 0);
}
threadLoop是一个方法指针,第二个参数是自己,最终会调用到_threadLoop方法并传入this指针,_threadLoop方法内部会调用self->threadLoop(),这个self就是当前Thread的this指针,除了result返回false或者调用了requestExit才会退出。 不然会一直循环调用self->threadLoop()函数,threadLoop在Thread中是一个纯虚函数,在其子类中实现,所以后面只要分析子线程的threadLoop方法即可。
1.3.3.2 InputDispatcher的start方法
>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
//注释1,创建InputThread对象
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
>frameworks/base/libs/androidfw/include/androidfw/Util.h
template <typename T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
>frameworks/native/services/inputflinger/InputThread.cpp
class InputThreadImpl : public Thread {
public:
explicit InputThreadImpl(std::function<void()> loop)
: Thread(/* canCallJava */ true), mThreadLoop(loop) {}
~InputThreadImpl() {}
private:
std::function<void()> mThreadLoop;
};
/**
*
* @param name 线程的名称
* @param loop 线程要执行的主循环函数或任务
* @param wake 一个回调函数,用于唤醒或通知线程的动作
*/
InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
: mName(name), mThreadWake(wake) {
mThread = new InputThreadImpl(loop);//注释2,创建InputThreadImpl对象,该对象用于处理线程的实际操作。
mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
在注释1处创建InputThread对象,分别传入了线程名称InputDispatcher、线程主循环函数dispatchOnce,回调函数mLooper->wake();然后在注释2处,也就是InputThread的构造方法中,创建InputThreadImpl对象,该对象继承自Thread ,是真正处理线程实际操作的对象。
1.3.3.3 InputDispatcher的dispatchOnce方法
在InputDispatcher线程启动之后,该线程循环执行的是dispatchOnce方法。
>frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all();
//注释1,检测缓存队列中是否有等待处理的命令
if (!haveCommandsLocked()) {
//将输入事件派发给合适的窗口
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) {
//记录线程下次被唤醒的时间
nextWakeupTime = LONG_LONG_MIN;
}
//注释2,检查ANR
const nsecs_t nextAnrCheck = processAnrsLocked();
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
//注释3,处理空闲状态
if (nextWakeupTime == LONG_LONG_MAX) {
mDispatcherEnteredIdle.notify_all();
}
} // release lock
//注释4,计算InputDisPatcherThread需要休眠的最长时间
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
在注释1处判断,如果没有待处理的命令,调用 dispatchOnceInnerLocked 方法执行一次调度循环;nextWakeupTime用于记录下次唤醒的时间,如果有待处理的命令,则将 nextWakeupTime 设置为 LONG_LONG_MIN,这表示需要立即处理下一个任务,因为命令的执行可能影响了调度的时机。在注释2处检查是否需要处理 ANR 事件,nextAnrCheck 记录了下一次检查 ANR 的时间,将 nextWakeupTime 更新为当前唤醒时间和 ANR 检查时间中的最小值,以确保在 ANR 检查之前唤醒。在注释3处,如果判断nextWakeupTime为LONG_LONG_MAX,表示没有命令、事件或待处理的任务,调度器将进入一个几乎无限长的睡眠状态,此时会通知其他线程或组件事件派发器已进入空闲状态。
在注释4处获取当前时间 currentTime,并使用toMillisecondTimeoutDelay方法计算直到 nextWakeupTime 的超时时间, 调用 mLooper->pollOnce(timeoutMillis) 方法,进入等待状态,直到有事件到达、超时或者有其他需要唤醒的情况发生。
1.3.3.4 InputReader的start和loopOnce方法
和InputDispatcher的start方法类似,InputReader的start方法也是进一步创建InputThread对象,分别传入了线程名称InputReader、线程主循环函数loopOnce,回调函数mEventHub->wake();该线程启动之后会循环执行loopOnce方法。
>frameworks/>native/services/inputflinger/reader/InputReader.cpp
status_t InputReader::start() {
if (mThread) {
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
"InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
return OK;
}
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
std::scoped_lock _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
//注释1,获取设备节点的原始输入事件信息
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
std::scoped_lock _l(mLock);
//通知所有等待的线程,输入读取器仍然活跃。
mReaderIsAliveCondition.notify_all();
if (count) {
//注释2,对mEventBuffer中的原始输入事件信息进行加工处理,加工后的输入事件会交给InputDispatcher来处理
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
//注释3,处理超时事件
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
inputDevices = getInputDevicesLocked();
}
} // release lock
//注释4,如果输入设备状态发生了变化,调用mPolicy->notifyInputDevicesChanged方法进行事件通知
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
mQueuedListener->flush();//刷新或处理排队的监听器事件。
}
在注释1处从事件缓冲区中获取设备节点的原始输入事件信息并将其存放到mEventBuffer中,timeoutMillis 是等待事件的超时时间,mEventBuffer 是存放事件的缓冲区,EVENT_BUFFER_SIZE 是缓冲区的大小,事件信息主要有两种,设备节点的增删事件、原始输入事件;在注释2处 判断是否有事件,如果有则调用processEventsLocked方法,该方法会对mEventBuffer中的原始输入事件信息进行加工处理,并将加工后的输入事件会交给InputDispatcher处理;在注释3处判断输入事件是否已经超时,如果超时则调用timeoutExpiredLocked方法处理超时事件;在注释4处判断输入设备状态是否发生了变化,如果是则通知相关的策略或组件。
二、IMS架构图
这里我们结合InputManagerService的构造方法和start方法画了个简单的IMS架构图。