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
相關推薦
Android8.0 事件輸入系統
Android 輸入子系統名義上是由遍歷系統多個層的事件管道組成,在最低層,物理輸入裝置會生成描述狀態更改(例如按鍵按壓和觸控接觸點)的訊號。裝置韌體以某種方式編碼和傳輸這些訊號,例如向系統傳送 USB HID 報告或在 I2C 總線上產生中斷。 然後,訊號由 Linux 核心中的裝置驅
Android8.0 事件輸入系統
Android 輸入子系統名義上是由遍歷系統多個層的事件管道組成,在最低層,物理輸入裝置會生成描述狀態更改(例如按鍵按壓和觸控接觸點)的訊號。裝置韌體以某種方式編碼和傳輸這些訊號,例如向系統傳送 USB HID 報告或在 I2C 總線上產生中斷。
然後,訊號由
Android 4 0 事件輸入 Event Input 系統
1. TouchScreen功能在Android4.0下不工作 原來在Android2.3.5下能正常工作的TouchScreen功能,移植到Android 4.0就不能正常工作了。憑直覺,Android4.0肯定有鬼。真是不看不知道,一看嚇一跳。在Android
Android8.0之後呼叫系統相機崩潰問題
1.首先需要在manifest.xml中配置provider:
<!--android8.0需要的配置,主要是呼叫相機-->
<provider
android:authorities="包名.fileprovider"
android
Android輸入系統(一)輸入事件傳遞流程和InputManagerService的誕生
本文首發於微信公眾號「劉望舒」 原文連結 : Android輸入系統的事件傳遞流程和IMS的誕生
相關文章 解析WMS系列 View體系系列
前言
很多同學可能會認為輸入系統是不是和View的事件分發有些關聯,確實是有些關聯,只不過View事件分發只能算是輸入系統事件傳遞的一部分。這個系列講的
Android8.0 儲存系統
Android 一直在不斷髮展,可支援各種儲存裝置型別和功能。所有 Android 版本均支援配有傳統儲存(包括行動式儲存和內建儲存)的裝置。行動式儲存是指物理介質(如 SD 卡或 USB 裝置),用於進行臨時資料傳輸/檔案儲存。物理介質可以隨裝置一起保留更長時間,但並非固定在裝置上,可
Android輸入系統(二)IMS的啟動過程和輸入事件的處理
本文首發於 劉望舒的部落格 地址:liuwangshu.cn/framework/i…
關聯絡列 解析WMS系列 深入理解JNI系列 輸入系統系列
前言
在上一篇文章中,我們學習了IMS的誕生(建立),IMS建立後還會進行啟動,這篇文章我們來學習IMS的啟動過程和輸入事件的處理。
1.IMS
Android8.0系統通知欄的適配
Android8.0系統通知欄的每條通知都有一個對應的渠道,使用者可以選擇是否要關閉哪個渠道的通知。下面這張圖就有兩個通知渠道,由使用者自由選擇是否關閉哪一條渠道的通知,就能避免一些垃圾推送訊息的打擾。
如果將專案中的SDK版本指定到了26或者更高,還不進行通知
Android8.0 儲存系統
Android 一直在不斷髮展,可支援各種儲存裝置型別和功能。所有 Android 版本均支援配有傳統儲存(包括行動式儲存和內建儲存)的裝置。行動式儲存是指物理介質(如 SD 卡或 USB 裝置),用於進行臨時資料傳輸/檔案儲存。物理介質可以隨裝置一起保留更長時
Android8.0 Camera系統架構(一)
隨著Android系統的不斷升級,相機子系統框架也在不斷進化,由最初的API1和HAL1到現在的API2和HAL3,由最初簡單的拍照,錄製到現在的連拍,AI人像;可以說是架構上變動最大最頻繁的子系統。很多裝置仍然依賴相機 HAL1,因此 Android 7.0
Android8.0 系統原始碼編譯
環境
編譯環境:Ubuntu18.04
硬體環境:ThinkPad
編譯準備
安裝jdk
sudo apt-get update
sudo apt-get install openjdk-8-jdk
sudo apt-get
Android8.0 Binder之面向系統服務(一)
Android碎片化問題一直是OS更新的痛點,Google在Android8.0引入的Treble旨在解決Android長期以來碎片化嚴重的問題,Treble計劃將Binder擴充套件為三角結構,分別對應dev/binder,dev/vndbinder,dev/
關於android8.0.0以上系統,安裝檔案不成功的問題 解決
今天遇到bug,
1.專案生成的二維碼連結是https的,我用微信掃一掃一步步執行下去。 下載不下來,頁面空白。
解決: 用手機自帶的掃一掃軟體直接掃描 可以下載成功
2.在華為榮耀V8,小米8等機型上出現“程式未檢測到可以開啟此檔案的應用“,
原因:
Androi
android5.0輸入系統新增自定義按鍵
申明:本按鍵新增沒有用到全志sys_config.fex配置io。
Board:全志R16
SDK:Android KitKat 4.4.2、Linux-3.4
開發內容:自定義按鍵名為SOCHIP_EXT1,接在R16開發板的GPIOB7口。
Activity是如何接收到touch事件的(視窗與使用者輸入系統)
前兩個問題在前兩篇文章中已經分析,在這篇文章中我們以第三個問題為切入點,簡單分析一下視窗與使用者輸入的關係。
Touch事件是如何分發到Activity上來的?
正常的思路是直接去尋找Activity 的dispatchTouchEvent方法,
Android Activity啟動流程(基於Android8.0系統)
主要物件介紹
ActivityManagerService:負責系統中所有Activity的生命週期;
Activi
輸入一組整數,0結束輸入,之後輸出輸入的最大的和最小的整數.【思路】
cnblogs amp println system ack rgs int 輸入 !=
package com.ykmimi.new1;
/**
* 輸入一組整數,0結束輸入,之後輸出輸入的最大的和最小的整數.
*/
import java.util.Scanner
Android音視頻通話過程中最小化成懸浮框的實現(類似Android8.0畫中畫效果)
apk 添加 touch null cas 如果 動態添加 int sta 關於音視頻通話過程中最小化成懸浮框這個功能的實現,網絡上類似的文章很多,但是好像還沒看到解釋的較為清晰的,這裏因為項目需要實現了這樣的一個功能,今天我把它記錄下來,一方面為了以後用到便於自己查閱,一
Android7.0調用系統相機拍照、讀取系統相冊照片+CropImageView剪裁照片
alpha pri process 點擊事件 self tps 而在 center ase Android手機拍照、剪裁,並非那麽簡單
簡書地址:[我的簡書–T9的第三個三角]
前言 項目中,基本都有用戶自定義頭像或自定義背景的功能,實現方法一般都是調用
慕課網 微信服務號+Yii 2.0構建商城系統全棧應用 百度雲網盤分享
div .com alt 商城系統 分享 棧應用 微信 info yii 慕課網 微信服務號+Yii 2.0構建商城系統全棧應用 百度雲網盤分享
慕課網 微信服務號+Yii 2.0構建商城系統全棧應用 百度雲網盤分享