The original App started like this, just read it

Preface

When we click on the software icon on the screen of the mobile phone, we can open the software. The seemingly simple process actually contains a lot of low-level interaction. You don't understand it yet. Welcome to call me.

Introduction to Startup Process

The first thing to know is that the mobile screen is actually an Activity, which we call Launcher professionally. We believe that friends who have developed in-car devices will not be unfamiliar. Launcher is provided by mobile phone manufacturers. Different mobile phone manufacturers compete with each other in Launcher's design.Of course, we can write Launcher ourselves, run it on our mobile phone and use our desktop style. Of course, we won't talk about how to write a Launcher here. If you're interested, please follow me.

Friends who have written about AndroidDemo must know that we must configure Activeness to start by default in the AndroidManifest configuration file.

<intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> 

It's just telling Launcher which page to launch the App on.This allows PackageManger-Service to read from the configuration file which Activity should be started when the system starts.

The second thing to know is that Launch and other APP s run in different processes, so their communication is done through Binder, so AMS is essential.Let's take starting WeChat as an example to see how the startup process works.

A simple summary of the process used to start WeChat is:

1.Launcher tells AMS to start WeChat and tells AMS which page to start, which page is the first page
2.AMS receives a message telling Launcher that it knows and writes down the page to start
3.Launcher enters Paused state, tell AMS, you go to find WeChat

That's how Launcher and AMS interact

4.AMS checks whether WeChat is started, that is, running in the background. If it is running in the background, it starts directly. If not, AMS creates an ActivityThread object in the new process and starts the main function in it.
5. After WeChat starts, tell AMS that it is ready to start
6.AMS finds the front page of Wechat from previous records and tells Wechat which page to launch.
7. WeChat started successfully by following the page of AMS notification.

The above stage is the interaction process between WeChat and AMS.Now let's analyze the process

Start process analysis

When you click on the WeChat icon on Launcher, the startActivitySafely method is called. The key information in intent that carries WeChat is the default startup page information that we configure in the configuration file. In fact, Launcher recorded the startup information when WeChat was installed. The icon is just a shortcut entry.

The startActivitySafely method will eventually call the Activity's startActivity method

@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
} 

The startActivity method eventually returns to the startActivityForResult method, where the code of the startActivityForResult method is -1, indicating that startActivity does not care about starting successfully.The startActivityForResult section method is as follows:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        if (requestCode >= 0) { 

The startActivityForResult method calls the mInstrumentation.execStartActivity method again, and we see that one of the parameters is

mMainThread.getApplicationThread() 

As mentioned in the article on ActivityThread's in-depth understanding of Android messaging mechanisms, ActivityThread was created when APP was started. ActivityThread stands for the Application. The most commonly used Application we develop is in the context of ActivityThread, which is often used in development, but has a low status in Android systems.

Android's main function is in ActivityThread

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    SamplingProfilerIntegration.start();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser(); 

Go back to the above method

mMainThread.getApplicationThread() 

The result is a Binder object, representing Launcher's App process, and mToken is actually a Binder object, representing Launcher's Activity passed to AMS via Instrumentation so that AMS knows who initiated the request.

mInstrumentation.execStartActivity

The official documentation for instrumentation is:

http://developer.android.com/intl/zh-cn/reference/android/app/Instrumentation.html

Instead of detailing instrumentation here, let's move on to the mInstrumentation.execStartActivity method

public Instrumentation.ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread)contextThread;
    if(this.mActivityMonitors != null) {
        Object e = this.mSync;
        synchronized(this.mSync) {
            int N = this.mActivityMonitors.size();

            for(int i = 0; i < N; ++i) {
                Instrumentation.ActivityMonitor am = (Instrumentation.ActivityMonitor)this.mActivityMonitors.get(i);
                if(am.match(who, (Activity)null, intent)) {
                    ++am.mHits;
                    if(am.isBlocking()) {
                        return requestCode >= 0?am.getResult():null;
                    }
                    break;
                }
            }
        }
    }

    try {
        intent.setAllowFds(false);
        intent.migrateExtraStreamToClipData();
        int var16 = ActivityManagerNative.getDefault().startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null?target.mEmbeddedID:null, requestCode, 0, (String)null, (ParcelFileDescriptor)null, options);
        checkStartActivityResult(var16, intent);
    } catch (RemoteException var14) {
        ;
    }

    return null;
}

