background

Engaged in development to a certain stage, want to improve the system must understand some of the working principle. Why is that? Because only by understanding this can you write good code for the features of your platform. When faced with a tough problem, you will be able to integrate system principles more quickly to find the optimal solution. The subbase determines the superstructure. The same principle applies to development. I’m an advocate of going back to basics. Advanced functions are always made up of the most basic elements, just as a few elements make up the material world of unimaginable richness. Only by mastering the basics can you unleash an incredible burst of creativity!

Pay attention to the basics, return to the basics. Go back to the beginning and find inspiration. Wish to share with you ✌️!

A diagram illustrates the Activity startup process




This article focuses on the process from an App startup to an Activity executing onCreate(). The life cycle of an Activity is familiar.

In the figure above, I have listed all the class names and methods involved. You can look at the process, open the source code and follow through. I believe that after a time, in the future development you will be more confident!

The image above may seem dazzling at first, but fear not. There’s nothing there at all, you just have to start with the blue arrow, and you’ll see that you’re done. With this brief analysis, you should be able to figure out the Activity startup process in 3 minutes.

About the Activity starts, I’m from the Thread of the ask to meng 】 【 refused to talk about the Handle, the context of https://juejin.cn/post/6844903844619485197 is mentioned. This article focuses on what threads are and the messaging mechanism in Android. You can click on the link to have a look.

It all starts with the main() method

In Android, an application starts with the main() method in ActivityThread.java. Those of you who have studied Java know that the entry point to Java programs is the main() method. In this sense, we can think of it as a Java program (note that Android is not a Java program).

As you can see from the figure above, the main() method does the following:

  1. Initialize the main thread Looper, master Handler. And put the main thread into an infinite loop waiting to receive a Message. For details about Android’s Handler mechanism, check out the article I mentioned above: “From the Thread of ask to meng 】 【 refused to talk about the Handle” https://juejin.cn/post/6844903844619485197 below is the main () method is the key code:
public static void main(String[] args){... Looper.prepareMainLooper();// Initialize Looper. ActivityThread thread =new ActivityThread();
    // Instantiate an ActivityThread
    thread.attach(false);
    // The last thing this method does is send a message to create the Application. Looper.loop();// The main thread enters an infinite loop, waiting to receive messages
}

Copy the code

2. The attach() method is called to send a message that initializes the Application. This process is either long or short. More on this below.

How is the message to create the Application sent?

As mentioned above, the ultimate purpose of the Attach () method for ActivityThread is to send an Application creation message, H.bin_application, to the main thread’s main Handler. So let’s see what the attach() method does. Attach () Key code:

public void attach(boolean system){...final IActivityManager mgr = ActivityManagerNative.getDefault();  
    // Get the IActivityManager instance and see what it is
    try {
        mgr.attachApplication(mAppThread);
         // See? The key. The mAppThread parameter is also described below
    } catch (RemoteException ex) {
        throwex.rethrowFromSystemServer(); }... }Copy the code

Take a look at the two objects above.

What is the IActivityManager MGR?

Can see from the above graph that IActivityManager is an interface, when we call ActivityManagerNative. GetDefault () to obtain the actual is a proxy class instance — ActivityManagerProxy, This thing implements the IActivityManager interface. Open the source code and you will see that ActivityManagerProxy is an inner class of ActivityManagerNative. As you can see, the Android team is following the principle of least surprise in the design process, putting related things together as much as possible. So since it’s a proxy class, who does it represent? Let’s see in the code. The following code is a bit convoluted! Brother, hold on!

  1. Let’s start with the ActivityManagerProxy constructor:
public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
}
Copy the code

This constructor is very simple. It first takes an IBinder parameter, which is then assigned to the mRemote variable. This mRemote is obviously a member variable of the ActivityManagerProxy, and operations on it are mediated indirectly by the ActivityManagerProxy. This design has the advantage of protecting the mRemote and being able to perform other transactions before manipulating the mRemote, which we do as IActivityManager! This is very clever.

  1. So where is the constructor called?
static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    // Check to see if there is any
    if(in ! =null) {
        returnin; }...return new ActivityManagerProxy(obj);
    // This is where the constructor is called
}
Copy the code

