Android中inputevent的分析.docx

上传人:b****9 文档编号:23321931 上传时间:2023-05-16 格式:DOCX 页数:12 大小:18.83KB
下载 相关 举报
Android中inputevent的分析.docx_第1页
第1页 / 共12页
Android中inputevent的分析.docx_第2页
第2页 / 共12页
Android中inputevent的分析.docx_第3页
第3页 / 共12页
Android中inputevent的分析.docx_第4页
第4页 / 共12页
Android中inputevent的分析.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

Android中inputevent的分析.docx

《Android中inputevent的分析.docx》由会员分享,可在线阅读,更多相关《Android中inputevent的分析.docx(12页珍藏版)》请在冰豆网上搜索。

Android中inputevent的分析.docx

Android中inputevent的分析

Android的InputEvent子系统的来龙去脉。

Android系统里面有很多小工具,运行这些工具,我们对它们有一个感性的认识,进而阅读和分析这些小工具源代码,再顺藤摸瓜,就可以把整个子系统的来龙去脉弄清楚。

1.运行toolbox的getevent工具。

#getevent-help

getevent-help

Usage:

getevent[-t][-n][-sswitchmask][-S][-v[mask]][-p][-q][-ccount][-r][device]

-t:

showtimestamps

-n:

don'tprintnewlines

-s:

printswitchstatesforgivenbits

-S:

printallswitchstates

-v:

verbositymask(errs=1,dev=2,name=4,info=8,vers=16,pos.events=32)

-p:

showpossibleevents(errs,dev,name,pos.events)

-q:

quiet(clearverbositymask)

-c:

printgivennumberofeventsthenexit

-r:

printrateeventsarereceived

#getevent-c20

getevent-c20

adddevice1:

/dev/input/event4

name:

"sensor-input"

adddevice2:

/dev/input/event3

name:

"88pm860x_hook"

adddevice3:

/dev/input/event2

name:

"88pm860x_on"

adddevice4:

/dev/input/event1

name:

"88pm860x-touch"

adddevice5:

/dev/input/event0

name:

"pxa27x-keypad"

/dev/input/event0:

0001006600000001

/dev/input/event0:

0000000000000000

/dev/input/event0:

0001006600000000

/dev/input/event0:

0000000000000000

/dev/input/event1:

0003000000000c48

/dev/input/event1:

0003000100000751

/dev/input/event1:

0001014a00000001

/dev/input/event1:

0000000000000000

/dev/input/event1:

0003000000000c67

/dev/input/event1:

00030001000006f9

/dev/input/event1:

0000000000000000

/dev/input/event1:

0003000000000c9e

/dev/input/event1:

000300010000069e

/dev/input/event1:

0000000000000000

/dev/input/event1:

0003000000000cc4

/dev/input/event1:

0003000100000620

/dev/input/event1:

0000000000000000

/dev/input/event1:

0003000000000ce8

/dev/input/event1:

00030001000005ba

/dev/input/event1:

0000000000000000

运行这个工具,然后按键或者滑动触摸屏,会看到程序会实时打印event。

从上面的输出来看,系统有5个input子系统。

它们分别是

adddevice1:

/dev/input/event4

name:

"sensor-input"

#Sensorinput子系统

adddevice2:

/dev/input/event3

name:

"88pm860x_hook"

#耳机Hook键子系统。

可支持接电话挂电话的耳机上面有一个按键,对应的就是这个input子系统。

adddevice3:

/dev/input/event2

name:

"88pm860x_on"

#开机键input子系统

adddevice4:

/dev/input/event1

name:

"88pm860x-touch"

#TouchScreeninput子系统

adddevice5:

/dev/input/event0

name:

"pxa27x-keypad"

#按键子系统,包括Home/Menu/Back等按键。

可以尝试多种event,实际感觉一下出来的log。

2.阅读getevent的代码。

代码为./core/toolbox/getevent.c

从代码中,我们知道,程序在while

(1)的一个死循环里,不断地在读取(select操作)/dev/input下面的文件,检查是否Kernel往里面更新内容,如果有内容更新,就把它打印出来。

并且从代码中,我们还知道,任何一个event都有三种属性,type,code,value.

while