In fact, this class is a Binder communication class, equivalent to IPowerManager.java, which implements IPowerManager.aidl. Let's look at getDefault again.

public static IActivityManager getDefault() {
    return (IActivityManager)gDefault.get();
} 

The getDefault method yields an IActivityManager, an interface that implements IInterface, which defines the life cycle of four components

public static IActivityManager asInterface(IBinder obj) {
    if(obj == null) {
        return null;
    } else {
        IActivityManager in = (IActivityManager)obj.queryLocalInterface("android.app.IActivityManager");
        return (IActivityManager)(in != null?in:new ActivityManagerProxy(obj));
    }
} 

Eventually returns an ActivityManagerProxy object, AMP, which is the proxy object of AMS. When it comes to proxy as proxy mode, I can keep an eye on what proxy mode is and the use of dynamic and static proxies. A separate article will follow.

AMP startActivity method

public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken("android.app.IActivityManager");
    data.writeStrongBinder(caller != null?caller.asBinder():null);
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo);
    data.writeString(resultWho);
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    data.writeString(profileFile);
    if(profileFd != null) {
        data.writeInt(1);
        profileFd.writeToParcel(data, 1);
    } else {
        data.writeInt(0);
    } 

The main thing is to write the data into the AMS process and wait for the results of AMS to return. This process is rather dull, because we can only plug-in the client Hook, not the server, so we can only watch quietly.(Warm Tip: If you're already a bit dizzy at this point, that's right. The main way to study the source code is to comb the whole process. Don't tangle with the details of the source code, you won't be able to extricate yourself.)

AMS processes Launcher's information

AMS tells Launcher I know, so how does AMS tell Launcher?

Binder's communication is equal, who sends the message is the client, and who receives the message is the server. Launcher's process has been passed in before. AMS saves it as an ActivityRecord object, which contains an ApplicationThreadProxy, which is the proxy object for Binder. AMS sends messages through ApplicationTreadProxy, which App receives through ApplicationThreadMessages.

Launcher receives the message and tells AMS again. Okay, I know, I'm going. ApplicationThread calls the sendMessage method of ActivityThread to send a message to the Launcher main thread.This is when AMS starts a new process and creates an ActivityThread, specifying the main function entry.

When you start a new process, you create an ActivityThread object for the process, which is the UI thread. When you enter the main function, you create a Looper, or mainLooper, and you create an Application, so the Application is just important to the developer.Once created, tell AMS WeChat is started, AMS records the registration information for this APP, and then AMS sends messages to APP through this ActivityThread.

At this time AMS tells WeChat which Activity to start based on previous records, and WeChat can start.

public void handleMessage(Message msg) {
    ActivityThread.ActivityClientRecord data;
    switch(msg.what) {
    case 100:
        Trace.traceBegin(64L, "activityStart");
        data = (ActivityThread.ActivityClientRecord)msg.obj;
        data.packageInfo = ActivityThread.this.getPackageInfoNoCheck(data.activityInfo.applicationInfo, data.compatInfo);
        ActivityThread.this.handleLaunchActivity(data, (Intent)null);
        Trace.traceEnd(64L); 
ActivityThread.ActivityClientRecord 

It's Activity from AMS

data.activityInfo.applicationInfo 

summary

The attributes we get are called LoadedApk, which extracts all the resources in the apk, so how do the pages jump inside the APP? For example, if we jump from ActivityA to ActivityB, we can think of Activity as Launcher. The only difference is that under normal circumstances, ActivityB and ActivityA are in the same process, so we don't create new processes.

That's how APP started. Click on my avatar to see more of my articles.

Finally, for Android programmers, I've sorted out some information for you, including advanced UI, performance optimization, architect courses, NDK, ReactNative+Weex Wechat applets, Flutter and other advanced Android practice techniques. I hope to help you, save you time to search for information on the web, and also share the dynamics.Learn with your friends!

A group of free guided learning notes for architecture that needs to be expanded Android Architecture Design Mass(185873940)

Keywords: Android Mobile Java

Added by upnxwood16 on Fri, 31 May 2019 19:12:21 +0300