The above method is a static method in ActivityManagerNative that calls the constructor of ActivityManagerProxy. However, this static method also requires an IBinder as an argument! The old man was confused. But no fear, let’s keep looking!

  1. GetDefault () Gets the static constant gDefault
private static final Singleton<IActivityManager> gDefault = 
  new Singleton<IActivityManager>() {
    protected IActivityManager create(a) {
       IBinder b = ServiceManager.getService("activity");
       // What's the point? This is where the IBinder instance is obtained.. IActivityManager am = asInterface(b);// call the above method..returnam; }};Copy the code

This is the static constant of ActivityManagerNative, which is a singleton. I finally get the IBinder instance I’ve been using up until now.

IBinder b = ServiceManager.getService("activity");
Copy the code

Try to find the corresponding position in the figure above.

Here, the ServiceManager gets the IBinder instance. If you know the AIDL communication process before. This might be a little easier to understand, but it’s just another way to get an IBinder instance. The purpose of obtaining the IBinder is to communicate with ActivityManager through this IBinder, which in turn schedules the sending of H.bin_application, the Message that initializes the Application. This is all you need to know if you have never worked with a Binder mechanism before. I’ll write an article about Binder in Android later. Of course, you can also refer to luo Da’s series of articles, written in detail, very great! 【 Android interprocess communication Binder mechanism in Java application framework layer interface source code analysis] http://m.blog.csdn.net/article/details?id=6642463.

  1. Take a look at attachApplication(mAppThread).
public void attachApplication(IApplicationThread app){... mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply,0); . }Copy the code

This approach is illustrated in the figure above.

The above sentence is the key to this method. The IBinder instance’s tansact() method is called and the parameter app(mentioned later) is put into data, which is eventually passed to ActivityManager.

At this point, we basically know what IActivityManager is. The most important implementation class is ActivityManagerProxy, which primarily represents Binder instances in the kernel that communicate with ActivityManager. Let’s look at ApplicationThread mAppThread.

What is an ApplicationThread?

  1. In the ActivityThread member variables, you can find:
final ApplicationThread mAppThread = new ApplicationThread();
Copy the code

ApplicationThread appears as a constant in ActivityThread. This indicates that the system does not want this variable to be modified midway, so this variable has a specific and very important role to play.

  1. Let’s see what he is.
private class ApplicationThread extends ApplicationThreadNative{... }Copy the code

ApplicationThread is an internal class in ActivityThread. Why not write it somewhere else? I think this is also an exercise in the principle of least surprise. Because ApplicationThread is specifically true to the object used here.

  1. It inherits from ApplicationThreadNative, so let’s see what it is.
public abstract class ApplicationThreadNative extends Binder 
    implements IApplicationThread{...// No argument constructor
    public ApplicationThreadNative(a) {
        // This is Binder
        attachInterface(this, descriptor); }... }Copy the code

Obviously, ApplicationThread is ultimately a Binder! It is also an IApplicationThread because it implements the IApplicationThread interface. You can find all the corresponding relationships in the figure above.

The constructor used by the ApplicationThread we saw in ActivityThread is parameterless, so look what the parameterless constructor did!

Binder’s attachInterface(IInterface Owner, String Descriptor) method is nothing special except assignment.

public void attachInterface(IInterface owner, String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}
Copy the code

4. What is IApplicationThread? Tie, come on! We keep digging.

