"See Android from source code" pendingintent

Source: Internet
Author: User
Tags mremote

First, the introduction

Pendingintent is a very humble class,

You may have encountered it under the following circumstances


1, Alarmmanager

int RequestID = 1;        Alarmmanager am = (alarmmanager) getsystemservice (alarm_service);        Intent i = new Intent (this,ashqalreceiver.class);        pendingintent pi = pendingintent.getbroadcast (this                , RequestID                , I                , pendingintent.flag_update_current);        Am.setrepeating (Alarmmanager.rtc_wakeup                , System.currenttimemillis () + +                , +                , pi);


2, Notificationmanager

Initialize int requestid = 1;        Mpendingintent = Pendingintent.getactivity (this                , RequestID                , New Intent (This,myactivity.class)                , pendingintent.flag_update_current);//Call Notificationmanager NM = (Notificationmanager) getsystemservice ( Notification_service);        Notificationcompat.builder Builder = new Notificationcompat.builder (this);        Builder.setsmallicon (r.drawable.ic_launcher);        Builder.setcontenttitle ("Notification Title");        Builder.setcontenttext ("context text");        Builder.setcontentintent (mpendingintent);        Builder.setautocancel (true);        Notification Notification = Builder.build ();        Nm.notify (0,notification);

Or

Pendingintent mpendingintent = Pendingintent.getservice (Mctx                    , RequestID                    , Mintent                    , Pendingintent.flag_ update_current);            Mbuilder.setcontentintent (mpendingintent);


2 ways to save the desired action (call broadcast, open activity, open service) to Pendingintent, and perform this operation at the appropriate time

Whether you open activity from the drop-down message bar or open a service operation, or by Alarmmanager a timed broadcast,

Are all carried out in a cross-process manner, where are the current pendingintent objects stored? How do I call to pendingintent in other processes?

This has to start with the creation of Pendingintent.



Ii. creation of Pendingintent

Mentioned in the previous 3 static ways to create, according to the Android SDK reference description, respectively is

Pendintent.getservice,pendingintent.getactivity,pendingintent.getbroadcast

These three creation methods are very similar, we only select one of the Pendintent.getservice


Create the sample code as follows:

Pendingintent mpendingintent = Pendingintent.getservice (Mctx                    , RequestID                    , Mintent                    , Pendingintent.flag_ Update_current);

If the subsequent action is startservice, you need to create the pendingintent from Pendingintent.getservice


Android.app.pendingintent.java,getservice function implementation

public static Pendingintent GetService (context context, int requestcode,            Intent Intent, int flags) {        String packa Gename = Context.getpackagename ();        String Resolvedtype = Intent! = null? Intent.resolvetypeifneeded (                context.getcontentresolver ()): null;        try {            intent.preparetoleaveprocess ();            Iintentsender target =                activitymanagernative.getdefault (). Getintentsender (                    Activitymanager.intent_sender _service, PackageName,                    null, NULL, Requestcode, new intent[] {Intent},                    resolvedtype! = null? New string[] {RE Solvedtype}: null,                    flags, NULL, Userhandle.myuserid ());            return target! = null? New Pendingintent (target): null;        } catch (RemoteException e) {        }        return null;    }

Gets the MIME type of the package name and intent from the context (such as Text/plain),

Use static function Activitymanagernative.getdefault () Gets the local proxy object activitymanagerproxy to Activitymanagerservice (which encapsulates the remote Activitymanagerservice)

Call this Activitymanagerproxy's Getintentsender function


Android.app.ActivityManagerNative.ActivityManagerProxy

    Public iintentsender getintentsender (int type, string packagename, IBinder token, string resultwho, int Requestcode, intent[] intents, string[] resolvedtypes, int flags, Bundle options, int userId) throws Re        moteexception {Parcel data = Parcel.obtain ();        Parcel reply = Parcel.obtain ();        Data.writeinterfacetoken (Iactivitymanager.descriptor);        Data.writeint (type);        Data.writestring (PackageName);        Data.writestrongbinder (token);        Data.writestring (resultwho);        Data.writeint (Requestcode);            if (intents! = null) {data.writeint (1);            Data.writetypedarray (intents, 0);        Data.writestringarray (resolvedtypes);        } else {data.writeint (0);        } data.writeint (Flags);            if (options! = null) {data.writeint (1);        Options.writetoparcel (data, 0);        } else {data.writeint (0);     } data.writeint (UserId);   Mremote.transact (get_intent_sender_transaction, data, reply, 0);        Reply.readexception ();        Iintentsender res = IIntentSender.Stub.asInterface (Reply.readstrongbinder ());        Data.recycle ();        Reply.recycle ();    return res; }

Obviously, Activitymanagerproxy serializes a series of parameter data to a parcel object, and then calls the Transact method of mremote (the remote Activitymanagerservice object),

Tells the activitymanagerservice of the system process to deal with this thing



Handling this thing code in the Activitymanagerservice of the system process

