Analysis of activation process of activity based on N source code

Source: Internet
Author: User
Tags abstract config stub mremote

For the topic of the article, online flooding, in order to deepen the impression, it is best to follow the source code, so that the understanding of the framework and the application of control are very helpful.

Recommended some of the old Luo's column articles:

Introduction to the Activity initiation process and learning plan for Android apps

Lao Luo's blog is very good, but the source of the analysis is a bit old, but the general idea will not change. I am here based on the Android 7.0 source code to follow this process, I hope to help everyone.

Analysis before, we must have a knowledge of the use of aidl, so look at the source code will not be confused, do not understand can see the article published before: Aidl simple use

It is important to have this picture in mind:

Remember these points:

1, the server has a middle stub (this name can be customized definition, such as the following to be activitymanagernative), remember that it inherits binder, implement interface.

2, the service side will have a true realization, it inherits stub, remember we in use aidl of time also will this use. Like the activitymanagerservices here.

3, the client has a middle proxy, in the cross-process will be this way to get it, proxy=stub.asinterface (binder), proxy inside there will be a binder object, The method that invokes the proxy will call the Binder object's Transact method, which will cross the process into the stub's Ontransact method, as can be seen from the image above.

After understanding these three points, we can analyze the activation process of the activity.

Start the activity in the app first:

	public void Startactivitytest () {
		Intent Intent = new Intent (this, mainactivity.class);
		StartActivity (intent);
	}

The Activity.java will then enter the inside:

    public void StartActivity (Intent Intent, @Nullable Bundle options) {
        if (options! = null) {
            Startactivityforresul T (intent,-1, options);
        }  else {
            //Note We want to go through this call for compatibility with
            ///applications which may have overridden the method.
            Startactivityforresult (Intent,-1);
        }
    }