public interface IApplicationThread extends IInterface {... String descriptor ="android.app.IApplicationThread"; 
    // Take note of this parameter. }Copy the code

Well, that’s not in the picture above. I’m digging something up. But study, let’s have a look.

IApplicationThread is an interface that inherits from IInterface, so we need to pay attention to the descriptor argument. We’ll use it later, but it’s an identifier that’s important when you’re querying.

Ok, so we finally know what the two objects in the attach() method are. ApplicationThread, as an instance of IApplicationThread, is responsible for sending the Activity lifecycle and other messages at the end. In other words, you go all the way around and end up back here to send the message. I wipe!

You may be wondering why we have to detour since we already created an ApllicationThread in ActivityThread. Of course, to allow the system to control the process, otherwise why upload ApplicationThread to ActivityManager?

ActivityManagerService schedules the sending of initialization messages

After all this work, ApplicationThread is finally in ActivityManagerService. Please find the corresponding location in the picture above!

As you can see from the figure above, ActivityManagerService has one of these methods:

private final boolean attachApplicationLocked(IApplicationThread thread
, int pid) {... thread.bindApplication();// Pay attention!. }Copy the code

ApplicationThread passes into ActivityManagerService as an IApplicationThread. After a series of operations, it calls its own bindApplication() method. Issue a message to initialize Applicationd.

public final void bindApplication(String processName, 
    ApplicationInfo appInfo,
    List<ProviderInfo> providers, 
    ComponentName instrumentationName,
    ProfilerInfo profilerInfo, 
    Bundle instrumentationArgs,
    IInstrumentationWatcher instrumentationWatcher,
    IUiAutomationConnection instrumentationUiConnection, 
    int debugMode,
    boolean enableBinderTracking, 
    boolean trackAllocation,
    boolean isRestrictedBackupMode, 
    boolean persistent, 
    Configuration config,
    CompatibilityInfo compatInfo, 
    Map<String, IBinder> services, 
    Bundle coreSettings){... sendMessage(H.BIND_APPLICATION, data); }Copy the code

Scaring old paper! So many parameters. This obviously violates the principle of parameters as little as possible! That said, sometimes it’s hard to avoid parameter accumulation during development. Nor can it be generalized.

However, at this point, all we need to know is that an H.bin_application message is sent at the end, and the program starts.

The world after receiving the initialization message

Above we found where the message to initialize Applicaitond was sent. Now, you need to take a look at what happened after you received the message.

Now find the first message under H in the figure above: H.bin_application. Once you receive this message, start creating the Application. This process is done in handleBindApplication(). Look at this method. You can see the corresponding method in the figure above.

private void handleBindApplication(AppBindData data) {... mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()) .newInstance();// Initialize an Instrumentation with reflection. That will be explained later.. Application app = data.info.makeApplication(data.restrictedBackupMode,null);
    // Create an Application instance using the LoadedApp commandmInitialApplication = app; . mInstrumentation.callApplicationOnCreate(app);// Call Application's onCreate() method. }Copy the code

HandleBindApplication () is a long method, but I’ve highlighted the above lines for you. They are crucial to the subject of this article. Several new objects appear in the above short code. I’ll tell you all about it.

Instrumentation? What the hell?

1. This thing called Instrumentation is very strange, let’s translate it as Instrumentation. There’s literally no clue as to what it is. But we can open the document and see.

Instrumentation is instantiated before any code in the application runs and allows you to monitor all interactions between the application and the system.

That’s about it.

2. However, we can see from the above code that Instrumentation is indeed created before Application initialization. So how does it implement monitoring application and system interaction?

Open this class and you can see that the final Apllication creation, Activity creation, and life cycle are all performed through this object. Simply put, these operations are wrapped in a layer. By operating Instrumentation to achieve the above functions.

3. So what are the benefits? Think about it. Instrumentation as an abstraction, when we agreed to implement the function, we just need to add these abstract functions to Instrumentation, and then call. The rest, however, is left to the Instrumentation implementation object. Ah! This is an application of polymorphism. Ah! This relies on abstraction, not concrete practice. Ah! It is the practice of dependency inversion principle that the upper level puts forward requirements and the lower level defines interfaces. Oh! So much for abstraction.

As you can see from the code, the way to instantiate Instrumentation here is reflection! The reflected ClassName comes from Binder passed in from ActivityManagerService. Too deep! Is to hide the concrete implementation object. But then the coupling is very low.

4. All right, enough nonsense. While we are talking about Instrumentation, look at the callApplicationOnCreate() method tuned last.

public void callApplicationOnCreate(Application app) {
    app.onCreate();
}
Copy the code

You read that right. It didn’t do anything. Just call Application’s onCreate() method. That’s why it can be used for monitoring.

In the figure above you can see the Instrumentation and how it interacts.

LoadedApk is data.info.

I won’t talk about how it came about in this paper, but maybe in the future. This article just looks at the process. So just go in and see what its makeApplication() does, and create the Application.

public Application makeApplication(boolean forceDefaultAppClass,
    Instrumentation instrumentation) {... String appClass = mApplicationInfo.className;//Application class name. Obviously reflection is going to be used.. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread ,this);
    // Take note of Context
    app = mActivityThread.mInstrumentation
        .newApplication( cl, appClass, appContext);
    // Create the Application from the meter. }Copy the code

In this method, all we need to know is that after getting the actual class name of the Application, the final creation is left to Instrumentation, as mentioned earlier.

It’s worth noting that, as noted above, when you need to fetch the Application a second time, you just need to call this method again. “How convenient!

Now look back to the Instrumentation

Take a look at how the Application creation is done in newApplication().

static public Application newApplication(Class
         clazz , Context context) throws InstantiationException
    , IllegalAccessException
    , ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        // Create a reflection
        app.attach(context);
        // Pay attention to the first method called after Application is created.
        // The purpose is to bind the Context.
        return app;
    }
Copy the code

Oh, my God, after all this work, the Application has been created. Give yourself a little red flower!

LaunchActivity

When the Application is initialized, the system sends an Intent to start the Activity with the specified Manifests. This process will be discussed next time. Basically see flow!

  1. Immediately, H receives a LAUNCH_ACTIVITY message. Then start the Activity initiation journey. Once the message is received, the real processing takes place in the handleLaunchActivity() in the ActivityThread. Can’t wait to see what’s going on? Find the corresponding steps in the figure above!
private void handleLaunchActivity(ActivityClientRecord r , Intent customIntent , String reason) {... Activity a = performLaunchActivity(r, customIntent);/ / damned! It's wrapped in another method..if(a ! =null) {... handleResumeActivity(r.token ,false, r.isForward ,! r.activity.mFinished && ! r.startsNotResumed , r.lastProcessedSeq, reason);// The Activity is created successfully and goes to onResume()!. }}Copy the code

As can be seen from the above code… Well, it doesn’t make any sense!

  1. Let’s go one more way.
private Activity performLaunchActivity(ActivityClientRecord r , Intent customIntent) {... activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);// Create the Activity from the meter. Application app = r.packageInfo.makeApplication(false
     , mInstrumentation);
     // As mentioned earlier, we are getting Application. activity.attach(appContext ,this
        , getInstrumentation()
        , r.token
        ,.ident
        , app
        , r.intent
        , r.activityInfo
        , title
        , r.parent
        , r.embeddedID
        , r.lastNonConfigurationInstances
        , config
        ,r.referrer
        , r.voiceInteractor
        , window);
    // The method appears!.if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(
          activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    // Select the onCreate() method depending on whether it can be persisted.. }Copy the code

This method has a lot of content, so let’s look at it one by one.

activity = mInstrumentation.newActivity(
         cl, component.getClassName(), r.intent);
Copy the code

As mentioned earlier, the creation and lifecycle of activities and applications are outsourced to Instrumentation. So it’s in charge. Look what Instrumentation did.

public Activity newActivity(ClassLoader cl, String className, Intent intent)
            throws InstantiationException
            , IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
        // Nothing really. Reflection instantiates the Activity
    }
