Analyze the startup process for Android applications _android

Source: Internet
Author: User
Tags prev

Objective

Before we begin, we hope you can best meet the following conditions:

1, have a compiled Android source code (hands-on practice will have a more in-depth understanding)

2, a certain understanding of the binder mechanism

This article starts the process analysis based on the Android 5.1 source code. Why is 5.1 of the source code? Because the code compiled at hand only this version ... In addition, what version of the source code is not important, the general process does not differ in nature, just to achieve the details of the adjustment, to find a familiar version of you just fine.

1. Start sequence diagram

As a person with minor obsessive-compulsive disorder, arrange the sequence diagram, I believe we netizens, we can understand the whole start-up process:

Note: To give you a clearer understanding of the entire process, divide the sequence diagram into three parts: thelauncher process , thesystem process , theapp process , which involves a common class with L/ A a distinction indicates which process is relevant and easy to understand.

2. Key class Description

The entire start-up process because it involves multiple binder communications, here is a brief description of the use of several classes to facilitate the understanding of the entire interactive process:

1, Activitymanagerservice: AMS is one of the core of Android services, mainly responsible for the four components of the system start-up, switching, scheduling and application process management and scheduling, and its responsibilities and operating systems in the process management and scheduling module is similar, so it is very important in Android, It is also a binder implementation class in itself.

2, Instrumentation: As the name suggests, it is used to monitor the interaction between applications and systems.

3, Activitythread: The application of the entry class, the system by calling the main function, open the message loop queue. Activitythread is called the main thread of the application (UI thread).

4, Applicationthread: Applicationthread provides a binder communication interface, and AMS invokes the local method of this app process through an agent.

5, Activitymanagerproxy: AMS services in the current process of the proxy class, is responsible for communication with AMS.

6, Applicationthreadproxy: Applicationthread is a proxy class in AMS service and is responsible for communicating with Applicationthread.

3. Process Analysis

The first account of the entire process analysis of the scene: the user clicks on the application icon on the launcher to the application of the main interface to launch the display in front of the user .

This whole process involves communicating across processes, so we divide it into three processes that are shown in a sequence diagram: Thelauncher process , thesystem process , and theapp process . To describe the process of interacting between processes without too long code, here is a brief description of several important interaction points.

You can also see from the sequence diagram that the call chain is quite long, the corresponding amount of code is also relatively large, and the sequence diagram is only the analysis of the process in this scenario. The road is long, and the line will come!

3.1 Launcher respond to user clicks, notify AMS

Launcher as an application of the entrance, or it is necessary to explain, we look at the Launcher code fragment, launcher use is the Packages/apps/launcher3 source.

