Android 2.3 input event processing

Source: Internet
Author: User
Tags call back

The Linux Kernel provides an input subsystem for implementation. The input subsystem creates a node for our hardware input device in the/dev/input/path, generally, these nodes are named after eventxx in our mobile phone, such as event0 and event1. You can use eviocgname to obtain the name of the event node. This is the source of data processing for input events in Android. We will not talk about the Data Writing driver.

First, let's briefly introduce the process of Android event transfer. Events such as buttons and touch screens are obtained through windowmanagerservice and transmitted to viewroot through shared memory and pipelines, viewroot then dispatch the view to the application. When an event is input from a hardware device, system_server notifies viewroot of the event in the pipeline (PIPE) when detecting the event. In this case, viewroot reads the event information from the memory. The following describes the entire process in a module partition diagram:

The following describes the main process of each module:

1. Create a read-through channel initialization:

A. windowmanagerservice and viewroot establish pipeline Initialization

Windowmanagerservice: it is mainly responsible for event transmission and runs in system_server. It mainly uses inputmanager to start the input event startup thread.

Read event data

Windowmanagerservice ---> pipe communication in the viewroot direction, indicating that WMS notifies viewroot that a new event is written to the shared memory;

Viewroot --> the MPs queue in the windowmanagerservice direction indicates that viewroot has digested new events in the shared memory. We hereby notify WMS.

The file descriptor of the viewroot and windowmanagerservice pipelines is stored in a class named inputchannel. The inputchannel class is

The carrier of pipeline communication. The two use ashmem_create_region to create an anonymous memory for data transmission.

Create a pipe on the viewroot. Java side:

Minputchannel = new inputchannel ();
Try {
Res = swindowsession. Add (mwindow, m1_wattributes,
Gethostvisibility (), mattachinfo. mcontentinsets,
Minputchannel );
} Catch (RemoteException E)

Windowmanagerservice. Java:

If (outinputchannel! = NULL ){
String name = win. makeinputchannelname ();
Inputchannel [] inputchannels = inputchannel. openinputchannelpair (name );
Win. minputchannel = inputchannels [0];
Inputchannels [1]. transfertobinderoutparameter (outinputchannel );

Minputmanager. registerinputchannel (win. minputchannel );
}

Creates an inputchannel. This inputchannel implements a set of full-duplex pipelines and requests for shared memory. The outinputchannel is transmitted by viewroot.

Inputchannel object, which is assigned a value in addwindow. The two use pipe to establish a control channel and use the shared memory to establish a data channel.

This involves the following files:

Frameworks/base/service/Java/COM/Android/Server/windowmanagerservice. Java

Frameworks/base/CORE/Java/Android/View/viewroot. Java

--> JNI android_view_inputchannel.cpp

--> Inputtransport. cpp

B. inputchannel registration process

One Pipeline communication only corresponds to the event processing of a single activity, that is, the number of full-duplex pipelines in the current system. Therefore, the system requires a manager to manage and schedule the communication of each pipeline, therefore, after creating an inputchannel object, we need to register it in the inputmanager management.

Logoff is used to check whether there are events. inputmanager starts two processes to manage event occurrence and transmission. inputreaderthread and inputdispatcherthread, inputreaderthread process are responsible for polling events, and inputdispatcherthread is responsible for dispatch events.


2. Data Processing Process:

EventhubRead data from/dev/input/eventx:

Bool eventhub: getevent (rawevent * outevent)
{

Int pollresult = poll (MFDs, mfdcount,-1 );

If (PFD. revents & Pollin ){
Int32_t readsize = read (PFD. FD, minputbufferdata,
Sizeof (struct input_event) * input_buffer_size );

...

}


InputreaderThe Mapper processes different data. switchinputmapper, keyboardinputmapper, trackballinputmapper, touchinputmapper, and mouseinputmapper process Mapper to filter data.

Void inputreader: looponce (){
Rawevent;
Meventhub-> getevent (& rawevent );

Process (& rawevent );
}

Void inputreader: Process (const rawevent * rawevent ){

Switch (rawevent-> type ){
Case eventhubinterface: device_added:
Adddevice (rawevent-> DeviceID );
Break;

Case eventhubinterface: device_removed:
Removedevice (rawevent-> DeviceID );
Break;

Case eventhubinterface: finished_device_scan:
Handleconfigurationchanged (rawevent-> when );
Break;

Default:
Consumeevent (rawevent );
Break;
}
}

Pass:

Virtual void policykey (nsecs_t eventtime, int32_t DeviceID, int32_t source,
Uint32_t policyflags, int32_t action, int32_t flags, int32_t keycode,
Int32_t scancode, int32_t metastate, nsecs_t downtime) = 0;
Virtual void policymotion (nsecs_t eventtime, int32_t DeviceID, int32_t source,
Uint32_t policyflags, int32_t action, int32_t flags,
Int32_t metastate, int32_t edgeflags,
Uint32_t pointercount, const int32_t * pointerids, const pointercoords * pointercoords,
Float xprecision, float yprecision, nsecs_t downtime) = 0;
Virtual void policyswitch (nsecs_t when,
Int32_t switchcode, int32_t switchvalue, uint32_t policyflags) = 0;

Call back the data to the inputdisplatcher module.

 

Inputdispatcher distributes received data: the polling process of the inputdispatcherthread thread is dispatchonce () --> dispatchonceinnerlocked (). The inputdispatcherthread continuously executes this operation to achieve the purpose of polling.

Process and distribute to different applications
Bool inputdispatcherthread: threadloop (){
Dispatchonceinnerlocked {
Case evententry: type_key:
Dispatchkeylocked (); --> dispatcheventtocurrentinputtargetslocked
--> Preparedispatchpolicelocked
Case evententry: type_motion:
Dispatchmotionlocked ();
}
}

The dispatchkeylocked function, which then calls dispatcheventtocurrentinputtargetslocked for further processing. Add the activity window that needs to receive Keyboard Events to mcurrentinputtargets. Therefore, take them out and call the preparedispatchreceivelocked function to distribute the keyboard events to them for processing.
Inputdispatcherthread processing process:

The main operations of inputdispatcherthread are performed in two parts at the same time,

Part of the process is to pre-process the events passed by inputreader by dispatch, such as determining the focus window and processing special Buttons such as home/endcall. After preprocessing, inputdispatcher stores the event to the outboundqueue of the corresponding focus window. The outboundqueue queue is a member function of inputdispatcher: connection, so it is related to viewroot.

In part, it is round-robin For logoff. This round-robin process is to check whether nativeinputqueue has handled the previous event. If nativeinputqueue has handled the event, it will send a message to inputdispatcher to indicate that consume has completed, only nativeinputqueue consume completes an event. inputdispatcher writes another event to the shared memory.


Two queue queues are used here:

Queue <dispatchentry> outboundqueue; Use handlereceivecallback to process received data

Use publishkeyevent and publishmotionevent in inputpublisher to write the event to the shared memory.


Queue <evententry> minboundqueue; process the data from callback y.


Data processing logic for the client:
Inputconsumer is used to consume data (inputchannel. cpp). The core function is:
Status_t inputconsumer: consume (inputeventfactoryinterface * factory, inputevent ** outevent ){
Switch (msharedmessage-> type ){
Case ainput_event_type_key :{
Keyevent * keyevent = factory-> createkeyevent ();
If (! Keyevent) return no_memory;

Populatekeyevent (keyevent );

* Outevent = keyevent;
Break;
}

Case ainput_event_type_motion :{
Motionevent * motionevent = factory-> createmotionevent ();
If (! Motionevent) return no_memory;

Populatemotionevent (motionevent );

* Outevent = motionevent;
Break;
}
...
}

JNI function: android_view_inputqueue.cpp
Int nativeinputqueue: handlereceivecallback (INT receivefd, int events, void * Data ){
/* Receive the signal first */
Status_t status = connection-> inputconsumer. receivedispatchsignal ();

/* Reprocess data */
Status = connection-> inputconsumer. Consume (& connection-> inputeventfactory, & inputevent );

/* Convert to the native data of the Java object */

Android_view_keyevent_fromnative and android_view_motionevent_fromnative

/* Call back the data to the Java Layer */

Env-> callstaticvoidmethod (ginputqueueclassinfo. clazz,

Dispatchmethodid, inputhandlerobjlocal, inputeventobj,
Jlong (finishedtoken ));

}


The following describes how C ++ calls Java:

First, register two methods:

Env-> callstaticvoidmethod (ginputqueueclassinfo. clazz,
Dispatchmethodid, inputhandlerobjlocal, inputeventobj,
Jlong (finishedtoken ));
Get_static_method_id (ginputqueueclassinfo. dispatchkeyevent, ginputqueueclassinfo. clazz,
"Dispatchkeyevent ",
"(Landroid/View/inputhandler; landroid/View/keyevent; j) V ");

Get_static_method_id (ginputqueueclassinfo. dispatchmotionevent, ginputqueueclassinfo. clazz,
"Dispatchmotionevent ",
"(Landroid/View/inputhandler; landroid/View/motionevent; j) V ");


The two methods are defined in inputqueue. Java:

Env-> callstaticvoidmethod (ginputqueueclassinfo. clazz,
Dispatchmethodid, inputhandlerobjlocal, inputeventobj,
Jlong (finishedtoken ));
Private Static void dispatchkeyevent (inputhandler,
Keyevent event, long finishedtoken ){
Runnable finishedcallback = finishedcallback. Obtain (finishedtoken );
Inputhandler. handlekey (event, finishedcallback );
}

@ Suppresswarnings ("UNUSED ")
Private Static void dispatchmotionevent (inputhandler,
Motionevent event, long finishedtoken ){
Runnable finishedcallback = finishedcallback. Obtain (finishedtoken );
Inputhandler. handlemotion (event, finishedcallback );
}


Env-> callstaticvoidmethod (ginputqueueclassinfo. clazz,
Dispatchmethodid, inputhandlerobjlocal, inputeventobj,
Jlong (finishedtoken ));


The handlekey is used by inputhandler to process keyevent and motionevent events.


Client Data callback mechanism:

Each client registers an inputchannel

Status_t nativeinputqueue: registerinputchannel (jnienv * ENV, jobject inputchannelobj,

Add notify callback function

Looper-> addfd (receivefd, 0, alooper_event_input, handlereceivecallback, this );

 

Env-> callstaticvoidmethod (ginputqueueclassinfo. clazz,
Dispatchmethodid, inputhandlerobjlocal, inputeventobj,
Jlong (finishedtoken ));
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.