Copy the code

It just reflects an Activity.

if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(
          activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
Copy the code

Select the Activity’s onCreate() method based on whether it can persist. OnCreate () is also performed using Instrumentation. Their respective onCreate() methods are:

onCreate(icicle, persistentState);
// Persistent data is available
Copy the code

and

onCreate(icicle);
// The number of pages that you want to write.
Copy the code

The middle two methods to pay attention to it, not to explain, interested in the point source code to see.

At this point, the Activity starts! How’s that? It’s not complicated.

conclusion

That’s the end of this piece. This main process starts with the Application creation and ends with the first Activity onCreate(). This process is not long, the key is combined with the above figure. I’ve highlighted the key points in different colors.

See the students here reward themselves with a pack of latiao!

Refer to the link

  1. Android interprocess communication Binder mechanism in the application framework layer Java interface source code analysis

    】 http://m.blog.csdn.net/article/details?id=6642463

  2. [Instrumentation API] https://developer.android.com/reference/android/app/Instrumentation.html

  3. The Activity start process (below) 】 【 http://www.jianshu.com/p/3cf90c633bb1

  4. The Android learning – ActivityManager to use the Proxy mode] http://www.cnblogs.com/bastard/archive/2012/05/25/2517522.html

  5. [ActivityManager API] https://developer.android.com/reference/android/app/ActivityManager.html

Thank you for reading. Be sure to give CoorChice a like and follow if you find it helpful. Thanks!