public class Launcher extends activity implements View.onclicklistener, Onlongclicklistener, Launchermodel.callbacks, View.ontouchlistener, Pageswitchlistener, Launcherproviderchangelistener {.../** * launches the intent referred
  by the clicked shortcut.
  * * @param v The view representing the clicked shortcut. /public void OnClick (View v) {/* sure that rogue clicks Don ' t get through while AllApps is launching, or after
  The//view has detached (it's possible for this to happen if the view is removed mid touch).
  if (v.getwindowtoken () = = null) {return;

  }

  ...
  Object tag = V.gettag ();
  if (tag instanceof shortcutinfo) {onclickappshortcut (v);
  else if (tag instanceof folderinfo) {...} else if (v = = Mallappsbutton) {Onclickallappsbutton (v);
  else if (tag instanceof AppInfo) {startappshortcutorinfoactivity (v);
 else if (tag instanceof launcherappwidgetinfo) {...} } private void StartappshortcutorinfoactiviTy (View v) {... boolean success = startactivitysafely (V, intent, tag);
 
 ...
 } 
  Boolean startactivitysafely (View V, Intent Intent, Object tag) {... try {success = StartActivity (V, Intent, tag);
  The catch (Activitynotfoundexception e) {...}
 return success;
  Boolean startactivity (View V, Intent Intent, Object tag) {intent.addflags (intent.flag_activity_new_task); try {... if (user = null | | user.equals (Userhandlecompat.myuserhandle ())) {//could be launching some Bookke
   Eping Activity startactivity (Intent, optsbundle);
   } else {...}
  return true;
  The catch (SecurityException e) {...}
 return false; }
}

The Activity:startActivityForResult code snippet is as follows by Staracticity and then calling to Instrumentation:execStartActivity the following:

public class Instrumentation {
 ...
 Public Activityresult execstartactivity,
   ibinder contextthread, IBinder token, activity target,
   Intent Intent, int requestcode, Bundle options) {iapplicationthread Whothread
  = (iapplicationthread) contextthread;
  ...
  try {
   ...
   .. int result = Activitymanagernative.getdefault ()
    . StartActivity (Whothread, Who.getbasepackagename (), intent,
      intent.resolvetypeifneeded (Who.getcontentresolver ()),
      token, target!= null target.mEmbeddedID:null,
      requestcode, 0, NULL, options);
   ...
  } catch (RemoteException e) {
  } return
  null;
 }
 ...
}

Here the ActivityManagerNative.getDefault return ActivityManagerService of the remote interface, that is, the ActivityManagerProxy interface, someone may ask why it is ActivityManagerProxy , this involves binder communication, which is no longer unfolding here. Through the binder driver, ActivityManagerProxy communicating with the AMS service, the process is implemented across processes to the system.

3.2 AMS responds to launcher process requests

From the above process we know that the AMS should handle the request from the launcher process, please refer to the sequence diagram and source code, at this time we look at the ActivityStackSupervisor:startActivityUncheckedLocked method, visual This method has more than 600 lines of code, to see some key snippets:

Public final class Activitystacksupervisor implements Displaylistener {... final int startactivityuncheckedlocked (ACTI Vityrecord R, Activityrecord Sourcerecord, Ivoiceinteractionsession voicesession, Ivoiceinteractor voiceInteractor, I
 NT Startflags, Boolean doresume, Bundle options, Taskrecord intask) {final Intent Intent = r.intent;
 Final int callinguid = R.launchedfromuid;
 ... final Boolean launchsingletop = R.launchmode = = Activityinfo.launch_single_top;
 Final Boolean launchsingleinstance = R.launchmode = = Activityinfo.launch_single_instance; 

 Final Boolean launchsingletask = R.launchmode = = Activityinfo.launch_single_task;
 int launchflags = Intent.getflags ();  ..//We ll invoke onuserleaving before OnPause only if the launching//activity did not explicitly
 An automated launch.
 Muserleaving = (Launchflags & intent.flag_activity_no_user_action) = = 0;
   
   ... Activityrecord nottop = (Launchflags & Intent.flag_activity_previouS_is_top)!= 0?

 R:null; If the onlyifneeded flag is set, then we can does this if the activity//being launched is the same as the one making T He call ... or, as/a special case, if we did not know the caller then we count the "/" as the Calle
   R. if ((startflags&activitymanager.start_flag_only_if_needed)!= 0) {...} ..//If The caller isn't coming from another activity, but has given us a//explicit task into which they would l
 IKE us to launch the "New Activity"//Then let's about doing that. if (Sourcerecord = = null && intask!= null && intask.stack!= null) {final Intent baseintent = intask.ge
 Tbaseintent ();
 Final Activityrecord root = intask.getrootactivity (); ...//If This task is empty, then we are adding the the "the" the "the" the "the" the "the" the "the", "the" and "determines" is must
 As a new_task.
 if (launchsingleinstance | | launchsingletask) {...}
   ...
 } ... if (intask = = null) {if (Sourcerecord == null) {//the ' not ' being started from another ... in this//case We-always-start a new task. if ((Launchflags & intent.flag_activity_new_task) = = 0 && intask = null) {SLOG.W (TAG, "StartActivity Calle D from the non-activity context;
  Forcing "+" Intent.flag_activity_new_task for: "+ Intent);
 Launchflags |= Intent.flag_activity_new_task; } else if (Sourcerecord.launchmode = = activityinfo.launch_single_instance) {//The original activity who is starting
 The US is running as a single//instance ... this new activity it are starting must go in its//own task.
 Launchflags |= Intent.flag_activity_new_task; Or else if (launchsingleinstance | | launchsingletask) {//The activity being started are a single instance ... it always/
 /gets launched into its own task.
 Launchflags |= Intent.flag_activity_new_task; }..//We may want to try-to-place the new, existing task. We always//Do this if the target activity is Singletask or singleinstance; We'll also do//this if New_task has been requested, and there are not a additional qualifier//us to telling Place it in a new Task:multi task, always doc mode, or being asked to//launch this as a new task behind the E. if ((Launchflags & Intent.flag_activity_new_task)!= 0 && (launchflags & Intent.flag_activity_mul tiple_task) = = 0) | | launchsingleinstance | | Launchsingletask) {//If bring to front are requested, and no result are requested and we have not//been given a expli CIT task to launch by, and//We can find a task that is started with this same//component, then instead of launch
 ING bring that one to the front. if (Intask = = NULL && R.resultto = null) {//The If there is a task to bring to the front. If This is//a single_instance activity, there can be one and only one//INSTANCE of it history, and it is Alwa Ys in it own//unique task, so we do a special SEArch.
  Activityrecord intentactivity =!launchsingleinstance?
 Findtasklocked (R): findactivitylocked (Intent, r.info);
 if (intentactivity!= null) {...}
   } ... if (r.packagename!= null) {//If the activity being launched is the same as the one currently
   At the top, then we need to check if it should is launched//once.
   Activitystack topstack = Getfocusedstack ();
   Activityrecord top = topstack.toprunningnondelayedactivitylocked (Nottop); if (top!= null && R.resultto = null) {if (Top.realActivity.equals (r.realactivity) && Top.userid = =
   R.userid) {...}
  
 } else{...}
 Boolean newtask = false;

 Boolean keepcurtransition = false;
    Taskrecord tasktoaffiliate = launchtaskbehind && sourcerecord!= null?

 SourceRecord.task:null;
 Should This is considered a new task? if (R.resultto = null && Intask = null &&!addingtotask && (launchflags & inteNt. 
      Flag_activity_new_task)!= 0 {... if (Reusetask = null) {R.settask (Targetstack.createtaskrecord (), Newtaskinfo!= null? Newtaskinfo:r.info, newtaskintent!= null?
    Newtaskintent:intent, Voicesession, Voiceinteractor,!launchtaskbehind//* totop); ...
   }
   else {r.settask (reusetask, tasktoaffiliate); }
    ...
 } else if (Sourcerecord!= null) {} else if (!addingtotask && (Launchflags&intent.flag_activity_reord Er_to_front)!= 0) {} else if (Intask!= null) {} else {} ... targetstack.startactivitylocked (
   
 R, NewTask, Doresume, keepcurtransition, Options);
 ... return activitymanager.start_success; }
 ...
}

The function is set by the intent flag value, and the findTaskLocked function is used to find the existence of such a task, where the result returned is null and intentActivity null, so a new task needs to be created to start this Activity . Now the top of the processing stack Activity is to Launcher MainActivity Activity start this by creating a new task that is not the same as the one we're about to start Activity .

After the stack top detection, you need to push launcher into the paused state before you can start a new Activity . Next call to ActivityStack:startPausingLocked , let's take a look at this function:

 final class Activitystack {... final Boolean startpausinglocked (Boolean userleaving, 
 Boolean uisleeping, Boolean resuming, Boolean dontwait) {if (mpausingactivity!= null) {...}
 Activityrecord prev = mresumedactivity;
 if (prev = = null) {...}
 ... mresumedactivity = null;
 mpausingactivity = prev;
 mlastpausedactivity = prev; Mlastnohistoryactivity = (Prev.intent.getFlags () & intent.flag_activity_no_history)!= 0 | | (Prev.info.flags & Activityinfo.flag_no_history)!= 0?
 Prev:null;
 Prev.state = activitystate.pausing; ... if (Prev.app!= null && prev.app.thread!= null) {try {... prev.app.thread.schedulePauseActivity prev
  . Apptoken, Prev.finishing, userleaving, Prev.configchangeflags, dontwait);
 The catch (Exception e) {...}
 } else {...}
 ...
 } 
...
}

Here prev.app.thread is the ApplicationThread remote interface of an object that schedulePauseActivity notifies launcher to enter the paused state by invoking the remote interface. At this point, the AMS request for launcher has been responded to, and this is what we found to be a callback to the launcher process via binder communication.

3.3 Launcher process suspend launcher, notify AMS again

This process is relatively simple, we look at ActivityThread :

Public final class Activitythread {
 ...
 private void Handlepauseactivity (IBinder token, Boolean finished,
   boolean userleaving, int configchanges, Boolean Dontreport) {
  Activityclientrecord r = mactivities.get (token);
  if (r!= null) {
   ...
   Performpauseactivity (token, finished, R.isprehoneycomb ());

   Make sure any pending writes are now committed.
   if (R.isprehoneycomb ()) {
    queuedwork.waittofinish ();
   }

   Tell the activity manager we have paused.
   if (!dontreport) {
    try {
     activitymanagernative.getdefault (). activitypaused (token);
    } catch ( RemoteException ex) {
    }
 }} ...
}

This section launcher the ActivityThread Processing page paused and again by ActivityManagerProxy notifying AMs.

3.4 AMs to create a new process

When the

Creates a new process, AMS saves a processrecord message. If we do not specify the process attribute for the application tag in the Androidmanifest.xml configuration file in the application, the system defaults to the package name. Each application has its own UID, so the combination of UID + process can create a processrecord for each application.

 Public final class Activitymanagerservice extends Activitymanagernative implements Wat Chdog. Monitor, Batterystatsimpl.batterycallback {... private final void startprocesslocked (Processrecord app, String hostingt  Ype, String hostingnamestr, String abioverride, String entrypoint, string[] entrypointargs) {...//Start The process.
  It'll either succeed and return a result containing//the PID of the new process, or else throw a runtimeexception.
  Boolean isactivityprocess = (entrypoint = = null);
  if (entrypoint = = null) EntryPoint = "Android.app.ActivityThread"; Process.processstartresult Startresult = Process.Start (entrypoint, App.processname, UID, uid, Gids, DebugFlags, Mount External, App.info.targetSdkVersion, App.info.seinfo, Requiredabi, Instructionset, App.info.dataDir, Entrypointa
  RGS); ...
 }
 catch () {...} 
}
 ...
}

The main thing here is to call the Process:start interface to create a new process, and the new process will import the android.app.ActivityThread class and execute its main function, which is why each application has an ActivityThread instance to correspond to.

3.5 Application Process Initialization

The function we look at Activity main here binds the looper of the main thread and goes into the message loop, and you should know that the entire Android system is message driven, which is why the main thread defaults to binding looper:

Public final class Activitythread {
 ...
 public static void Main (string[] args) {
  ...
  Looper.preparemainlooper ();

  Activitythread thread = new Activitythread ();
  Thread.attach (false);

  ...

  Looper.loop ();
  
  ...
 }
 
 private void Attach (Boolean system) {
  ...
  if (!system) {
   ...
   Final Iactivitymanager mgr = Activitymanagernative.getdefault ();
   try {
    mgr.attachapplication (mappthread);
   } catch (RemoteException ex) {
    //Ignore
   }}
  else { c29/> ...
  }
  ...
 }
 ...
}

The attach function eventually invokes the ActivityManagerService remote interface ActivityManagerProxy的attachApplication function, and the incoming argument is that mAppThread it is an object of a ApplicationThread type Binder , and its role is to communicate with the application process by the AMS.

3.6 Registering the application process in AMS, launching the boot stack top page

We mentioned that AMS is responsible for the start-up, switching, scheduling and application process management and scheduling of the four major components of the system, and through the previous process we know that the application process is created to interact with AMS through the Binder Drive, and AMS then registers the information after the application process has been created, If you take a registry of Windows System programs to understand this process, it may be more image.

mMainStack.topRunningActivityLocked(null)Remove the boot from the top of the stack Activity and realStartActivityLockedhan start the page in the function by ApplicationThreadProxy repatriating the app process.

Public final class Activitystacksupervisor implements Displaylistener {
 ...
 Final Boolean realstartactivitylocked (Activityrecord R,
   Processrecord app, Boolean Andresume, Boolean checkconfig)
   throws RemoteException {
  ...
  R.app = app;
  ...
   
  try {
  ...
  .. App.thread.scheduleLaunchActivity (New Intent (r.intent), R.apptoken,
     System.identityhashcode (R), R.info, new Configuration (mservice.mconfiguration),
     R.compat, R.launchedfrompackage, R.task.voiceinteractor, App.repprocstate,
     r.icicle, r.persistentstate, results, newintents,!andresume,
     Mservice.isnexttransitionforward (), profilerinfo);
  ...
  } catch (RemoteException e) {
  ...
  }
  ...
 }
 ...
}

At this point in the app process, we can see that the call chain after some columns is finally called to the MainActivity:onCreate function, then it is called onResume , and then the AMS is notified that it is MainActivity already in resume state. At this point, the entire boot process is over.

4, summary

Through the above process, I believe that we can have a basic understanding, here we ignore the details of simplifying the process, from the process point of view of the following figure: Launch_app_sim

The picture here is not to repeat, activity starts to resume state, at this time can interact. The above is the analysis of Android application start-up process of the full content, how to have questions welcome to correct the exchange.

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.