Android input events from read to distribution five: the interception process before event distribution

Source: Internet
Author: User

In the previous article: Android input events from read to distribution three: Inputdispatcherthread thread distribution events in the article has already mentioned the event before the distribution to do interception, but did not unfold to analyze it, So the main purpose of this article is to analyze the interception process before the event is distributed. (Note: Android source version is 6.0)
On the Android input event from read to distribution three: Inputdispatcherthread thread distribution events in the article we analyze the Notifykey method of the Inputdispatcher class, the first attempt to intercept the event, you can look at this method:

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {...    KeyEvent event;    event.initialize(args->deviceId, args->source, args->action,            0,            args->downTime, args->eventTime);    mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);...}

Here is the interception before the event enters the queue, which is called the first intercept.
In addition, there is an interception before the event is distributed, that is, after the event has entered the Inputdispatcherthread thread, an intercept is made before the event is sent, and the invocation process is as follows:
Dispatchonce
->dispatchonceinnerlocked
->dispatchkeylocked
->dointerceptkeybeforedispatchinglockedinterruptible
->mpolicy->interceptkeybeforedispatching
This process is referred to here as two interception.

With the above knowledge of the bedding, below, we analyzed the two interception process.

First event Intercept

First look at the timing diagram:

Next, following the sequence diagram, we analyze the source of the event interception:
When we call the Mpolicy->interceptkeybeforequeueing method in Inputdispatcher::notifykey, we go to Nativeinputmanager: The Interceptkeybeforequeueing method is:

void Nativeinputmanager:: Interceptkeybeforequeueing (Constkeyevent* keyevent, uint32_t& policyflags) {// Policy://-Ignore Untrusted Events andPass them along.//-Ask ThewindowManager what Do  withNormal events andTrusted injected events.//-For normal events wake andBrighten the screenifCurrentlyoff orDim. Bool Interactive = Minteractive.load ();if(interactive)    {policyflags |= policy_flag_interactive; }if((Policyflags & policy_flag_trusted)) {nsecs_t when= Keyevent->geteventtime ();        jnienv* env = jnienv ();        Jobject keyeventobj = android_view_keyevent_fromnative (env, keyevent); Jint wmactions;if(keyeventobj) {wmactions = Env->callintmethod (Mserviceobj, Gserviceclassinfo.interceptkeybeforequeuein G, Keyeventobj, policyflags);if(Env, Checkandclearexceptionfromcallback"Interceptkeybeforequeueing") {wmactions =0;            } android_view_keyevent_recycle (env, keyeventobj);        Env->deletelocalref (Keyeventobj); }Else{Aloge ("Failed to obtain key event object for interceptkeybeforequeueing."); Wmactions =0; } handleinterceptactions (Wmactions, when,/*byref*/Policyflags); }Else{if(interactive)        {policyflags |= policy_flag_pass_to_user; }    }}

This function first constructs a keyeventobj based on the parameters of the KeyEvent type passed down, and the construction process is implemented by invoking the Android_view_keyevent_fromnative method:

Jobject android_view_keyevent_fromnative (jnienv*Env, const keyevent*Event) {Jobject EVENTOBJ =Env->callstaticobjectmethod (Gkeyeventclassinfo.clazz, Gkeyeventclassinfo.obtain, Nanoseconds_to_mill Iseconds (Event->getdowntime ()), Nanoseconds_to_milliseconds (Event->geteventtime ()),Event->getaction (),Event->getkeycode (),Event->getrepeatcount (),Event->getmetastate (),Event->getdeviceid (),Event->getscancode (),Event->getflags (),Event->getsource (), NULL);if(Env->exceptioncheck ()) {Aloge ("An exception occurred while obtaining a key event."); LOGE_EX (Env);Env->exceptionclear ();returnNULL; }returnEVENTOBJ;}

This method uses JNI to invoke a static method obtain of the Java layer, using this method to construct a eventobj and return. This is not our concern, for the time being, back to the Nativeinputmanager::interceptkeybeforequeueing method, after constructing the Keyeventobj object, and using JNI to call the Java layer return value of an instance method of int, this instance is determined by mserviceobj, it is actually an instance of Inputmanagerservice. If you follow a little trace, you will understand that there is no nagging.
It then enters into a series of calls to the Interceptkeybeforequeueing method:

    // Native callback.    privateintinterceptKeyBeforeQueueingeventint policyFlags) {        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);    }

The Mwindowmanagercallbacks implementation class is Inputmonitor, and its Interceptkeybeforequeueing method is as follows:

    @Override    publicintinterceptKeyBeforeQueueingeventint policyFlags) {        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);    }

The mpolicy in this function is defined as follows:

finalnew PhoneWindowManager();

