In the frameworks layer of the previous Linux/android--input system Inputmanagerservice (vi) here describes the startup of the Android layer input service, which initiates a thread that reads from the underlying event events.
The kernel layer of the linux/android--input system interacts with the frameworks layer (v) to interact with a event%d device file, which means that the Android layer reads event%d to get the event, This job is inputreader.
Writing is not easy, reprint need to indicate the source: http://blog.csdn.net/jscese/article/details/42739197
GetEvents:
This is running in the Inputread thread, the previous article has introduced, literally means to get the event, implemented in/frameworks/base/services/input/ In EventHub.cpp, the function is long and lists several important:
size_t eventhub::getevents (int timeoutmillis, rawevent* buffer, size_t buffersize) {... struct input_event readbuffer[b Uffersize]; rawevent* event = buffer, ... if (mneedtoscandevices) {//This is true at Eventhub initial Mneedtoscandevices = False ; Scandeviceslocked (); Scan to open device, follow up to see Mneedtosendfinisheddevicescan = true; while (mopeningdevices! = NULL) {//This pointer has a point that indicates that some input devices are open above device* device = mopeningdevices; Initialize an add Event,type to device_added alogv ("Reporting device opened:id=%d, name=%s\n", device-& Gt;id, device->path.string ()); Mopeningdevices = device->next; Event->when = Now; Event->deviceid = Device->id = = Mbuiltinkeyboardid? 0:device->id; Event->type = device_added; event + = 1; Mneedtosendfinisheddevicescan = true; if (--capacity = = 0) {break; } } ... while (Mpendingeventindex < Mpendingeventcount) {//This is an array of epoll_event types for processing multiple input event cons t struct epoll_event& eventitem = mpendingeventitems[mpendingeventindex++]; device* device = mdevices.valueat (Deviceindex); The above will add the open device to this vector if (eventitem.events & Epollin) {int32_t readsize = Read (devi CE->FD, Readbuffer,//This has been mentioned before. Will eventually be called to read sizeof (struct input_event) * capacity in Evdev);.. for (size_t i = 0; i < count; i++) {const struct input_event& Iev = readbuffer[i]; Here to read the above input_event transformed here rawevent Event->deviceid = deviceId; Event->type = Iev.type; Event->code = Iev.code; Event->value = Iev.value; event + = 1; }... int pollresult = epoll_wait (MEPOLLFD, Mpendingeventitems, epoll_max_events, TimeoutMillis); //For waiting to monitor if there is an event readable ... }//All done, return the number of events we read. return event-buffer; Subtraction of pointers, number of elements in this array}
Scandeviceslocked:
The next step is to open an input device file, configure it and abstract it to an Android layer on this side of input devices:
void eventhub::scandeviceslocked () { status_t res = scandirlocked (device_path); if (Res < 0) { aloge ("Scan dir failed for%s\n", device_path);//The PATH here is "/dev/input" } if ( Mdevices.indexofkey (VIRTUAL_KEYBOARD_ID) < 0) { createvirtualkeyboardlocked (); }}
Continue looking down will read the directory under the file, and call into opendevicelocked open, this function is also relatively long, focus on several places first:
status_t eventhub::opendevicelocked (const char *devicepath) {char buffer[80]; ALOGV ("Opening Device:%s", DevicePath); int fd = open (DevicePath, O_RDWR | O_CLOEXEC); if (FD < 0) {Aloge ("Could not open%s,%s\n", DevicePath, Strerror (errno)); return-1; } ...//is to obtain some relevant parameter information based on the Open FD//Allocate device. (The device object takes ownership of the FD at this point.) int32_t deviceId = mnextdeviceid++; device* device = new device (FD, DeviceId, String8 (devicePath), identifier); Here according to the parameters obtained from the previous new into a device, is initially opened to complete the abstraction into a device ...//Load the configuration file for the device. loadconfigurationlocked (device); This is important to load the configuration information for this device, which will be followed by the configuration to define the rules ...//is a series of judgment initialization, which is more important is device->classes this variable, represents the input device type, is the keyboard, mouse, touch screen ...//Register with Epoll. struct Epoll_event eventitem; Registered Epoll memset (&eventitem, 0, sizeof (Eventitem)); Eventitem.events = Epollin; EventItem.data.u32 = deviceId; if (Epoll_ctl (MEPOLLFD,Epoll_ctl_add, FD, &eventitem)) {Aloge ("Could not ADD device FD to Epoll instance. errno=%d ", errno); Delete device; return-1; } ... adddevicelocked (device); Add to Keyedvector}
This inside has a lot of original printing, want to understand deeply can let go debugging to see, here do not introduce more, can look under load configuration that function loadconfigurationlocked:
void eventhub::loadconfigurationlocked (device* Device) { Device->configurationfile = Getinputdeviceconfigurationfilepathbydeviceidentifier ( //based on some of the device information obtained above, go further to the config file device-> identifier, input_device_configuration_file_type_configuration); if (Device->configurationfile.isempty ()) { alogd ("No input device configuration file found for device '%s '."), device->identifier.name.string ()); } else { status_t status = Propertymap::load (Device->configurationfile, //After finding, save the config file for this device &device->configuration); if (status) { Aloge ("Error loading input device configuration file for device '%s '.") Using the default configuration. ", device->identifier.name.string ());}}}
Next see how to find the corresponding config file, here is called to the/frameworks/base/libs/androidfw/inputdevice.cpp:
String8 getinputdeviceconfigurationfilepathbydeviceidentifier (const inputdeviceidentifier& DeviceIdentifier, Inputdeviceconfigurationfiletype type) {if (Deviceidentifier.vendor!=0 && deviceidentifier.product! = 0 {if (deviceidentifier.version! = 0) {//Try vendor product version. String8 Versionpath (Getinputdeviceconfigurationfilepathbyname (String8::format ("vendor_%04x_product_%04 X_version_%04x ",//Use the relevant vid PID of the input device previously obtained to find the file Deviceidentifier.vendor, Deviceidentifi Er.product, deviceidentifier.version), type); if (!versionpath.isempty ()) {return versionpath; }}//Try vendor product. String8 Productpath (Getinputdeviceconfigurationfilepathbyname (String8::format ("vendor_%04x_product_%04x", Deviceidentifier.vendor, Deviceidentifier.product), (type)); if (!productpath.isempty ()) {return productpath; }}//Try device name. Return Getinputdeviceconfigurationfilepathbyname (Deviceidentifier.name, type); This function is also in the same file, that is, to Path.setto (getenv ("Android_root")); Path.append ("/usr/"); This is the file system in the/SYSTEM/USR directory down to find}
So we need to compile the configuration file into the system for some output devices, and the name is generally
vendor_%04x_product_%04x.xxxType, it's clear here!
Here getevents should be almost there, the details need to be carefully read the code, when the above read to the event array is returned after the preliminary processing!
Processeventslocked:
Above GetEvents returned to Meventbuffer, do preliminary processing:
void Inputreader::p rocesseventslocked (const rawevent* rawevents, size_t count) {for (const rawevent* rawevent = Raweve Nts Count;) {Traversal gets to the event array int32_t type = rawevent->type; size_t batchsize = 1; if (type < eventhubinterface::first_synthetic_event) {//If it is a regular event int32_t deviceId = Rawevent->devi CeId; while (BatchSize < count) {if (Rawevent[batchsize].type >= Eventhubinterface::first_synthet ic_event | | Rawevent[batchsize].deviceid! = deviceId) {break; } batchsize + = 1; }//#if debug_raw_events ALOGW ("BatchSize:%d count:%d", batchsize, Count);//#endif processeventsfor Devicelocked (DeviceId, rawevent, batchsize); The event array that is acquired in this case belongs to the same batch, further processing, the condition is: the general event and is the same device} else {switch (Rawevent->type) {//here is some special Event type, as mentioned above, there will be this add event case event when the device is openedHubinterface::D evice_added:adddevicelocked (Rawevent->when, Rawevent->deviceid); Break Case Eventhubinterface::D evice_removed:removedevicelocked (Rawevent->when, Rawevent->deviceid); Break Case eventhubinterface::finished_device_scan:handleconfigurationchangedlocked (Rawevent->when); Break Default:alog_assert (FALSE); Can ' t happen break; }} count-= BatchSize; If the member in the event array is not processed above, continue rawevent + = batchsize in turn; }}
The arguments passed in are the array of event arrays and the number of getevents that were obtained in a certain time in the preceding period, and the prototype is defined in/frameworks/base/services/input/inputreader.h:
The event queue. static const int event_buffer_size = n; Rawevent Meventbuffer[event_buffer_size];
/* * A Raw event as retrieved from the Eventhub. */struct rawevent { nsecs_t when; int32_t deviceId; int32_t type; int32_t Code; int32_t value;};
Here you can see that processeventslocked is just a preliminary distribution of the get to event, looking at the type of event added.
Can see in the Inputreader inside again came a adddevicelocked , this to more top getevents in the next to open the device when the adddevicelocked distinguish, do not give around dizzy yo ~
void inputreader::adddevicelocked (nsecs_t when, int32_t deviceId) {ssize_t Deviceindex = Mdevices.indexofkey (deviceId) ; if (deviceindex >= 0) {ALOGW ("Ignoring spurious device added event for deviceId%d.", deviceId); Return } inputdeviceidentifier identifier = Meventhub->getdeviceidentifier (deviceId); This takes the device-related parameters uint32_t classes = meventhub->getdeviceclasses (deviceId) previously resolved in Eventhub; This above says that when the open device is initialized, it represents the type ALOGW ("Jscese display in adddevicelocked classes = = 0x%x \ n", classes); inputdevice* device = createdevicelocked (deviceId, identifier, classes); Here again to create a inputdervice, this will not continue to follow up, according to classes select the corresponding event processing map and the current device binding device->configure (when, &mconfig, 0); Device->reset (when); if (device->isignored ()) {Alogi ("Device added:id=%d, Name= '%s ' (ignored Non-input device)", DeviceId, Identifier.name.string ()); } else {Alogi ("Device added:id=%d, name= '%s ', sources=0x%08x", DeviceId, Identifier.name.string (), device->getsources ()); } mdevices.add (deviceId, device); Add this input device bumpgenerationlocked ();}
See the next steps when dealing with ordinary events:
void Inputreader::p rocesseventsfordevicelocked (int32_t deviceId, const rawevent* rawevents, size_t count) { ssize_t Deviceindex = Mdevices.indexofkey (deviceId); if (Deviceindex < 0) { ALOGW ("discarding event for unknown deviceId%d.", deviceId); return; } inputdevice* device = mdevices.valueat (Deviceindex); Here InputDevice if (device->isignored ()) { //alogd ("discarding event for ignored DeviceId%d") is taken out by ID. ", deviceId); return; } Device->process (rawevents, Count); A process function is called here}
Continue to see InputDevice's process:
void InputDevice::p rocess (const rawevent* rawevents, size_t count) {//process all of the events in order for each map Per. We cannot simply ask each mapper to process them in bulk because mappers May//has side-effects that must be inter leaved. For example, joystick movement events and//gamepad button presses is handled by different mappers but they should be Dispatched//in the order received. size_t nummappers = Mmappers.size (); Here is a map number, this also mentioned above, in the create will be based on the classes type to match the map processing, generally match a for (const rawevent* rawevent = rawevents; count--; raweve nt++) {//Iterate through an array of events, and sequentially process # if debug_raw_events alogd ("Input event:device=%d type=0x%04x code=0x%04x value=0x%08x whe N=%lld ", Rawevent->deviceid, Rawevent->type, Rawevent->code, Rawevent->value, RA Wevent->when); #endif if (Mdropuntilnextsync) {if (Rawevent->type = = Ev_syn && RAWEVENT-&G T;code = = syn_report) {MdropuntIlnextsync = false; #if debug_raw_events alogd ("Recovered from input event buffer overrun."); #endif} else {#if debug_raw_events alogd ("Dropped input event while waiting for next input sync ."); #endif}} else if (Rawevent->type = = Ev_syn && Rawevent->code = = syn_dropped) { Alogi ("Detected input event buffer overrun for device%s.", GetName (). String ()); Mdropuntilnextsync = true; Reset (Rawevent->when); } else {for (size_t i = 0; i < nummappers; i++) {inputmapper* mapper = Mmappers[i]; Mapper->process (rawevent); This is the process function that calls process map}}}}
Refer to Classes device type several times, see definition, in EventHub.h:
/*//CLASSES=0X80000004 * Input device classes. */enum {/* The input device is a keyboard or have buttons. */Input_device_class_keyboard = 0x00000001,/* T He input device is an alpha-numeric keyboard (not just a dial pad). */Input_device_class_alphakey = 0x00000002,/* The INPUT DEVICE is a touchscreen or a touchpad (either single- Touch or multi-touch). */Input_device_class_touch = 0x00000004,/* The INPUT DEVICE is a cursor device such as a trackball or MOUS E. */input_device_class_cursor = 0x00000008,/* The INPUT DEVICE is a multi-touch touchscreen. */INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,/* The INPUT DEVICE is a directional pad (implies keyboard, have DP AD keys). */Input_device_class_dpad = 0x00000020,/* The INPUT DEVICE is a gamepad (implies keyboard, have BUTTON key s). */Input_device_class_gamepad = 0x00000040,/* The INPUT DEVICE has switches. */Input_device_class_switch= 0x00000080,/* The input device is a joystick (implies gamepad, have joystick absolute axes). */Input_device_class_joystick = 0x00000100,/* The INPUT DEVICE has a vibrator (supports ff_rumble). */Input_device_class_vibrator = 0x00000200,/* The INPUT DEVICE is virtual (not a real DEVICE, not part of the UI Configuration). */input_device_class_virtual = 0x40000000,/* The INPUT DEVICE is external (not built-in). */input_device_class_external = 0x80000000,};
Then the next thing you need to deal with is the various INPUTMAP classes in the defined Inputreader.
Summarize:
This is where eventhub inputreader Device inputdevice inputmap is involved.
Take a look at the relationship:
The heap device is created in eventhub , which corresponds to the device file one by one under/dev/input, which is the input device registered in kernel.
The inputreader creates multiple InputDevice , which is created from the parameters in the Device , so the eventhub Device one by one corresponds.
InputDevice will add the required InputMapaccording to classes at the time of creation, each of the different InputMap in inputreader There are many ways to handle this.
This is generally the case, here about the Inputreader part of the first analysis here, and then down InputMap in the event distribution processing, follow-up analysis ~
The Inputreader of Linux/android--input system (vii)