This article analyzes the ins and outs of the android input event subsystem.
There are many gadgets in the Android system. running these tools, we have a perceptual knowledge of them, and then we can read and analyze the source code of these gadgets. Then we can figure out the ins and outs of the entire subsystem.
1. Run the getevent tool of toolbox.
# Getevent-help
Getevent-help
Usage: getevent [-T] [-N] [-s switchmask] [-S] [-V [mask] [-p] [-q] [-c count] [- r] [device]
-T: Show time stamps
-N: Don't print newlines
-S: Print switch states for given bits
-S: print all switch states
-V: verbosity mask (errs = 1, Dev = 2, name = 4, info = 8, Vers = 16, POS. Events = 32)
-P: show possible events (errs, Dev, name, POS. Events)
-Q: Quiet (clear verbosity mask)
-C: Print given number of events then exit
-R: Print rate events are already ed
# Getevent-C 20
Getevent-C 20
Add device 1:/dev/input/event4
Name: "sensor-input"
Add device 2:/dev/input/event3
Name: "88pm860x_hook"
Add device 3:/dev/input/event2
Name: "88pm860x_on"
Add Device 4:/dev/input/event1
Name: "88pm860x-touch"
Add Device 5:/dev/input/event0
Name: "pxa27x-keypad"
/Dev/input/event0: 0001 0066 00000001
/Dev/input/event0: 0000 0000 00000000
/Dev/input/event0: 0001 0066 00000000
/Dev/input/event0: 0000 0000 00000000
/Dev/input/event1: 0003 0000 00000c48
/Dev/input/event1: 0003 0001 00000751
/Dev/input/event1: 0001 014a 00000001
/Dev/input/event1: 0000 0000 00000000
/Dev/input/event1: 0003 0000 00000c67
/Dev/input/event1: 0003 0001 000006f9
/Dev/input/event1: 0000 0000 00000000
/Dev/input/event1: 0003 0000 00000c9e
/Dev/input/event1: 0003 0001 0000069e
/Dev/input/event1: 0000 0000 00000000
/Dev/input/event1: 0003 0000 00000cc4
/Dev/input/event1: 0003 0001 00000620
/Dev/input/event1: 0000 0000 00000000
/Dev/input/event1: 0003 0000 00000ce8
/Dev/input/event1: 0003 0001 000005ba
/Dev/input/event1: 0000 0000 00000000
Run the tool, press the button or slide the touch screen, and the program prints the event in real time. From the above output, the system has five input subsystems. They are
Add device 1:/dev/input/event4
Name: "sensor-input"
# Sensor input subsystem
Add device 2:/dev/input/event3
Name: "88pm860x_hook"
# Earphone hook System. There is a button on the headset that supports phone calls, corresponding to the input subsystem.
Add device 3:/dev/input/event2
Name: "88pm860x_on"
# Enable the input subsystem
Add Device 4:/dev/input/event1
Name: "88pm860x-touch"
# Touch screen input subsystem
Add Device 5:/dev/input/event0
Name: "pxa27x-keypad"
# Key subsystem, including home/menu/back.
You can try a variety of events and actually feel the log.
2. Read the getevent code. Code:./CORE/toolbox/getevent. c
From the code, we know that the program is constantly reading (Select Operation) in an endless loop of while (1)/Dev/InputCheck whether the Kernel updates the content in the following file. If any content is updated, print it out. We also know from the code that any event has three attributes: type, code, and value.
While (1 ){
Pollres = poll (ufds, NFDs,-1 );
// Printf ("poll % d, returned % d/N", NFDs, pollres );
If (ufds [0]. revents & Pollin ){
Read_policy (device_path, ufds [0]. FD, print_flags );
}
For (I = 1; I <NFDs; 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, "cocould not get event/N ");
Return 1;
}
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_t now = event. Time. TV _sec * 000000ll + event. Time. TV _usec;
If (last_sync_time)
Printf ("rate % LLD", interval 00ll/(now-last_sync_time ));
Last_sync_time = now;
}
Printf ("% s", newline );
If (event_count & -- event_count = 0)
Return 0;
}
}
}
3. The question is, does the android framework have the same principle ?? The guess should be the same, otherwise the tool will have no value for debugging.
Let's read and analyze the input event code in the framework.
From the perspective of the kernel layer, Let's first look at the code of the/dev/input device in the framework.
In. Frameworks/base/libs/UI/eventhub. cpp, we can see code similar to the getevent tool.
Bool eventhub: 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 ("select failed (errno = % d)/n", errno );
Usleep (100000 );
}
Continue;
}
....
// MFDs [0] is used for inotify, so process regular events starting at MFDs [1]
For (I = 1; I <mfdcount; I ++ ){
If (MFDs [I]. revents ){
Logv ("revents for % 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 ("% s got: T0 = % d, T1 = % d, type = % d, code = % d, V = % d ",
Mdevices [I]-> path. String (),
....
}
4. Then, the module in the Framework calls eventhub again, and then queries it.
In the Framework directory, enter the following command to search
# Find.-Name "*. cpp" | grep-V eventhub | xargs grep eventhub
./Base/services/JNI/com_android_server_keyinputqueue.cpp: # include <UI/eventhub. h>
./Base/services/JNI/com_android_server_keyinputqueue.cpp: static sp <eventhub> ghub;
./Base/services/JNI/com_android_server_keyinputqueue.cpp: sp <eventhub> hub = ghub;
./Base/services/JNI/com_android_server_keyinputqueue.cpp: hub = new eventhub;
./Base/services/JNI/com_android_server_keyinputqueue.cpp: sp <eventhub> hub = ghub;
./Base/services/JNI/com_android_server_keyinputqueue.cpp: hub = new eventhub;
5. We learned from the search results that eventhub is called in the JNI file com_android_server_keyinputqueue.cpp.
Open and read the com_android_server_keyinputqueue.cpp file. The following function calls the getevent function of eventhub.
Static jboolean
Android_server_keyinputqueue_readevent (jnienv * ENV, jobject clazz,
Jobject event)
{
Glock. Lock ();
Sp <eventhub> hub = ghub;
If (hub = NULL ){
Hub = new eventhub;
Ghub = hub;
}
Glock. Unlock ();
Int32_t DeviceID;
Int32_t type;
Int32_t scancode, keycode;
Uint32_t flags;
Int32_t value;
Nsecs_t when;
Bool res = 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 )));
Return res;
}
6. Search for Java functions in this file based on JNI call rules.
Static jninativemethod ginputmethods [] = {
/* Name, signature, funcptr */
{"Readevent", "(landroid/View/rawinputevent;) Z ",
(Void *) android_server_keyinputqueue_readevent },
....
7. Find the corresponding Java file, base/services/Java/COM/Android/Server/keyinputqueue. Java
Private Static native Boolean readevent (rawinputevent outevent );
The readevent function is called in a thread.
Thread mthread = new thread ("inputdevicereader "){
Public void run (){
If (Debug) slog. V (TAG, "inputdevicereader. Run ()");
Android. OS. process. setthreadpriority (
Android. OS. process. thread_priority_urgent_display );
Rawinputevent EV = new rawinputevent ();
While (true ){
Try {
Inputdevice di;
// Block, doesn' t release the monitor
Readevent (EV );
Boolean send = false;
Boolean configchanged = false;
If (false ){
Slog. I (TAG, "input event: Dev = 0x"
+ Integer. tohexstring (EV. DeviceID)
+ "Type = 0x" + integer. tohexstring (EV. type)
+ "Scancode =" + eV. scancode
+ "Keycode =" + eV. keycode
+ "Value =" + eV. value );
}
8. Who started this thread ??? Find the mthread variable and find that the thread will be started in the keyinputqueue constructor.
Keyinputqueue (context, hapticfeedbackcallback){
If (measure_latency ){
Lt = new latencytimer (100,100 0 );
}
Resources r = 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 ();
Powermanager PM = (powermanager) Context. getsystemservice (
Context. power_service );
Mwakelock = PM. newwakelock (powermanager. partial_wake_lock,
"Keyinputqueue ");
Mwakelock. setreferencecounted (false );
Mfirst = new queuedevent ();
Mlast = new queuedevent ();
Mfirst. Next = mlast;
Mthread. Start ();
}
9. Where is the keyinputqueue instantiated?
Check the keyinputqueue class declaration and find that it is an abstract class.
Public abstract class keyinputqueue
{
.....
}
It indicates that it will be inherited by a class and then searched.
/Frameworks $ find.-Name "*. Java" | grep-V keyinputqueue | xargs grep keyinputqueue
. /Policies/base/phone/COM/Android/Internal/policy/impl/keyguardviewmediator. java: * {@ link COM. android. server. keyinputqueue}'s and {@ link android. view. windowmanager}'s.
./Base/services/Java/COM/Android/Server/powermanagerservice. Java :&&! "Keyinputqueue". Equals (TAG ))){
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: Import com. Android. server. keyinputqueue. queuedevent;
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: Implements watchdog. Monitor, keyinputqueue. hapticfeedbackcallback {
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: Return keyinputqueue. getswitchstate (SW );
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: Return keyinputqueue. getswitchstate (devid, SW );
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: Return keyinputqueue. haskeys (keycodes, keyexists );
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: private class keyq extends keyinputqueue
./Base/services/Java/COM/Android/Server/windowmanagerservice. Java: Implements keyinputqueue. filtercallback {
./Base/services/Java/COM/Android/Server/inputdevice. Java: // for use by keyinputqueue for keeping track of the current touch
./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. according to the above search results, it will be found in windowmanagerservice. in Java, there is a keyq class that inherits the keyinputqueue class. In this file, find where the keyq class is defined and instantiated and find the keyq class instantiated in its constructor.
Private windowmanagerservice (context, powermanagerservice pm,
Boolean haveinputmethods ){
If (measure_latency ){
Lt = new latencytimer (100,100 0 );
}
....
Mqueue = new keyq ();
Minputthread = new inputdispatcherthread ();
Policythread thr = new policythread (mpolicy, this, context, PM );
...
}
At this point, the process of the input event framework is basically completed. Windowmanagerservice is a service started in the system server process. It runs as soon as it is started. Of course, its constructor runs as soon as it is started.
The process is as follows:
Windowmanagerservice
|
|
//
Keyq
|
|
//
Keyinputqueue
|
|
//
Eventhub
|
|
//
Kernel device (/dev/input)
Subsequent articles will introduce the implementation of/dev/input in the kernel.
Http://blog.csdn.net/learnrose/article/details/6236890 #