Android.app.ActivityManagerNative. ontransact Method Fragment,

Because Activitymanagerservice inherits from Activitymanagernative,

Activitymanagerservice this request to activitymanagernative processing

Case Get_intent_sender_transaction: {data.enforceinterface (iactivitymanager.descriptor);            int type = Data.readint ();            String PackageName = data.readstring ();            IBinder token = Data.readstrongbinder ();            String resultwho = data.readstring ();            int requestcode = Data.readint ();            Intent[] requestintents;            String[] Requestresolvedtypes;                if (Data.readint ()! = 0) {requestintents = Data.createtypedarray (intent.creator);            Requestresolvedtypes = Data.createstringarray ();                } else {requestintents = null;            Requestresolvedtypes = null;            } int fl = Data.readint (); Bundle options = Data.readint ()! = 0?            Bundle.CREATOR.createFromParcel (data): null;            int userId = Data.readint (); Iintentsender res = Getintentsender (type, PackageName, token, resultwho, requEstcode, Requestintents, Requestresolvedtypes, FL, options, userId);            Reply.writenoexception ();            Reply.writestrongbinder (res! = null? Res.asbinder (): null);        return true; }

The data is deserialized, the Getintentsender method of the Activitymanagerservice is called, and the feedback is written to reply, returning from the Mremote.transcat function.


We thoroughly analyze the Getintentsender method of Activitymanagerservice, as follows