Therefore, the next step is to enter the Interceptkeybeforequeueing method of Phonewindowmanager.

    /** {@inheritDoc} * /    @Override     Public int interceptkeybeforequeueing(KeyEvent event,intPolicyflags) {if(!msystembooted) {//If We have a not yet booted, don ' t let key events do anything.            return 0; }        ...Final BooleanInteractive = (Policyflags & flag_interactive)! =0;Final BooleanDown = event.getaction () = = Keyevent.action_down;Final BooleanCanceled = Event.iscanceled ();Switch(KeyCode) { CaseKeyevent.keycode_volume_down: CaseKEYEVENT.KEYCODE_VOLUME_UP: CaseKeyevent.keycode_volume_mute: {if(keycode = = Keyevent.keycode_volume_down) {if(down) {if(Interactive &&!mscreenshotchordvolumedownkeytriggered && (Event.getflags ( ) & keyevent.flag_fallback) = =0) {mscreenshotchordvolumedownkeytriggered =true;                            Mscreenshotchordvolumedownkeytime = Event.getdowntime (); Mscreenshotchordvolumedownkeyconsumed =false;                            Cancelpendingpowerkeyaction ();                        Interceptscreenshotchord (); }                    }Else{mscreenshotchordvolumedownkeytriggered =false;                    Cancelpendingscreenshotchordaction (); }                }Else if(keycode = = keyevent.keycode_volume_up) {if(down) {if(Interactive &&!mscreenshotchordvolumeupkeytriggered && (Event.getflags () & keyevent.flag_fallback) = =0) {mscreenshotchordvolumeupkeytriggered =true;                            Cancelpendingpowerkeyaction ();                        Cancelpendingscreenshotchordaction (); }                    }Else{mscreenshotchordvolumeupkeytriggered =false;                    Cancelpendingscreenshotchordaction (); }                }returnResult ...    }

This method is long and only a small part is posted here. The return value of this method is critical, and returning 0 means that the event is intercepted, and returning 1 means that the event is allowed to be sent to the application. Let's look at the processing of the final return value. Return to the Nativeinputmanager::interceptkeybeforequeueing method again, save the return value in the Wmactions variable, and then call the Handleinterceptactions method to process the return value. It is defined as follows:

void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,        uint32_t& policyFlags) {    if (wmActions & WM_ACTION_PASS_TO_USER) {        policyFlags |= POLICY_FLAG_PASS_TO_USER;    else {#if DEBUG_INPUT_DISPATCHER_POLICY        ALOGD("handleInterceptActions: Not passing key to user.");#endif    }}

Wm_action_pass_to_user is defined as follows:

enum {    1,};

This bit operation, but the result is that if the return value is 1, the two bits and 1, then add the Policy_flag_pass_to_user flag to policyflags, which means that the event can be sent to the application, otherwise, from the note can be known not to send the event to the user.
The first event interception specifically will intercept what events, you can see for yourself, you can go straight to see the Phonewindowmanager interceptkeybeforequeueing method, to see this method, those events after processing the return value of 0. A return value of 0 indicates that the event was intercepted.
Next we'll look at the second intercept.

Second event intercept

First look at the timing diagram:

You can see that the calling process is exactly the same as the first stage, so the source code is no longer tracked here. Interested can look at Phonewindowmanager's Interceptkeybeforedispatching method, this method of the event did two interception, the return value of this method is 1 indicates that the event was intercepted, the return value of 0 indicates that the event was released.
Let's look at the process of returning the value:

Jlong Delaymillis =Env->calllongmethod (Mserviceobj, gserviceclassinfo.interceptkeybeforedispatching, in            Putwindowhandleobj, Keyeventobj, policyflags); boolError= Checkandclearexceptionfromcallback (Env,"Interceptkeybeforedispatching"); Android_view_keyevent_recycle (Env, keyeventobj);Env->deletelocalref (Keyeventobj);if(!Error) {if(Delaymillis <0) {result =-1; }Else if(Delaymillis >0{result = Milliseconds_to_nanoseconds (Delaymillis); }            }

Here you can see that the return value is stored in the Delaymillis variable and then judged:
If the return value is negative, then result=-1, the return value equals 0 is not processed, because result defaults to a value of 0, and if the return value is greater than 0, the return value of milliseconds_to_nanoseconds is given to result. The Milliseconds_to_nanoseconds party is defined as follows:

staticinline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs){    return secs*1000000;}

You can see that the return value is *1000000.
Result will eventually be returned to Inputdispatcher:

voidInputdispatcher::d ointerceptkeybeforedispatchinglockedinterruptible(Commandentry*Commandentry) {Keyentry*Entry=Commandentry -Keyentry;    KeyEvent event; Initializekeyevent (&event, entry); MLock.Unlock (); nsecs_t delay=Mpolicy -Interceptkeybeforedispatching (commandentry -Inputwindowhandle,&Event, entry -Policyflags); MLock.Lock ();if(Delay< 0) {Entry -Interceptkeyresult=Keyentry:: Intercept_key_result_skip; }Else if(!Delay) {entry -Interceptkeyresult=Keyentry:: Intercept_key_result_continue; }Else{Entry -Interceptkeyresult=Keyentry:: Intercept_key_result_try_again_later; Entry -Interceptkeywakeuptime=Now ()+Delay } entry -Release ();}

In this method, the Entry->interceptkeyresult variable is assigned a value based on the return value. From the name we can guess, the return value is less than 0 intercept event, equal to 0 of the release event, greater than 0 is to wait to detect the need to intercept?
These three types correspond to the processing in Inputdispatcher::d ispatchkeylocked Method:

    //Handle case where the policy asked us to try again later last time.    if(Entry -Interceptkeyresult==Keyentry:: Intercept_key_result_try_again_later) {if(currenttime<Entry -Interceptkeywakeuptime) {if(Entry -Interceptkeywakeuptime< *Nextwakeuptime) {*Nextwakeuptime=Entry -Interceptkeywakeuptime; }return false;//wait until next wakeup} entry -Interceptkeyresult=Keyentry:: Intercept_key_result_unknown; Entry -Interceptkeywakeuptime= 0; }

This shows the processing of the Intercept_key_result_try_again_later, which determines the interception time and current time, and if the current time is less than the intercept time, the next cycle is processed. So what we understand is right.

if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {        if (*dropReason == DROP_REASON_NOT_DROPPED) {            *dropReason = DROP_REASON_POLICY;        }    }

This shows the processing of the Intercept_key_result_skip type, if the state of Dropreason is not to discard the event, then change its state to the policy discard. That is, the incident was intercepted.
Intercept_key_result_continue is not doing the processing. All the processing code that does not correspond to this state.

Android input events from read to distribution five: the interception process before event distribution

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.