(1){

pollres=poll(ufds,nfds,-1);

//printf("poll%d,returned%d\n",nfds,pollres);

if(ufds[0].revents&POLLIN){

read_notify(device_path,ufds[0].fd,print_flags);

}

for(i=1;i

if(ufds[i].revents){

if(ufds[i].revents&POLLIN){

res=read(ufds[i].fd,&event,sizeof(event));

if(res<(int)sizeof(event)){

fprintf(stderr,"couldnotgetevent\n");

return1;

}

if(get_time){

printf("%ld-%ld:

",event.time.tv_sec,event.time.tv_usec);

}

if(print_device)

printf("%s:

",device_names[i]);

printf("%04x%04x%08x",event.type,event.code,event.value);

if(sync_rate&&event.type==0&&event.code==0){

int64_tnow=event.time.tv_sec*1000000LL+event.time.tv_usec;

if(last_sync_time)

printf("rate%lld",1000000LL/(now-last_sync_time));

last_sync_time=now;

}

printf("%s",newline);

if(event_count&&--event_count==0)

return0;

}

}

}

3.问题来了,AndroidFramework是否也是一样的原理呢?

猜测应该是一样的才对,不然这个工具就没有调试的价值了。

我们来阅读和分析framework中inputevent的相关代码。

我们从Kernel层往上看,先看看Framework中,直接操纵/dev/input设备的代码。

在.frameworks/base/libs/ui/EventHub.cpp中,我们看到跟getevent工具类似的代码。

boolEventHub:

:

getEvent(int32_t*outDeviceId,int32_t*outType,

int32_t*outScancode,int32_t*outKeycode,uint32_t*outFlags,

int32_t*outValue,nsecs_t*outWhen)

{

....

while

(1){

....

release_wake_lock(WAKE_LOCK_ID);

pollres=poll(mFDs,mFDCount,-1);

acquire_wake_lock(PARTIAL_WAKE_LOCK,WAKE_LOCK_ID);

if(pollres<=0){

if(errno!

=EINTR){

LOGW("selectfailed(errno=%d)\n",errno);

usleep(100000);

}

continue;

}

....

//mFDs[0]isusedforinotify,soprocessregulareventsstartingatmFDs[1]

for(i=1;i

if(mFDs[i].revents){

LOGV("reventsfor%d=0x%08x",i,mFDs[i].revents);

if(mFDs[i].revents&POLLIN){

res=read(mFDs[i].fd,&iev,sizeof(iev));

if(res==sizeof(iev)){

LOGV("%sgot:

t0=%d,t1=%d,type=%d,code=%d,v=%d",

mDevices[i]->path.string(),

....

}

4.那么framework中那个模块再调用EventHub呢,接着往下查。

在framework目录中,输入下面的命令查找

#find.-name"*.cpp"|grep-vEventHub|xargsgrepEventHub

./base/services/jni/com_android_server_KeyInputQueue.cpp:

#include

./base/services/jni/com_android_server_KeyInputQueue.cpp:

staticspgHub;

./base/services/jni/com_android_server_KeyInputQueue.cpp:

sphub=gHub;

./base/services/jni/com_android_server_KeyInputQueue.cpp:

hub=newEventHub;

./base/services/jni/com_android_server_KeyInputQueue.cpp:

sphub=gHub;

./base/services/jni/com_android_server_KeyInputQueue.cpp:

hub=newEventHub;

5.从查找结果中得知,在jni文件com_android_server_KeyInputQueue.cpp文件中有对EventHub进行调用。

打开并阅读com_android_server_KeyInputQueue.cpp文件得知,在下面的函数中调用了EventHub的getEvent函数

staticjboolean

android_server_KeyInputQueue_readEvent(JNIEnv*env,jobjectclazz,

jobjectevent)

{

gLock.lock();

sphub=gHub;

if(hub==NULL){

hub=newEventHub;

gHub=hub;

}

gLock.unlock();

int32_tdeviceId;

int32_ttype;

int32_tscancode,keycode;

uint32_tflags;

int32_tvalue;

nsecs_twhen;

boolres=hub->getEvent(&deviceId,&type,&scancode,&keycode,

&flags,&value,&when);

env->SetIntField(event,gInputOffsets.mDeviceId,(jint)deviceId);

env->SetIntField(event,gInputOffsets.mType,(jint)type);

env->SetIntField(event,gInputOffsets.mScancode,(jint)scancode);

env->SetIntField(event,gInputOffsets.mKeycode,(jint)keycode);

env->SetIntField(event,gInputOffsets.mFlags,(jint)flags);

env->SetIntField(event,gInputOffsets.mValue,value);

env->SetLongField(event,gInputOffsets.mWhen,

(jlong)(nanoseconds_to_milliseconds(when)));

returnres;

}

6.根据jni的调用规则,在本文件中查找对于的java函数。

staticJNINativeMethodgInputMethods[]={

/*name,signature,funcPtr*/

{"readEvent","(Landroid/view/RawInputEvent;)Z",

(void*)android_server_KeyInputQueue_readEvent},

....

7.接着顺藤摸瓜,找到对应的java文件,base/services/java/com/android/server/KeyInputQueue.java

privatestaticnativebooleanreadEvent(RawInputEventoutEvent);

在一个线程中会调用readEvent函数。

ThreadmThread=newThread("InputDeviceReader"){

publicvoidrun(){

if(DEBUG)Slog.v(TAG,"InputDeviceReader.run()");

android.os.Process.setThreadPriority(

android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

RawInputEventev=newRawInputEvent();

while(true){

try{

InputDevicedi;

//block,doesn'treleasethemonitor

readEvent(ev);

booleansend=false;

booleanconfigChanged=false;

if(false){

Slog.i(TAG,"Inputevent:

dev=0x"

+Integer.toHexString(ev.deviceId)

+"type=0x"+Integer.toHexString(ev.type)

+"scancode="+ev.scancode

+"keycode="+ev.keycode

+"value="+ev.value);

}

8.那是谁启动这个线程呢?

查找mThread变量,得知在KeyInputQueue的构造函数中会启动这个线程。

KeyInputQueue(Contextcontext,HapticFeedbackCallbackhapticFeedbackCallback){

if(MEASURE_LATENCY){

lt=newLatencyTimer(100,1000);

}

Resourcesr=context.getResources();

BAD_TOUCH_HACK=r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);

JUMPY_TOUCH_HACK=r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);

mHapticFeedbackCallback=hapticFeedbackCallback;

readExcludedDevices();

PowerManagerpm=(PowerManager)context.getSystemService(

Context.POWER_SERVICE);

mWakeLock=pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,

"KeyInputQueue");

mWakeLock.setReferenceCounted(false);

mFirst=newQueuedEvent();

mLast=newQueuedEvent();

mFirst.next=mLast;

mThread.start();

}

9.那这个KeyInputQueue是在哪里被实例化呢?

而且查看KeyInputQueue类的声明,得知它是一个abstractclass.

publicabstractclassKeyInputQueue

{

.....

}

说明它肯定会被某个类继承.接着查找。

/frameworks$find.-name"*.java"|grep-vKeyInputQueue|xargsgrepKeyInputQueue

./policies/base/phone/com/android/internal/policy/impl/KeyguardViewMediator.java:

*{@linkcom.android.server.KeyInputQueue}'sand{@linkandroid.view.WindowManager}'s.

./base/services/java/com/android/server/PowerManagerService.java:

&&!

"KeyInputQueue".equals(tag))){

./base/services/java/com/android/server/WindowManagerService.java:

importcom.android.server.KeyInputQueue.QueuedEvent;

./base/services/java/com/android/server/WindowManagerService.java:

implementsWatchdog.Monitor,KeyInputQueue.HapticFeedbackCallback{

./base/services/java/com/android/server/WindowManagerService.java:

returnKeyInputQueue.getSwitchState(sw);

./base/services/java/com/android/server/WindowManagerService.java:

returnKeyInputQueue.getSwitchState(devid,sw);

./base/services/java/com/android/server/WindowManagerService.java:

returnKeyInputQueue.hasKeys(keycodes,keyExists);

./base/services/java/com/android/server/WindowManagerService.java:

privateclassKeyQextendsKeyInputQueue

./base/services/java/com/android/server/WindowManagerService.java:

implementsKeyInputQueue.FilterCallback{

./base/services/java/com/android/server/InputDevice.java:

//ForusebyKeyInputQueueforkeepingtrackofthecurrenttouch

./base/services/java/com/android/server/InputDevice.java:

if(KeyInputQueue.BAD_TOUCH_HACK){

./base/services/java/com/android/server/InputDevice.java:

Slog.i("KeyInputQueue","Updating:

"+currentMove);

./base/services/java/com/android/server/InputDevice.java:

Slog.i("KeyInputQueue","Updating:

"+currentMove);

10.从上面的查找结果得知,会在WindowManagerService.java中有一个KeyQ类继承KeyInputQueue类,再在这个文件中查找KeyQ类在哪里定义并实例化的,找到在其构造函数里实例化的。

privateWindowManagerService(Contextcontext,PowerManagerService

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1