@Override public iintentsender getintentsender (int type, string packagename, IBinder token, string resultwho , int requestcode, intent[] intents, string[] resolvedtypes, int flags, Bundle options, int userId)        {Enforcenotisolatedcaller ("Getintentsender");                Refuse possible leaked file descriptors if (intents! = null) {if (Intents.length < 1) {            throw new IllegalArgumentException ("Intents array length must be >= 1");                } for (int i=0; i<intents.length; i++) {Intent Intent = intents[i]; if (intent! = null) {if (Intent.hasfiledescriptors ()) {throw new Illegalargume                    Ntexception ("File descriptors passed in Intent"); } if (type = = Activitymanager.intent_sender_broadcast && (intent.get Flags () &intent.flag_receiver_boot_upgrade)! = 0) {                        throw new IllegalArgumentException ("Can ' t use Flag_receiver_boot_u                    Pgrade here ");                } Intents[i] = new Intent (Intent); }} if (resolvedtypes! = NULL && resolvedtypes.length! = intents.length) {th            Row new IllegalArgumentException ("Intent array length does not match resolvedtypes length"); }} if (options = null) {if (Options.hasfiledescriptors ()) {throw new Il            Legalargumentexception ("File descriptors passed in Options");            }} synchronized (this) {int callinguid = Binder.getcallinguid ();            int origuserid = userId; UserID = Handleincominguser (Binder.getcallingpid (), Callinguid, userId, type = = Activitymanager.intent_ Sender_broadcast, False, "Getintentsender", null);            if (Origuserid = = userhandle.user_current) {//We don ' t want to evaluate this until  G Intent is//actually executed.                However, we do want to always do the//security checking for it above.            UserId = userhandle.user_current; } try {if (Callinguid! = 0 && Callinguid! = process.system_uid) {in T uid = Appglobals.getpackagemanager (). Getpackageuid (PackageName, Userhandle.getuserid (calling                    Uid)); if (! Userhandle.issameapp (Callinguid, uid)) {String msg = "Permission denial:getintentsender () from pi                            D= "+ binder.getcallingpid () +", uid= "+ binder.getcallinguid () + ", (need uid=" + uid + ")" + "is not allowed-to-Send as package" +                        PackageName; Slog. W (TAG, msg);                    throw new SecurityException (msg);                        }} return getintentsenderlocked (type, PackageName, Callinguid, UserId,                            Tokens, resultwho, Requestcode, intents, resolvedtypes, flags, options);            } catch (RemoteException e) {throw new SecurityException (e); }        }    }

The whole set of intent is first deeply copied,

Then pass the information passed to check callinguid and packagename the corresponding UID is the same,

And then call into the function getintentsendrlocked


The getintentsendrlocked method of Activitymanagerservice

Iintentsender getintentsenderlocked (int type, String packagename, int callinguid, int userId, IBinder token, St Ring resultwho, int requestcode, intent[] intents, string[] resolvedtypes, int flags, Bundle options        {if (DEBUG_MU) slog.v (Tag_mu, "getintentsenderlocked (): uid=" + callinguid);        Activityrecord activity = NULL;            if (type = = Activitymanager.intent_sender_activity_result) {ACTIVITY = activityrecord.isinstacklocked (token);            if (activity = = NULL) {return null;            } if (activity.finishing) {return null;        }} Final Boolean nocreate = (flags&pendingintent.flag_no_create)! = 0;        Final Boolean cancelcurrent = (flags&pendingintent.flag_cancel_current)! = 0;        Final Boolean updatecurrent = (flags&pendingintent.flag_update_current)! = 0; Flags &= ~ (pendingintent.flag_no_create| Pendingintent.flag_cancel_current |        Pendingintent.flag_update_current);                Pendingintentrecord.key Key = new Pendingintentrecord.key (type, packagename, activity, resultwho,        Requestcode, intents, resolvedtypes, flags, options, USERID);        Weakreference<pendingintentrecord> ref;        ref = Mintentsenderrecords.get (key); Pendingintentrecord REC = ref! = NULL?        Ref.get (): null; if (rec! = null) {if (!cancelcurrent) {if (updatecurrent) {if (rec.key.req                                Uestintent! = null) {Rec.key.requestIntent.replaceExtras (intents! = null?)                    INTENTS[INTENTS.LENGTH-1]: null);                        } if (intents! = null) {intents[intents.length-1] = rec.key.requestIntent;                        Rec.key.allIntents = intents;                    Rec.key.allResolvedTypes = Resolvedtypes; } ELSE {rec.key.allIntents = NULL;                    Rec.key.allResolvedTypes = null;            }} return rec;            } rec.canceled = true;        Mintentsenderrecords.remove (key);        } if (nocreate) {return rec;        } rec = new Pendingintentrecord (this, key, Callinguid);        Mintentsenderrecords.put (key, Rec.ref);                if (type = = Activitymanager.intent_sender_activity_result) {if (activity.pendingresults = = null) {            Activity.pendingresults = new hashset<weakreference<pendingintentrecord>> ();        } activity.pendingResults.add (Rec.ref);    } return rec; }


Here are the 3 flags that were used in the parameters just now.

Flag_no_create, does not exist on the creation, the existence is deleted and then created, one-time use, not put into the mintentsenderrecords

Flag_cancel_current, existing in the delete current, and then create a new into the Mintentsenderrecords

Flag_update_current, exists and does not replace intent for cancel, otherwise creates a new, put in Mintentsenderrecords

Three flags are closed after reading to a value

After that, a pendingintentrecord.key is formed using the multiple parameters passed in, and then the mintentsenderrecords container is searched for the existence of the Key.

Executed according to the 3 flag logic above

And finally all return a pendingintentrecord,

This pendingintentrecord inherits from the Aidl interface Iintentsender.stub and implements the Send method


Finally, the obtained pendingintentrecord is stored in the reply by serialization method,

Data is passed back to user space via binder mechanism interprocess communication

Use Pendingintent to encapsulate this iintentsender,new pendingintent (iintentsender)

So Pendingintent is created.


Because Pendingintentrecord.key rewritten its own hashcode and Equals method,

So even if the object's Pendingintent memory address is different, it may be judged to be the same request



Second, the use of pendingintent

Because the Pendingintent object is passed to the target (such as the top bar notification bar, broadcast),

As in Alarmmanager, the Pendingintent object passed to Alarmmanager is encapsulated as a alarm object

Alarm a = new Alarm (type, when, whenelapsed, Windowlength, Maxwhen, interval,                operation, WorkSource);

Then call the Send method on the Pendingintent object at the right time

Com.android.server.AlarmManagerService.AlarmHander.handlerMessage

public void Handlemessage (Message msg) {if (Msg.what = = alarm_event) {arraylist<alarm> T                Riggerlist = new arraylist<alarm> ();                    Synchronized (MLock) {final long NOWRTC = System.currenttimemillis ();                    Final Long nowelapsed = Systemclock.elapsedrealtime ();                Triggeralarmslocked (Triggerlist, nowelapsed, NOWRTC); }//Now trigger the alarms without the lock held for (int i=0; I<trigger List.size ();                    i++) {Alarm Alarm = Triggerlist.get (i);                    try {alarm.operation.send ();                            } catch (Pendingintent.canceledexception e) {if (Alarm.repeatinterval > 0) {  This intentsender was no longer valid, but this//was a repeating alarm, so toss the                            Hoser. RemOve (Alarm.operation); }                    }                }            }        }

You can trigger the Sendinner function of the Pendingintentrecoard,

For example, if the type is service, call the following function fragment

Case Activitymanager.intent_sender_service:                        try {                            owner.startserviceinpackage (uid,                                    finalintent, Resolvedtype, userId);                        } catch (RuntimeException e) {                            SLOG.W (Activitymanagerservice.tag,                                    "Unable to send StartService intent", e);                        } Break                        ;

Startserviceinpackage, so you can start the service.



Iv. Inspiring

Inspired by this, because Pendingintent inherits from Parcelable can be serialized

All we need to do is serialize the pendingintent through intent to other components of the same package,

Deserialization back, call send, can trigger a predefined operation

Specific ways See: How-to-use-pendingintent-to-communicate-from-a-service-to-a-client-activity

Http://stackoverflow.com/questions/6099364/how-to-use-pendingintent-to-communicate-from-a-service-to-a-client-activity



"See Android from source code" pendingintent

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.