Android 输入系统架构 笔记1
来源:互联网 发布:阿里云企业邮箱官网 编辑:程序博客网 时间:2024/05/22 16:44
1. 首先看下服务的启动:
Android系统启动的时候,会启动很多服务,一般都是在SystemServer中启动的,代码如下:
路径 Framework/base/services/java/com/android/server/SystemServer.java
wm = WindowManagerService.main(context, power,factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,!firstBoot);
这里创建了一个WindowManagerService的类,我们来看看这个类的构造函数:
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
private WindowManagerService(Context context, PowerManagerService pm,boolean haveInputMethods, boolean showBootMsgs) {
……
mInputManager = new InputManager(context, this);
……
mInputManager.start();
……
}
在WindowManagerService的构造函数中又new了一个InputManager类。InputManager类是整个android的input的上层代码最重要的类就是通过这个类繁衍出了整个复杂的Android的input子系统。作用就好像Zygote的孕育着Android的各个服务而InputManager就是负责将整个android的Input子系统。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
public InputManager(Context context, WindowManagerService windowManagerService) {
……
Looper loo
per = windowManagerService.mH.getLooper();
nativeInit(mContext, mCallbacks, looper.getQueue());
……
}
在InputManger的构造函数中调用了nativeInit这个方式看到native开头或者结尾的函数一般都是JNI。在InputManager的JNI可以找到这个函数的实现。
Framework/base/services/jni/com_android_server_InputManager.java
static JNINativeMethod gInputManagerMethods[] = {
{ "nativeInit", "(Landroid/content/Context;" "Lcom/android/server/wm/InputManager$Callbacks;Landroid/os/MessageQueue;)V",
(void*) android_server_InputManager_nativeInit },
Framework/base/services/jni/com_android_server_InputManager.java
static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,
jobject contextObj, jobject callbacksObj, jobject messageQueueObj) {
……
gNativeInputManager = new NativeInputManager(contextObj, callbacksObj, looper);
……
}
在JNI的代码中又构造了一个重要的NativeInputManager类这是个C++的本地类。已经不在是之前了那个java的InputManager类。接下来看看NativeInputManager的构造函数。
Framework/base/services/jni/com_android_server_InputManager.java
NativeInputManager::NativeInputManager(jobject contextObj,
jobject callbacksObj, const sp<Looper>& looper) :mLooper(looper) {
……
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
……
}
这里new了两个类EventHub和InputManager类。EventHub就是Input子系统的HAL层了负责将linux的所有的input设备打开并负责轮询读取他们的上报的数据后面会详细介绍这里先简单介绍一下。InputManager类主要是负责管理input Event有InputReader从EventHub读取事件然后交给InputDispatcher进行分发。
Framework/base/services/input/InputManager.cpp
InputManager::InputManager(
const sp<InputReaderInterface>& reader,
const sp<InputDispatcherInterface>& dispatcher) :
mReader(reader),
mDispatcher(dispatcher) {
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
在InputManager中的initialize的初始化了两个线程。一个是inputReaderThread负责从EventHub中读取事件另外一个是InputDispatcherThread线程主要负责分发读取的事件去处理。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
private WindowManagerService(Context context, PowerManagerService pm, boolean haveInputMethods, boolean showBootMsgs){
mInputManager.start();
……
}
在开始的时候new了一个InputManager然后在继续调用其start方法。
Framework/base/services/java/com/android/server/wm/WindowManagerServer.java
public void start() {
Slog.i(TAG, "Starting input manager");
nativeStart();
registerPointerSpeedSettingObserver();
registerShowTouchesSettingO
bserver();
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
NativeStart()跑到JNI的代码中去了跟上面的方式一样。
Framework/base/services/jni/com_android_server_InputManager.java
static JNINativeMethod gInputManagerMethods[] = {
…
…
{ "nativeStart", "()V", (void*) android_server_InputManager_nativeStart },
……
}
static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {
……
status_t result = gNativeInputManager->getInputManager()->start();
……
}
在java代码中用了nativeStart()然后JNI中又调用了NativeInputManager的start方法。在
Native的InputManager中找到start的实现。
Framework/base/services/input/InputManager.cpp
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
……
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
……
}
这个方法就是在前面InputManager中的构造函数initialize中的两个线程运行起来。先看InputDispatcher线程运行的情况然后就是InputReader线程。
Framework/base/services/input/InputDispatcher.cpp
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
InputDispatcher线程调用了Dispatcher的dispatchOnce的方法。同样的InputReader线程也会调用Reader的ReaderOnce的方法。
Framework/base/services/input/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() {
……
dispatchOnceInnerLocked(&
nextWakeupTime);
……
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
dispatchOnceInnerLocked是处理input输入消息mLooper->pollOnce(timeoutMillis)是等待下次输入消息的事件。先看下消息在dispatchOnceInnerLocked函数中是如何处理的。
Framework/base/services/input/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
……
case EventEntry::TYPE_KEY
……
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
case EventEntry::
TYPE_MOTION: {
……
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
……
}
这个函数比较长input事件在android的上层通过两个队列来保存分别是InboundQueue和outboundQueue。当有input事件产生时候会判断InboundQueue是否为空如果事件不为空的话就从队列中取出这个input事件然后根据input事件的类型来分发事件给不同的处理函数比较常见的是KEY和Motion事件。不管是Key事件也好还是Motion事件都会调用dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false)这个函数来继续处理。
Framework/base/services/input/InputDispatcher.cpp
void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
……
prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
resumeWithAppendedMotionSample);
……
}
在这个函数中会继续调用prepareDispatchCycleLocked方法来继续处理。而在prepareDispatchCycleLocked中又会继续调用startDispatchCycleLocked(currentTime, connection)来进一步处理。
Framework/base/services/input/InputDispatcher.cpp
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection) {
……
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
status = connection->inputPublisher.publishKeyEvent
case EventEntry::TYPE_MOTION: {
……
status = connection->inputPublisher.publishMotionEvent
……
status = connection->inputPublisher.sendDispatchSignal();
……
}
这个函数主要是根据input事件的类型来分发给不同的函数去处理,如果是KEY类型的事件就调用inputPublisher类的publishKeyEvent,如果是MOTION类的事件就会调用inputPublisher
类的publishMotionEvent方法。并在最后发一个sendDispatchSignal。
Framework/base/libs/ui/InputTransport.cpp
status_t InputPublisher::publishInputEvent(
……
int ashmemFd = mChannel->getAshmemFd();
int result = ashmem_pin_region(ashmemFd, 0, 0);
……
mSemaphoreInitialized = true;
mSharedMessage->consumed = false;
mSharedMessage->type = type;
mSharedMessage->deviceId = deviceId;
mSharedMessage->source = source;
……
}
利用publisher中的publishInputEvent将input event写入共享内存。这边产生了事件另外一边必然会有个地方回去消费这个事件。注意到上面的代码中最后发送了一个sendDispatchSignal。
Framework/base/libs/ui/InputTransport.cpp
status_t InputPublisher::sendDispatchSignal() {
……
return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
……
}
这个函数直接调用了inputChannel的sendSignal方法。继续找到inputChannel的sendSignal实现。
Framework/base/libs/ui/InputTransport.cpp
status_t InputChannel::sendSignal(char signal) {
……
do {
nWrite = ::write(mSendPipeFd, & signal, 1);
}
while (nWrite == -1 && errno == EINTR);
……
}
而在注册InputChannel的时候就曾经注册了当Looper接收到了信号的一个回调函数。
Framework/base/services/input/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
……
mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
……
}
在handleReceiveCallback中作为回调函数然后调用InputConsumer的consume函数来消费从inputReader中读取过来的InputEvent。
Framework/base/core/jni/android_view_InputQueue.cpp
int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* data) {
……
status = connection->inputConsumer.consume(& connection->inputEventFactory, & inputEvent);
……
}
回过头来看之前的InputReader线程,在inputManager的start方法被调用了Input的线程也就开始运行了。
Framework/base/services/input/InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
在InputReader的loopOnce中会调用EventHub的getevents方法。这个方法会和linux内核的input子系统打交道。
Framework/base/services/input/InputReader.cpp
void InputReader::loopOnce() {
……
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
……
if (count) {
processEventsLocked(mEventBuffer, count);
}
……
}
这个函数主要通过EventHub的getEvents来获取input事件。
Framework/base/services/input/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
……
struct input_event readBuffer[bufferSize];
……
for (;;) {
……
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
……
- Android 输入系统架构 笔记1
- Android 输入系统架构 笔记1
- Android 输入系统架构 笔记2
- Android 输入系统架构 笔记3
- Android 输入系统架构 笔记4
- Android输入系统笔记
- Android学习笔记1-系统架构
- 学习笔记:Android系统架构
- Android系统架构学习笔记
- Android群英传学习笔记(1)--Android体系与系统架构
- 《Android群英传》笔记1——Android系统架构
- 《Android群英传》学习笔记 ---Android系统架构
- android 系统架构--1
- Android GPS学习笔记(1)—系统架构
- Android GPS学习笔记—系统架构
- 阅读徐宜生《Android群英传》的笔记——第1章 Android系统与系统架构
- Android 输入系统解析 (1)
- N-android输入系统1
- 使用Collections.sort()对List/ArrayList进行排序
- osg全屏下的输入法面板显示问题
- 8天玩转并行开发——第五天 同步机制(下)
- 震惊!130万研究生考生信息泄露!
- 阅读 TCMessageBox toast 源码小记
- Android 输入系统架构 笔记1
- 垂直导航/侧面导航
- SQL Server执行计划 解析
- iOS经验2:从服务起请求显示广告视图( 定时器 手势 滚动窗口)
- iOS - 常用到的图片功能:截取当前屏幕/选择本地图片/图片压缩
- PreloadDataCache(缓存)
- 【思想篇】工作流技术JBPM4.4开发入门(三)
- 云南苦荞茶、苦荞面、红茶滇红期待您的加盟
- 上海企业自媒体平台营销策略