The options passed here are null, followed by the following method:

    public void Startactivityforresult (@RequiresPermission Intent Intent, int requestcode,
            @Nullable Bundle options) { C2/>if (mparent = = null) {
            Instrumentation.activityresult ar =
                minstrumentation.execstartactivity (This
                    , Mmainthread.getapplicationthread (), Mtoken, this,
                    intent, requestcode, options);

Here you will see a few important classes, a instrumentation class, which is the helper class that activity starts, and the Activitythread class, which mainly manages the execution flow of the main thread application. It has an internal class Applicationthread:

Private class Applicationthread extends Applicationthreadnative {

This is what. He inherited applicationthreadnative:

Public abstract class Applicationthreadnative extends Binder
        implements Iapplicationthread {

See no, he inherits Binder, implements interface. This is not the stub of the service side. Applicationthread is the server side of the implementation, to understand that the server here is on the client side.

This place can be remembered first, will be used later, continue our process, in the Startactivityforresult will go to instrumentation execution, and passed a binder applicationthread.

Enter Instrumentation.java

    Public Activityresult execstartactivity (
            Context who, IBinder Contextthread, IBinder token, Activity target,
            Intent Intent, int requestcode, Bundle options) {
        Iapplicationthread whothread = (iapplicationthread) contextthread;
        try {
            intent.migrateextrastreamtoclipdata ();
            Intent.preparetoleaveprocess (WHO);
            int result = Activitymanagernative.getdefault ()
                . StartActivity (Whothread, Who.getbasepackagename (), intent,
                        intent.resolvetypeifneeded (Who.getcontentresolver ()),
                        token, Target! = null? Target.mEmbeddedID:null,
                        requestcode, 0, NULL, options);
            Checkstartactivityresult (result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException ("Failure from System", e);
        }

Here comes another important class, activitymanagernative:

Public abstract class Activitymanagernative extends Binder implements Iactivitymanager
<pre class= "java" name= "code" >    static public Iactivitymanager Getdefault () {
        return gdefault.get ();
    }

It can be seen that it is also the intermediary stub on the service side, and then look at the Gdefault:

    private static final singleton<iactivitymanager> Gdefault = new singleton<iactivitymanager> () {
        Protected Iactivitymanager Create () {
            IBinder B = servicemanager.getservice ("activity");
            if (false) {
                log.v ("Activitymanager", "default service binder =" + b);
            }
            Iactivitymanager am = asinterface (b);
            if (false) {
                log.v ("Activitymanager", "Default service =" + am);
            }
            return am;
        }
    ;

It is a singleton class that calls the Get method and, if not initialized, walks into the Create method. This will get the binder object from the service explorer ServiceManager and see Iactivitymanager am = asinterface (b); You should get a local agent:

    static public Iactivitymanager asinterface (IBinder obj) {
        if (obj = = null) {
            return null;
        }
        Iactivitymanager in =
            (Iactivitymanager) obj.querylocalinterface (descriptor);
        if (in = null) {
            return in;
        }

        return new Activitymanagerproxy (obj);
    

Sure enough, this returns the Activitymanagerproxy type local agent, above StartActivity will walk into the agent inside:

    public int startactivity (iapplicationthread caller, String callingpackage, Intent Intent,
            string Resolvedtype, IBinder Resultto, String resultwho, int requestcode,
            int startflags, Profilerinfo profilerinfo, Bundle options) throw s remoteexception {
		...
        Mremote.transact (start_activity_transaction, data, reply, 0);
        return result;
    }

Here Mremote is the remote binder object, and calling Transact will enter the Ontransact method in the stub (activitymanagernative):

    public boolean ontransact (int code, PARCEL data, Parcel reply, int flags) throws RemoteException { Switch (code) {case Start_activity_transaction: {data.enforceinterface (iactivitymanager.des
            Criptor);
            IBinder B = Data.readstrongbinder ();
            Iapplicationthread app = Applicationthreadnative.asinterface (b);
            String callingpackage = data.readstring ();
            Intent Intent = Intent.CREATOR.createFromParcel (data);
            String Resolvedtype = data.readstring ();
            IBinder Resultto = Data.readstrongbinder ();
            String resultwho = data.readstring ();
            int requestcode = Data.readint ();
            int startflags = Data.readint (); Profilerinfo profilerinfo = Data.readint ()! = 0?
            ProfilerInfo.CREATOR.createFromParcel (data): null; Bundle options = Data.readint ()! = 0? Bundle.CREATOR.createFromParcel (data): nulL int result = StartActivity (app, Callingpackage, intent, Resolvedtype, Resultto, resultwho, Requestcode
            , Startflags, Profilerinfo, Options);
            Reply.writenoexception ();
            Reply.writeint (result);
        return true; }

Above startactivity will go into the stub of the implementation, who is the implementation of the stub, that is, who inherits activitymanagernative? Undoubtedly, of course, the famous activitymanagerservice:

Public final class Activitymanagerservice extends Activitymanagernative

Then follow and enter StartActivity:

    Public final int startactivity (iapplicationthread caller, String callingpackage,
            Intent Intent, String resolvedtype , IBinder Resultto, String resultwho, int requestcode,
            int startflags, Profilerinfo profilerinfo, Bundle boptions) {
  return Startactivityasuser (caller, callingpackage, intent, Resolvedtype, Resultto, resultwho, Requestcode,
                Startflags, Profilerinfo, boptions,
                Userhandle.getcallinguserid ());
    }
    Public final int Startactivityasuser (iapplicationthread caller, String callingpackage,
            Intent Intent, string Resolvedtype, IBinder Resultto, String resultwho, int requestcode,
            int startflags, Profilerinfo profilerinfo, Bundle boptions, int userId) {
        Enforcenotisolatedcaller ("startactivity");
        UserID = Musercontroller.handleincominguser (Binder.getcallingpid (), Binder.getcallinguid (),
                userId, False, Allow_full_only, "startactivity", null);
        Todo:switch to the user app stacks here.
        return mactivitystarter.startactivitymaywait (caller,-1, callingpackage, intent,
                resolvedtype, NULL, NULL, Resultto, resultwho, Requestcode, Startflags,
                profilerinfo, NULL, NULL, Boptions, FALSE, userId, NULL, NULL);
    }

You can see the startactivitymaywait function entered into the Activitystarter.java, and then enter the Startactivitylocked method:

    Final int startactivitylocked (iapplicationthread caller, Intent Intent, Intent ephemeralintent, String Res Olvedtype, Activityinfo ainfo, ResolveInfo rinfo, Ivoiceinteractionsession voicesession, Ivoiceinteractor voic
            Einteractor, IBinder Resultto, String resultwho, int requestcode, int callingpid, int callinguid, String callingpackage, int realcallingpid, int realcallinguid, int startflags, activityoptions options, Boolea N Ignoretargetsecurity, Boolean componentspecified, activityrecord[] outactivity, activitystacksupervisor.acti Vitycontainer container, Taskrecord intask) {int res = startactivitylocked (caller, intent, Epheme Ralintent, Resolvedtype, Ainfo, Rinfo, Voicesession, Voiceinteractor, Resultto, re Sultwho, Requestcode, Callingpid, Callinguid, Callingpackage, Realcallingpid, Realcallinguid, StartFla
                    GsOptions, Ignoretargetsecurity, componentspecified, Outrecord, container, intask); }

Again into the Startactivitylocked method:

    Final int startactivitylocked (iapplicationthread caller, Intent Intent, Intent ephemeralintent,
            String Resolvedtype, Activityinfo ainfo, ResolveInfo rinfo,
            ivoiceinteractionsession voicesession, Ivoiceinteractor Voiceinteractor,
            ibinder Resultto, string resultwho, int requestcode, int callingpid, int callinguid,
            string callingpackage, int realcallingpid, int realcallinguid, int startflags,
            activityoptions options, Boolean Ignoretargetsecurity, Boolean componentspecified,
            activityrecord[] outactivity, Activitystacksupervisor.activitycontainer container,
            Taskrecord intask) {
				dopendingactivitylauncheslocked (false);
			}
    Final void dopendingactivitylauncheslocked (Boolean doresume) {while
        (!mpendingactivitylaunches.isempty ()) {
            final Pendingactivitylaunch pal = mpendingactivitylaunches.remove (0);
            Final Boolean resume = Doresume && mpendingactivitylaunches.isempty ();
            try {
                final int result = startactivityunchecked (
                        pal.r, pal.sourcerecord, NULL, NULL, PAL.STARTFLAGS, resume, nul L, NULL);
                Poststartactivityuncheckedprocessing (
                        pal.r, result, MSupervisor.mFocusedStack.mStackId, Msourcerecord,
                        mtargetstack);
            } catch (Exception e) {
                slog.e (TAG, "Exception during pending activity launch pal=" + pal, E);
                Pal.senderrorresult (E.getmessage ());}}}
    

In the startactivityunchecked function:

    private int startactivityunchecked (final Activityrecord R, Activityrecord Sourcerecord,
            ivoiceinteractionsession Voicesession, Ivoiceinteractor voiceinteractor,
            int startflags, Boolean doresume, activityoptions options, Taskrecord intask) {
				msupervisor.resumefocusedstacktopactivitylocked ();
			}

Go to the resumefocusedstacktopactivitylocked function in Activitystacksupervisor.java:

    Boolean resumefocusedstacktopactivitylocked (
            activitystack targetstack, Activityrecord target, activityoptions Targetoptions) {
        if (targetstack! = null && isfocusedstack (targetstack)) {
            return Targetstack.resumetopactivityuncheckedlocked (target, targetoptions);
        }

Then went into the Activitystack.java in the resumetopactivityuncheckedlocked function, very complex ... Again into the resumetopactivityinnerlocked function:

Private Boolean resumetopactivityinnerlocked (Activityrecord prev, activityoptions options) {
	startpausinglocked ( Userleaving, False, True, Dontwaitforpause);
	Mstacksupervisor.startspecificactivitylocked (Next, true, true);
}

Startpausinglocked should be the activity that paused the activity and then go back to the startspecificactivitylocked function in Activitystacksupervisor:

    void startspecificactivitylocked (Activityrecord R, Boolean Andresume, Boolean checkconfig) {//IS
        This activity ' s application already running?

        Processrecord app = mservice.getprocessrecordlocked (R.processname, R.info.applicationinfo.uid, true);

        R.task.stack.setlaunchtime (R); if (app! = null && App.thread! = null) {try {if (R.info.flags&activityinfo.flag _multiprocess) = = 0 | | !"
                    Android ". Equals (R.info.packagename)) {//Don ' t add this if it's a platform component that's marked  To run in multiple processes, because this is actually//part of the framework
                    So doesn ' t do sense to track as a//separate apk in the process. App.addpackage (R.info.packagename, R.info.applicationinfo.versioncode, Mservice.mprocessstats)
         ;       } realstartactivitylocked (r, App, Andresume, Checkconfig);
            Return } catch (RemoteException e) {SLOG.W (TAG, "Exception when starting activity" + R.
            Intent.getcomponent (). Flattentoshortstring (), E);
        }//If a Dead object exception was thrown – fall through to//restart the application. } mservice.startprocesslocked (R.processname, R.info.applicationinfo, True, 0, "activity", r.int
    Ent.getcomponent (), False, False, true); }

This is because the activated activity is not the first activity of the app, so the information on the app above is not null and goes into realstartactivitylocked:

    Final Boolean realstartactivitylocked (Activityrecord R, Processrecord app,
            boolean Andresume, Boolean checkconfig) Throws RemoteException {
			app.thread.scheduleLaunchActivity (new Intent (r.intent), R.apptoken,
                    System.identityhashcode (R), R.info, new Configuration (mservice.mconfiguration),
                    new configuration ( Task.moverrideconfig), R.compat, R.launchedfrompackage,
                    task.voiceinteractor, App.repprocstate, R.icicle, R.persistentstate, results,
                    newintents,!andresume, Mservice.isnexttransitionforward (), profilerinfo);
	}

The app.thread here is the remote Binder agent, which is initialized in the ontransact in activitymanagernative:

    public boolean ontransact (int code, PARCEL data, Parcel reply, int flags)
            throws remoteexception {
        switch (code) { Case
        Start_activity_transaction:
        {
            data.enforceinterface (iactivitymanager.descriptor);
            IBinder B = Data.readstrongbinder ();
            Iapplicationthread app = Applicationthreadnative.asinterface (b);
    static public Iapplicationthread asinterface (IBinder obj) {
        if (obj = = null) {
            return null;
        }
        Iapplicationthread in =
            (iapplicationthread) obj.querylocalinterface (descriptor);
        if (in = null) {
            return in;
        }

        return new Applicationthreadproxy (obj);
    

You can see that this proxy is a applicationthreadproxy type, and calling Schedulelaunchactivity will go into the stub implementation class (Applicationthread):

        Public final void Schedulelaunchactivity (Intent Intent, ibinder token, int ident,
                activityinfo info, Configuration cu Rconfig, Configuration overrideconfig,
                compatibilityinfo compatinfo, String referrer, Ivoiceinteractor Voiceinteractor,
                int procstate, Bundle state, Persistablebundle persistentstate,
                list<resultinfo> Pendingresults, List<referrerintent> pendingnewintents,
                boolean notresumed, Boolean Isforward, Profilerinfo profilerinfo) {
			.
			.
            SendMessage (h.launch_activity, R);
        }
    private void SendMessage (int what, Object obj, int arg1, int arg2, Boolean async) {
        mh.sendmessage (msg);
    }

Here MH is the handler type, sending a message to let it switch to the main thread processing:

    Private class H extends Handler {
        public void Handlemessage (Message msg) {
            if (debug_messages) slog.v (TAG, ">>> handling:" + codetostring (msg . what));
            Switch (msg.what) {case
                launch_activity: {
                    trace.tracebegin (Trace.trace_tag_activity_manager, " Activitystart ");
                    Final Activityclientrecord r = (activityclientrecord) msg.obj;

                    R.packageinfo = Getpackageinfonocheck (
                            r.activityinfo.applicationinfo, r.compatinfo);
                    Handlelaunchactivity (R, NULL, "launch_activity");
                    Trace.traceend (Trace.trace_tag_activity_manager);
                } Break


Enter Handlelaunchactivity:

    private void Handlelaunchactivity (Activityclientrecord R, Intent customintent, String reason) {
		Activity a = PERFORML Aunchactivity (R, customintent);
		
		Handleresumeactivity (R.token, False, R.isforward,
        !r.activity.mfinished &&!r.startsnotresumed, R.lastprocessedseq, reason);
	}

Enter Handleresumeactivity:

    Private Activity Performlaunchactivity (Activityclientrecord R, Intent customintent) {Activity activity = nul
        L
            try {java.lang.ClassLoader cl = R.packageinfo.getclassloader ();
            Activity = minstrumentation.newactivity (cl, Component.getclassname (), r.intent);
            Strictmode.incrementexpectedactivitycount (Activity.getclass ());
            R.intent.setextrasclassloader (CL);
            R.intent.preparetoenterprocess ();
            if (r.state! = null) {R.state.setclassloader (CL);
		}} Application App = R.packageinfo.makeapplication (false, minstrumentation);
		Context AppContext = createbasecontextforactivity (r, activity);
		Configuration config = new configuration (mcompatconfiguration); Activity.attach (AppContext, this, getinstrumentation (), R.token, R.ident, app, R.intent, R.activit Yinfo, title, R.parent, R.embeddedid, R.lastnonconfigurationinstances, config, r.referrer, r.voiceinteractor, window); }

Finally, you can see that you create the activity with instrumentation, then create application, Contextimpl, configuration, and so on, and then call the activity's attach function, Associates the created object to the activity.


Activity startup process is tracked here, some functions in the middle of the description is not very clear, the following gives a picture to summarize:


 

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.