Android8.0 事件輸入系統
Android 輸入子系統名義上是由遍歷系統多個層的事件管道組成,在最低層,物理輸入裝置會生成描述狀態更改(例如按鍵按壓和觸控接觸點)的訊號。裝置韌體以某種方式編碼和傳輸這些訊號,例如向系統傳送 USB HID 報告或在 I2C 總線上產生中斷。 然後,訊號由 Linux 核心中的裝置驅動程式解碼。Linux 核心為許多標準的外圍裝置提供驅動程式,特別是那些符合 HID 協議的外圍裝置。然而,原始裝置製造商 (OEM) 通常必須為在低級別緊密整合到系統的嵌入式裝置(如觸控式螢幕)提供自定義驅動程式。
輸入裝置驅動程式負責通過 Linux 輸入協議將裝置特定訊號轉換為標準輸入事件格式。Linux 輸入協議在 linux/input.h 核心標頭檔案中定義了一組標準事件型別和程式碼。這樣一來,核心之外的元件就不需要關注物理掃描程式碼、HID 用途、I2C 訊息、GPIO 引腳等方面的詳細資訊。 接下來,Android EventHub 元件通過開啟與每個輸入裝置關聯的 evdev 驅動程式從核心讀取輸入事件。然後,Android InputReader 元件根據裝置類別解碼輸入事件,並生成 Android 輸入事件流。
1. 事件輸入管理服務
frameworks\base\services\java\com\android\server\SystemServer.java
private void startOtherServices() {
......
inputManager = new InputManagerService(context); //1.輸入法服務
wm = WindowManagerService.main(context, inputManager, //2.窗體管理服務
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
......
}
frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper()); //處理輸入事件
......
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); //初始化
LocalServices.addService(InputManagerInternal.class, new LocalService());
......
}
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);
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
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) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
......
sp<EventHub> eventHub = new EventHub(); //事件集線器
mInputManager = new InputManager(eventHub, this, this); //輸入管理者
}
frameworks\native\services\inputflinger\InputManager.cpp
InputManager::InputManager(
const sp<InputReaderInterface>& reader,
const sp<InputDispatcherInterface>& dispatcher) :
mReader(reader),
mDispatcher(dispatcher) {
initialize();
}
frameworks\native\services\inputflinger\InputManager.cpp
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
WindowManagerPolicy policy) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
onlyCore, policy), 0);
return sInstance;
}
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java 建立事件輸入通道
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
......
if(mInputManager != null) {
//建立事件輸入通道
final InputChannel inputChannel = mInputManager.monitorInput(TAG_WM);
mPointerEventDispatcher = inputChannel != null
? new PointerEventDispatcher(inputChannel) : null;
} else {
mPointerEventDispatcher = null;
}
......
}
frameworks\base\services\core\java\com\android\server\input\InputManagerService.java 建立Channel並由com_android_server_input_InputManagerService註冊
public InputChannel monitorInput(String inputChannelName) {
//建立並註冊通道
InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
inputChannels[0].dispose(); // don't need to retain the Java object reference
return inputChannels[1];
}
frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//新建通道
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
//新建處理控制代碼
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
//註冊通道和處理控制代碼
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
}
frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp 最終呼叫InputDispatch去註冊輸入通道
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}
frameworks\native\services\inputflinger\InputDispatcher.cpp 實際在派發器中註冊, Connection是InputDispatcher內部的一個類結構
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
//合成一個通道連線
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection); //fd對映
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); //加入Looper
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
2. 輸入事件採集
frameworks\base\services\core\java\com\android\server\input\InputManagerService.java
public void start() { ...... nativeStart(mPtr); ......}
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();
}
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;
}
frameworks\native\services\inputflinger\InputReader.cpp
bool InputReaderThread::threadLoop() {
mReader->loopOnce(); //開始
return true;
}
frameworks\native\services\inputflinger\InputReader.cpp
void InputReader::loopOnce() {
......
//採集輸入事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count); //處理事件
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) { //超時
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices); //獲取輸入裝置
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices); //通知輸入裝置
}
//重新整理事件監聽佇列
mQueuedListener->flush();
}
frameworks\native\services\inputflinger\EventHub.cpp epoll 是Linux下多路複用IO介面select/poll的增強版本,它能顯著提高程式在大量併發連線中只有少量活躍的情況下的系統CPU利用率。另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被核心IO事件非同步喚醒而加入Ready佇列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸發(Level Triggered)外,還提供了邊緣觸發(Edge Triggered),這就使得使用者空間程式有可能快取IO狀態,減少epoll_wait/epoll_pwait的呼叫,提高應用程式效率。 Inotify 是一個 Linux 核心特性,它監控檔案系統,並且及時向專門的應用程式發出相關的事件警告,比如刪除、讀、寫和解除安裝操作等。
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
//建立EPOLL,多路IO複用
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
//建立Inotify
mINotifyFd = inotify_init();
//觀察檔案描述符
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d",
DEVICE_PATH, errno);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN; //事件
eventItem.data.u32 = EPOLL_ID_INOTIFY;ea
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0]; //讀喚醒描述符
mWakeWritePipeFd = wakeFds[1]; // 寫喚醒描述符
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
int major, minor;
getLinuxRelease(&major, &minor);
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
frameworks\native\services\inputflinger\EventHub.cpp 獲取系統輸入原始事件
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer; //原始事件
size_t capacity = bufferSize; //緩衝容量
bool awoken = false;
for (;;) { //開始迴圈
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
.......
// Report any devices that had last been added/removed.
//裝置刪減
while (mClosingDevices) {
Device* device = mClosingDevices;
mClosingDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
//掃描裝置
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
......
// Grab the next input event.
//獲取下一次輸入事件
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.u32 == EPOLL_ID_WAKE) { //喚醒
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); //讀取資料
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
<