Android 9.0 source APP startup process

Keywords: socket Android SDK Java

The relevant source path used in this article: Android 9.0 app startup source code

1. Introduction to startup

1.1. Startup process:

  • Click the desktop App icon, and the Launcher process uses Binder IPC to initiate the startActivity request to the system server process;
  • After receiving the request, the system server process sends the request of creating the process to the Zygote process;
  • The Zygote process fork s out new sub processes, namely App processes;
  • App process, through Binder IPC, sends attachApplication request to sytem ﹣ server process;
  • After receiving the request, the system server process carries out a series of preparatory work, and then sends the creation Activity request to the App process through the binder IPC;
  • After receiving the request, the application thread of the App process sends a message to the main thread through the handler to execute the creation transaction;
  • After receiving the Message, the main thread creates the target Activity through the reflection mechanism and calls back the Activity.onCreate() and other methods;
  • At this point, the App will officially start, enter the Activity life cycle, and execute the onCreate/onStart/onResume method. After the UI rendering, you can see the main interface of the App;

1.2 Activity startup flow chart

1.3 process interaction mode involved

  • The system server process of Launcher process and AMS is in AIDL mode;
  • The system server process where AMS is located communicates with the Zygote process in Socket;
  • The Zygote process and the new APP process are in Binder IPC mode;

2. Activity start source

2.1 Launcher process stage

The desktop in Android also belongs to an APP, that is, LauncherApp. The desktop icon is displayed by the control of BubbleTextView, and there is a click event set in launchers. The specific click event is the INSTANCE object of ItemClickHandler class;

public View createShortcut(ViewGroup parent, ShortcutInfo info) {
  BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.app_icon, parent, false);
  favorite.applyFromShortcutInfo(info);
  // Desktop icon setting click event
  favorite.setOnClickListener(ItemClickHandler.INSTANCE);
  favorite.setOnFocusChangeListener(mFocusHandler);
  return favorite;
}

2.1.1 click Desktop Icon

Click the desktop icon to parse the icon information. The desktop icon belongs to AppInfo type, so call startAppShortcutOrInfoActivity() method;

public static final OnClickListener INSTANCE = ItemClickHandler::onClick;

private static void onClick(View v) {
  // Slightly...
	Launcher launcher = Launcher.getLauncher(v.getContext());
  // Slightly...
	Object tag = v.getTag();
  if (tag instanceof ShortcutInfo) {
    onClickAppShortcut(v, (ShortcutInfo) tag, launcher);
  } else if (tag instanceof FolderInfo) {
    // Slightly...
  } else if (tag instanceof AppInfo) {
    // Desktop icon type is App, enter this branch
    startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
  } else if (tag instanceof LauncherAppWidgetInfo) {
    // Slightly...
  }
}

In the startAppShortcutOrInfoActivity() method, create a new Intent object, set the package name to null, and call the startactivitysafety() method of the Launcher class;

private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
  Intent intent;
  // ...
  if (item instanceof ShortcutInfo) {
    ShortcutInfo si = (ShortcutInfo) item;
    if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI) && intent.getAction() == Intent.ACTION_VIEW) {
      // make a copy of the intent that has the package set to null
      // we do this because the platform sometimes disables instant
      // apps temporarily (triggered by the user) and fallbacks to the
      // web ui. This only works though if the package isn't set
      intent = new Intent(intent);
      intent.setPackage(null);
    }
  }
  launcher.startActivitySafely(v, intent, item);
}

In the startactivitysafety() method of the Launcher class, the startactivitysafety() of its parent class BaseDraggingActivity will be called to make a series of judgments in this method, and finally the startActivity() method will be called;

public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
	// Slightly...
  UserHandle user = item == null ? null : item.user;
  // Set the identification bit to open a new stack
	// Prepare intent
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  // Slightly...
  try {
    boolean isShortcut = 
      Utilities.ATLEAST_MARSHMALLOW  // Is SDK version greater than M
      && (item instanceof ShortcutInfo)  // item type, AppInfo here, so false
      && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) && !((ShortcutInfo) item).isPromise();
    if (isShortcut) {
      // Shortcuts need some special checks due to legacy reasons.
      startShortcutIntentSafely(intent, optsBundle, item);
    } else if (user == null || user.equals(Process.myUserHandle())) {
      // System process
      // Could be launching some bookkeeping activity
      startActivity(intent, optsBundle);
    } else {
      // ...
}

BaseDraggingActivity class inherits from BaseActivity(), BaseActivity also inherits from Activity class. startActivity() method is not implemented in BaseDraggingActivity and BaseActivity, so the startActivity() method of parent Activity class is called finally, and then startActivityForResult() method is called continuously;

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);
  }
}

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);
    // ...
  } else {
    // ...
  }
}

Execute execStartActivity() method of Instrumentation class in startActivityForResult() method;

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 = ActivityManager.getService().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);
  }
  return null;
}

2.1.2 Launcher process gets the agent of AMS

startActivity() is called through ActivityManager.getService();

public static IActivityManager getService() {
  return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() {
  @Override
  protected IActivityManager create() {
    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
    final IActivityManager am = IActivityManager.Stub.asInterface(b);
    return am;
  }
};

As we can see above, the IPC mode of Launcher process and AMS system server process is AIDL communication, that is, Binder IPC mode;

Compared with the ActivityManagerNative in the old version, it has been noted that this class is obsolete;

/**
 * {@hide}
 * @deprecated will be removed soon. See individual methods for alternatives.
 */
@Deprecated
public abstract class ActivityManagerNative {
  /**
  	* Cast a Binder object into an activity manager interface, generating
  	* a proxy if needed.
  	*
  	* @deprecated use IActivityManager.Stub.asInterface instead.
  	*/
  static public IActivityManager asInterface(IBinder obj) {
    return IActivityManager.Stub.asInterface(obj);
  }
  //...
}

2.1.3 initiate creation request to AMS process

After getting the agent of AMS in the Launcher process, the Launcher process calls the interface method through the agent object. According to the aidl communication, it will call the specific implementation class of AMS, and enter the system server process;

ActivityManager.getService().startActivity

2.2. System server process stage

AMS is the manager of all activities, which is located in the Android system server process;

2.2.1 AMS sends a creation process request to Zygote

ActivityManagerService also implements IActivityManager.Stub interface, executes its startActivity() method, and calls many overloaded functions;

public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
  @Override
  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());
  }

	@Override
  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) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId, true /*validateIncomingUser*/);
  }

	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, boolean validateIncomingUser) {
    enforceNotIsolatedCaller("startActivity");
    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser, Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    // TODO: Switch to user app stacks here.
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
      .setCaller(caller)
      .setCallingPackage(callingPackage)
      .setResolvedType(resolvedType)
      .setResultTo(resultTo)
      .setResultWho(resultWho)
      .setRequestCode(requestCode)
      .setStartFlags(startFlags)
      .setProfilerInfo(profilerInfo)
      .setActivityOptions(bOptions)
      .setMayWait(userId)
      .execute();
  }
  // ...
}

Finally, execute mcativitystartcontroller. obtainStarter(). Execute(), and mcativitystartcontroller is an ActivityStartController class object, and view its obtainStarter() method;

/**
	* @return A starter to configure and execute starting an activity. It is valid until after
	*         {@link ActivityStarter#execute} is invoked. At that point, the starter should be
	*         considered invalid and no longer modified or used.
	*/
ActivityStarter obtainStarter(Intent intent, String reason) {
  return mFactory.obtain().setIntent(intent).setReason(reason);
}

Return an ActivityStarter object and set the Intent object to reason, which is the "startActivityAsUser" parameter passed by the caller;

Check the corresponding methods in the ActivityStarter class, and pay attention to the setMayWait() method here;

ActivityStarter setMayWait(int userId) {
  mRequest.mayWait = true;
  mRequest.userId = userId;
  return this;
}

In this method, set the mayWait property of mRequest to true, set userId, continue executing the execute() method, judge whether mRequest.mayWait is true, and enter the corresponding branch;

/**
	* Starts an activity based on the request parameters provided earlier.
	* @return The starter result.
	*/
int execute() {
  try {
    // TODO(b/64750076): Look into passing request directly to these methods to allow
    // for transactional diffs and preprocessing.
    if (mRequest.mayWait) {
      return startActivityMayWait(mRequest.caller, mRequest.callingUid,  
                                  mRequest.callingPackage, mRequest.intent,  
                                  mRequest.resolvedType, mRequest.voiceSession,  
                                  mRequest.voiceInteractor, mRequest.resultTo,  
                                  mRequest.resultWho, mRequest.requestCode, 
                                  mRequest.startFlags, mRequest.profilerInfo,  
                                  mRequest.waitResult, mRequest.globalConfig, 
                                  mRequest.activityOptions, mRequest.ignoreTargetSecurity, 
                                  mRequest.userId, mRequest.inTask, mRequest.reason,  
                                  mRequest.allowPendingRemoteAnimationRegistryLookup, 
                                  mRequest.originatingPendingIntent);
    } else {
      // ...
    } finally {
      onExecutionComplete();
    }
  }

Continue to call the startActivityMayWait() method of this class;

private int startActivityMayWait(IApplicationThread caller, int callingUid, 
                                 String callingPackage, Intent intent, String resolvedType, 
                                 IVoiceInteractionSession voiceSession, 
                                 IVoiceInteractor voiceInteractor, IBinder resultTo, 
                                 String resultWho, int requestCode, int startFlags, 
                                 ProfilerInfo profilerInfo, WaitResult outResult, 
                                 Configuration globalConfig, SafeActivityOptions options, 
                                 boolean ignoreTargetSecurity, int userId, TaskRecord inTask, 
                                 String reason, 
                                 boolean allowPendingRemoteAnimationRegistryLookup, 
                                 PendingIntentRecord originatingPendingIntent) {
  // ...
  // Save a copy in case ephemeral needs it
  final Intent ephemeralIntent = new Intent(intent);
  // Don't modify the client's object!
  intent = new Intent(intent);
  // ...
  // Parsing Intent
  ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0 /* matchFlags */,  computeResolveFilterUid(callingUid, realCallingUid, mRequest.filterCallingUid));
  // ...
  // Collect information about the target of the Intent.
  ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
  // ...
  	// Data used to record Activity
  	final ActivityRecord[] outRecord = new ActivityRecord[1];
  	int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, 
                            voiceSession, voiceInteractor, resultTo, resultWho, requestCode, 
                            callingPid, callingUid, callingPackage, realCallingPid, 
                            realCallingUid, startFlags, options, ignoreTargetSecurity, 
                            componentSpecified, outRecord, inTask, reason, 
                            allowPendingRemoteAnimationRegistryLookup, 
                            originatingPendingIntent);
}

Here, continue to call the startActivity() method of this class;

private int startActivity(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, SafeActivityOptions options, 
                          boolean ignoreTargetSecurity, boolean componentSpecified, 
                          ActivityRecord[] outActivity, TaskRecord inTask, String reason, 
                          boolean allowPendingRemoteAnimationRegistryLookup, 
                          PendingIntentRecord originatingPendingIntent) {
  // ...
  mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType, 	
                                           aInfo, rInfo, voiceSession, voiceInteractor, 
                                           resultTo, resultWho, requestCode, callingPid, 
                                           callingUid, callingPackage, realCallingPid, 
                                           realCallingUid, startFlags, options, 
                                           ignoreTargetSecurity, componentSpecified, 
                                           mLastStartActivityRecord, inTask, 
                                           allowPendingRemoteAnimationRegistryLookup, 
                                           originatingPendingIntent);
	// ...
  return getExternalResult(mLastStartActivityResult);
}

Continue to call startActivity() overload function multiple times;

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord, 
                          IVoiceInteractionSession voiceSession, 
                          IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, 
                          ActivityOptions options, TaskRecord inTask, 
                          ActivityRecord[] outActivity) {
  int result = START_CANCELED;
  try {
    mService.mWindowManager.deferSurfaceLayout();
    result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, outActivity);
  } finally {
    // ...
  }
  return result;
}

In this method, the startActivityUnchecked() method is called to calculate the starting Flags, for example, whether there is NEW_TASK and set it to intent to calculate whether the Activity is inserted into the current existing task stack to determine whether the top Activity of the stack is the same and whether it needs to be reused.

private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                                   IVoiceInteractionSession voiceSession, 
                                   IVoiceInteractor voiceInteractor, int startFlags, 
                                   boolean doResume, ActivityOptions options, 
                                   TaskRecord inTask, ActivityRecord[] outActivity) {
  ...
  // Calculate Activity started Flags
  computeLaunchingTaskFlags();
  mIntent.setFlags(mLaunchFlags);
  // Calculate whether the Activity should be inserted into the existing task stack
  ActivityRecord reusedActivity = getReusableIntentActivity();
  ...
  mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition, mOptions);
  if (mDoResume) {
    ...
    mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions);
    ...
  }
  ...
}

Execute resumeFocusedStackTopActivityLocked() method of ActivitStackSupervisor;

boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
  ...
  final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
  if (r == null || !r.isState(RESUMED)) {
    mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
  } else if (r.isState(RESUMED)) {
    // Kick off any lingering app transitions form the MoveTaskToFront operation.
    mFocusedStack.executeAppTransition(targetOptions);
  }
  return false;
}

Continue to execute resumeTopActivityUncheckedLocked() method of ActivityStack;

@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
	...
  try {
    // Protect against recursion.
    mStackSupervisor.inResumeTopActivity = true;
    result = resumeTopActivityInnerLocked(prev, options); 
    ...
  } finally {
    mStackSupervisor.inResumeTopActivity = false;
  }
  return result;
}

2.2.2 encapsulate and pause Activity transactions

Continue to execute the resumeTopActivityInnerLocked() method of this class. In this method, the client transaction transaction transaction is used to process the suspension of the current Activity, i.e. LauncherApp, and then start a new APP;

@GuardedBy("mService")
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
	...
  if (next.app != null && next.app.thread != null) {
  	...
    synchronized(mWindowManager.getWindowManagerLock()) {
    	try {
        final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread, next.appToken); 
        ...
        if (next.newIntents != null) {
          transaction.addCallback(NewIntentItem.obtain(next.newIntents, false /* andPause */));
        }
        ...
        transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(next.app.repProcState, mService.isNextTransitionForward()));
        ...
        transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(next.app.repProcState, mService.isNextTransitionForward()));
        mService.getLifecycleManager().scheduleTransaction(transaction);
        ...
      }
    }
    ...
    // Execute start new Activity
    mStackSupervisor.startSpecificActivityLocked(next, true, true);
  }
	...
  return true;
}

2.2.3. Suspend the current Activity

First, stop the current Activity, enter the onPause state, and start a new Activity by executing the startSpecificActivityLocked() method;

Here, the clientlecyclemanager object is obtained through AMS, and its scheduleTransaction() method is executed to pause the current Activity;

public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
  
	private final ClientLifecycleManager mLifecycleManager;
  
	ClientLifecycleManager getLifecycleManager() {
		return mLifecycleManager;
	}
}

Execute the scheduleTransaction() method of the clientlifcyclemanager class, in which the schedule() method of the clientransaction object is executed;

class ClientLifecycleManager {
	void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if (!(client instanceof Binder)) {
      // the transaction is executed on client in ActivityThread.
      transaction.recycle();
    }
  } 
}

In the schedule() method of ClientTransaction class, use the iaapplicationthread object to execute scheduleTransaction(), which is the ApplicationThread object of the current App, that is, LauncherApp;

public class ClientTransaction implements Parcelable, ObjectPoolItem {
  public void schedule() throws RemoteException {
		mClient.scheduleTransaction(this);
  }
}

mClient object is iaapplicationtread object, iaapplicationthread is aidl file, corresponding to the internal class ApplicationThread object of ActivityThread class;

public final class ActivityThread extends ClientTransactionHandler {
	private class ApplicationThread extends IApplicationThread.Stub {
    @Override
    public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
      ActivityThread.this.scheduleTransaction(transaction);
    }
	}
}

2.2.4 send a message to the main process to suspend the Activity

ActivityThread inherits from ClientTransactionHandler class, so the scheduleTransaction() method of this class is executed;

public abstract class ClientTransactionHandler {
  void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
  }
}

sendMessage() of this class is an abstract method, which is implemented by a concrete implementation class, namely ActivityThread. what of the message is ActivityThread. H.execute_;

void sendMessage(int what, Object obj) {
  sendMessage(what, obj, 0, 0, false);
}

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
  Message msg = Message.obtain();
  msg.what = what;
  msg.obj = obj;
  msg.arg1 = arg1;
  msg.arg2 = arg2;
  if (async) {
    msg.setAsynchronous(true);
  }
  mH.sendMessage(msg);
}

mH is the H class of ActivityThread, which inherits from Handler. After receiving the message, execute() method of TransactionExecutor object in the main thread. The executed logic is encapsulated in ClientTransaction transaction transaction;

class H extends Handler {
	public void handleMessage(Message msg) {
    switch (msg.what) {
    	case EXECUTE_TRANSACTION:
        final ClientTransaction transaction = (ClientTransaction) msg.obj;
        mTransactionExecutor.execute(transaction);
        if (isSystem()) {
          // Client transactions inside system process are recycled on the client side
          // instead of ClientLifecycleManager to avoid being cleared before this
          // message is handled.
          transaction.recycle();
        }
        // TODO(lifecycler): Recycle locally scheduled transactions.
        break;
    }
  }
}

In the execute() method of TransactionExecutor, execute the callback object and LifecycleState object encapsulated in the ClientTransaction transaction;

public class TransactionExecutor {
  public void execute(ClientTransaction transaction) {
    final IBinder token = transaction.getActivityToken();
    ...
    executeCallbacks(transaction);
    executeLifecycleState(transaction);
    mPendingActions.clear();
    log("End resolving transaction");
  }
}

The transaction object is encapsulated in the resumeTopActivityInnerLocked() method of the ActivityStack class in 2.2.2. Here, the callback object is empty, and the executelifcyclestate() method is executed directly. The transaction object is added in the resumeTopActivityInnerLocked() method of the ActivityStack class;

Take out the ActivityLifecycleItem object added in the transaction object, where the ActivityLifecycleItem object is actually the NewIntentItem object;

private void executeLifecycleState(ClientTransaction transaction) {
  final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
  ...
  final IBinder token = transaction.getActivityToken();
  final ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
  ...
  // Cycle to the state right before the final requested state.
  cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);
  // Execute the final transition with proper parameters.
  lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
  lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}

Continue to execute the execute() method of the NewIntentItem class;

public class NewIntentItem extends ClientTransactionItem {
	@Override
  public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
    client.handleNewIntent(token, mIntents, mPause);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
  } 
}

2.2.5 main thread pauses Activity

Among them, the client object is the ClientTransactionHandler object, and the ActivityThread inherits from the ClientTransactionHandler class. In the ActivityThread class, the construction method of ClientTransactionHandler is passed in to the ActivityThread itself for construction;

@Override
public void handleNewIntent(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
  performNewIntents(token, intents, andPause);
}

void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) {
  final ActivityClientRecord r = mActivities.get(token);
  ...
  final boolean resumed = !r.paused;
  if (resumed) {
    r.activity.mTemporaryPause = true;
    mInstrumentation.callActivityOnPause(r.activity);
  }
  checkAndBlockForNetworkAccess();
  deliverNewIntents(r, intents);
  if (resumed) {
    r.activity.performResume(false, "performNewIntents");
    r.activity.mTemporaryPause = false;
  }
  // andPause == false, defined when passing in NewIntentItem
  if (r.paused && andPause) {
    // In this case the activity was in the paused state when we delivered the intent,
    // to guarantee onResume gets called after onNewIntent we temporarily resume the
    // activity and pause again as the caller wanted.
    performResumeActivity(token, false, "performNewIntents");
    performPauseActivityIfNeeded(r, "performNewIntents");
  }
}

Execute the callActivityOnPause() method of the Instrumentation class,

public void callActivityOnPause(Activity activity) {
  activity.performPause();
}

Continue calling performPause() method of Activity

final void performPause() {
  mDoReportFullyDrawn = false;
  mFragments.dispatchPause();
  mCalled = false;
  onPause();
  ...
}

Continue to execute the onPause() method and pause. Here we enter the onPause() life cycle method of a specific Activity. Before the onPause() method returns, the new Activity will not be created, so don't do time-consuming operations in the onPause() method. You can save the state here, close the animation, time-consuming operations, etc;

2.2.6 start a new Activity

Then continue to start the new Activity process in the resumeTopActivityInnerLocked() method of the ActivityStack class, and use AMS to execute the resumeTopActivityInnerLocked() method of the ActivityStack to start the new process;

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
	...
  mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true);
}

AMS calls the overloaded method twice;

@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
                                       boolean knownToBeDead, int intentFlags, 
                                       String hostingType, ComponentName hostingName,
                                       boolean allowWhileBooting, boolean isolated, 
                                       int isolatedUid, boolean keepIfLarge,
                                       String abiOverride, String entryPoint, 
                                       String[] entryPointArgs, Runnable crashHandler) {
  ...
  final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
  ...
  return success ? app : null;
}

Continue to call the startProcessLocked overload method;

@GuardedBy("this")
private final boolean startProcessLocked(ProcessRecord app, String hostingType,
                                         String hostingNameStr, boolean disableHiddenApiChecks, 
                                         String abiOverride) {
  ...
  // This parameter is important, which will be used later. Pass in the ActivityThread class name
  final String entryPoint = "android.app.ActivityThread";
  return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids, 
                            runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, 
                            invokeWith, startTime);
  ...
}
@GuardedBy("this")
private boolean startProcessLocked(String hostingType, String hostingNameStr, 
                                   String entryPoint, ProcessRecord app, int uid, int[] gids, 
                                   int runtimeFlags, int mountExternal, String seInfo, 
                                   String requiredAbi, String instructionSet, 
                                   String invokeWith, long startTime) {
  ...
  if (mConstants.FLAG_PROCESS_START_ASYNC) {
    ...
    final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint, app, 
                                                        app.startUid, gids, runtimeFlags, 
                                                        mountExternal, app.seInfo, requiredAbi, 
                                                        instructionSet, invokeWith, 
                                                        app.startTime);
    ...
  }
}

Execute the startProcess() method in this method;

private ProcessStartResult startProcess(String hostingType, String entryPoint, 
                                        ProcessRecord app, int uid, int[] gids, 
                                        int runtimeFlags, int mountExternal, String seInfo, 
                                        String requiredAbi, String instructionSet, 
                                        String invokeWith, long startTime) {
  try {
  	...
  	if (hostingType.equals("webview_service")) {
    	...
  	} else {
    	startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags,
                                  mountExternal, app.info.targetSdkVersion, seInfo, 
                                  requiredAbi, instructionSet, app.info.dataDir, invokeWith,
                                  new String[] {PROC_START_SEQ_IDENT + app.startSeq});
  	}
    ...
  }
}

2.2.7. Establish Socket communication with Zygote process

Execute the start() method of the Process class, and call the start() method of the ZygoteProcess class. The ZygoteProcess class object is a static object of the Process class, in which the parameter is passed into the zygote'socket, that is, the address of the connection when the socket communicates;

public static final String ZYGOTE_SOCKET = "zygote";
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
public static final ZygoteProcess zygoteProcess = new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);

public static final ProcessStartResult start(final String processClass, final String niceName, 
                                             int uid, int gid, int[] gids, int runtimeFlags, 
                                             int mountExternal, int targetSdkVersion, 
                                             String seInfo, String abi, String instructionSet, 
                                             String appDataDir, String invokeWith, 
                                             String[] zygoteArgs) {
  return zygoteProcess.start(processClass, niceName, uid, gid, gids, runtimeFlags, 
                             mountExternal, targetSdkVersion, seInfo, abi, instructionSet, 
                             appDataDir, invokeWith, zygoteArgs);
}

In the start() method of the ZygoteProcess class, the startViaZygote() method is executed. Here, the penultimate parameter is fixedly passed in false, which means that a new process is started instead of the Zygote process;

public final Process.ProcessStartResult start(final String processClass, final String niceName, 
                                              int uid, int gid, int[] gids, int runtimeFlags, 
                                              int mountExternal, int targetSdkVersion, 
                                              String seInfo, String abi, String instructionSet, 
                                              String appDataDir, String invokeWith, 
                                              String[] zygoteArgs) {
  try {
    return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, 
                          targetSdkVersion, seInfo, abi, instructionSet, appDataDir, 
                          invokeWith, false /* startChildZygote */, zygoteArgs);
  } catch (ZygoteStartFailedEx ex) {
    ...
  }
}

In the startViaZygote() method, it is mainly new that sets out a String type List set, which is used to save the relevant parameters of the startup process, such as process name, uid and so on, and then call zygoteSendArgsAndGetResult() method.

private Process.ProcessStartResult startViaZygote(final String processClass, 
                                                  final String niceName, final int uid, 
                                                  final int gid, final int[] gids, 
                                                  int runtimeFlags, int mountExternal, 
                                                  int targetSdkVersion, String seInfo, 
                                                  String abi, String instructionSet, 
                                                  String appDataDir, String invokeWith, 
                                                  boolean startChildZygote, String[] extraArgs) throws ZygoteStartFailedEx {
  ArrayList<String> argsForZygote = new ArrayList<String>();
  ...
  if (niceName != null) {
    argsForZygote.add("--nice-name=" + niceName);
  }
  ...
  argsForZygote.add(processClass);
  synchronized(mLock) {
    return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
  }
}

In the zygoteSendArgsAndGetResult() method, a parameter will be passed in. The first parameter is a ZygoteState object, which is obtained through the openZygoteSocketIfNeeded() method. It can be seen from the comments that this method is used to open the socket to the Zygote process. It also shows that the IPC mode between the system server process and the Zygote process is socket communication;

Method to determine whether the socket has been opened, there are 32-bit and 64 bit zygote processes, and through the abi parameter to match 32-bit or 64 bit. When connecting, the parameter mSocket is the connection address, which is initialized in the static object ZygoteProcess in the Process, namely zygote Process;

When the Zygote process starts, ro.zygote in Init.rc script has four supported attributes, which are determined by the hardware. Here, the main mode and the second mode, namely 64 bit and 32-bit, will be obtained to match whether they are supported or not;

/**
	* Tries to open socket to Zygote process if not already open. If
	* already open, does nothing.  May block and retry.  Requires that mLock be held.
	*/
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
  Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
  if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
    ... 
    try {
      primaryZygoteState = ZygoteState.connect(mSocket);
    }
  }
  if (primaryZygoteState.matches(abi)) {
    return primaryZygoteState;
  }
  // The primary zygote didn't match. Try the secondary.
  if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
    ...
    try {
      secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
    }
  }
  if (secondaryZygoteState.matches(abi)) {
    return secondaryZygoteState;
  }
  throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

At this time, communication has been established with the Zygote process through socket;

2.2.8 initiate a process creation request to the Zygote process

In the zygoteSendArgsAndGetResult() method, pass the relevant parameters to the Zygote process through socket,

Then a new ProcessStartResult object is created, and the result of Zygote execution is stored in the object through flow, pid, etc;

@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx {
  try {
    ...
    final BufferedWriter writer = zygoteState.writer;
    final DataInputStream inputStream = zygoteState.inputStream;
    writer.write(Integer.toString(args.size()));
    writer.newLine();
    for (int i = 0; i < sz; i++) {
      String arg = args.get(i);
      writer.write(arg);
      writer.newLine();
    }
    writer.flush();
    // Should there be a timeout on this?
    Process.ProcessStartResult result = new Process.ProcessStartResult();
    result.pid = inputStream.readInt();
    result.usingWrapper = inputStream.readBoolean();
    ...
    return result;
  } catch (IOException ex) {
    zygoteState.close();
    throw new ZygoteStartFailedEx(ex);
  }
}

2.3. Zygote process stage

When the Zygote process is started, the Server end of the Socket will be established, and it will enter polling waiting for the client access. At this time, AMS as the client of the Socket will establish a connection with the Zygote process and send a request, and the Zygote process will receive a new process request from the client to execute;

Execute the fork process request, see“ Zygote process start";

At this time, enter the Zygote process to create a new APP process;

2.3.1. Zygote process fork new sub process

At this point, we go into the Zygote process to execute the fork new process operation. The Zygote process receives the fork sub process request of AMS, and executes the processOneCommand() method of the ZygoteConnection class, wherein the forkAndSpecialize() method executing Zygote class proceeds out of the sub process fork, and then calls the handleChildProc() method, where the method in the () method is called. E () to execute;

First, look at the forkAndSpecialize() method;

The implementation of the native method is implemented in the com ﹣ Android ﹣ internal ﹣ OS ﹣ zygote.cpp class. The implementation methods are as follows:

static jint com_android_internal_os_Zygote_nativeForkSystemServer( JNIEnv* env, jclass, 
                                                                  uid_t uid, gid_t gid, 
                                                                  jintArray gids, 
                                                                  jint runtime_flags,
                                                                  jobjectArray rlimits, 
                                                                  jlong permittedCapabilities,
                                                                  jlong effectiveCapabilities) {
  pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, 
                                      permittedCapabilities, effectiveCapabilities, 
                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL, NULL, 
                                      false, NULL, NULL);
  

Continue to execute the ForkAndSpecializeCommon() method of this class, execute the fork() method, and fork will generate a new process, i.e. APP process, and return pid. When pid is equal to 0, it represents the sub process. At this time, execute PreApplicationInit() method in APP process, and call the CallStaticVoidMethod() method of Zygote class through JNI;

// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, 
                                     jint runtime_flags, jobjectArray javaRlimits, 
                                     jlong permittedCapabilities, jlong effectiveCapabilities, 
                                     jint mount_external, jstring java_se_info, 
                                     jstring java_se_name, bool is_system_server, 
                                     jintArray fdsToClose, jintArray fdsToIgnore, 
                                     bool is_child_zygote, jstring instructionSet, 
                                     jstring dataDir) {
  ...
  pid_t pid = fork();
  if (pid == 0) {
    // Sub process, i.e. app process out of fork
    PreApplicationInit();
    ...
    // Reflection calls the callPostForkChildHooks() method of the Zygote class
    env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, 
                              is_system_server, is_child_zygote, instructionSet);
  } else {
    // Parent process
  }
}

Enter the subprocess branch. In the PreApplicationInit() method, the subprocess setting indicates that it is not a zygote process;

static void PreApplicationInit() {
  // The child process sets this to indicate it's not the zygote.
  gMallocLeakZygoteChild = 1;
  // Set the jemalloc decay time to 1.
  mallopt(M_DECAY_TIME, 1);
}

Continue to call the CallStaticVoidMethod() method of Zygote class through JNI to do some initialization operations;

2.3.2 initiate Application creation to APP process

Next, go on to the operation after fork completes the subprocess, that is, the handleChildProc() method of the ZygoteConnection class;

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, boolean isZygote) {
  ...
  if (!isZygote) {
    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */);
  } else {
    ...
  }
}

Continue with the childZygoteInit() method of ZygoteInit, and finally call the applicationInit() method of the RuntimeInit class to create Application of the APP process.

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
  ...
  RuntimeInit.commonInit();
  ZygoteInit.nativeZygoteInit();
  return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

Execute the applicationInit() method of RuntimeInit, parse the parameters, and call the findStaticMain() method;

protected static Runnable applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
  ...
  final Arguments args = new Arguments(argv);
  ...
  return findStaticMain(args.startClass, args.startArgs, classLoader);
}

In findStaticMain() method, reflection finds the corresponding class and method, and unifies the parameters and other information to methodandargscaler class object for processing. The class name is the ActivityThread class name passed in when AMS interacts with Zygote process in the startProcessLocked method in the previous 2.2.6, and the corresponding method is main() method. Methodandargscaler class is a Runnable object, whose R In the un() method, the method found by reflection is executed, that is, the main() method of ActivityThread, which enters the ActivityThread class, that is, the main thread of the new process APP;

protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {
  Class<?> cl;
  try {
    cl = Class.forName(className, true, classLoader);
  }
  ...
  Method m;
  try {
    m = cl.getMethod("main", new Class[] { String[].class });
  }
  ...
  int modifiers = m.getModifiers();
  return new MethodAndArgsCaller(m, argv);
}

2.4 APP process stage

After the Zygote process fork s out the APP process, it enters the APP process, i.e. ActivityThread, executes its main() method, creates the Looper of the main thread, and polls for waiting messages. The Looper here is created by the system, so it is not necessary to manually create the Looper when using the Handler in the main thread at ordinary times;

public static void main(String[] args) {
  ...
  // Initialize environment for current user
 	Environment.initForCurrentUser();
  ...
  Process.setArgV0("<pre-initialized>");
  // Initialize main thread, UI thread
  Looper.prepareMainLooper();
  ...
  // Create the ActivityThread object and call its attach() method. The second parameter is false, indicating the non system process
  ActivityThread thread = new ActivityThread();
  thread.attach(false, startSeq);
  if (sMainThreadHandler == null) {
    sMainThreadHandler = thread.getHandler();
  }
  ...
  // Enter the main thread looper polling
  Looper.loop();
  throw new RuntimeException("Main thread loop unexpectedly exited");
}

2.4.1 send attachApplication request to AMS

In the main() method of ActivityThread, create the ActivityTread object and call its attach() method. The first parameter is passed in false, indicating that the process is not a system process;

In the attach() method, the agent object of AMS in APP process is obtained through ActivityManager.getService(), and the attachApplication request is sent to the system process (i.e. the system server process where AMS is located) through the agent object of AMS;

private void attach(boolean system, long startSeq) {
  sCurrentActivityThread = this;
  mSystemThread = system;
  if (!system) {
    ... // Related settings of dalvik virtual machine
    android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());
    RuntimeInit.setApplicationObject(mAppThread.asBinder());
    // Get Binder object of ActivityManager, that is, AMS agent of system process in APP process
    final IActivityManager mgr = ActivityManager.getService();
    try {
      // Initiate attachApplication request to system process through AMS proxy object
      mgr.attachApplication(mAppThread, startSeq);
    } catch (RemoteException ex) {
      throw ex.rethrowFromSystemServer();
    }
    ... 
  } else {
    ... // System process branch
  }
  ...
}

2.5. System server process stage

At this time, the APP process is suspended, enters the system server process where AMS is located, and executes the attachApplication() method of AMS;

2.5.1 create Application of APP process

Gets the process Pid and Uid that are currently invoked, then resets the IPC identifier on the current process, invokes the attachApplicationLocked() method, and then returns the IPC logo on the process before calling the method.

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
  synchronized (this) {
    int callingPid = Binder.getCallingPid();
    final int callingUid = Binder.getCallingUid();
    final long origId = Binder.clearCallingIdentity();
    attachApplicationLocked(thread, callingPid, callingUid, startSeq);
    Binder.restoreCallingIdentity(origId);
  }
}

Continue to execute attachApplicationLocked() method in AMS. In this method, first create Application and call back its lifecycle method onCreate(), then call attachApplicationLocked() method of StackSupervisor class to start a new Activity. First, create Application;

@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread, int pid, int callingUid, long startSeq) {
  try {
    if (app.isolatedEntryPoint != null) {
      // This is an isolated process which should just call an entry point instead of
      // being bound to an application.
      thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
    } else if (app.instr != null) {
      thread.bindApplication(processName, appInfo, providers, app.instr.mClass, 
                             profilerInfo, app.instr.mArguments, app.instr.mWatcher, 
                             app.instr.mUiAutomationConnection, testMode, 
                             mBinderTransactionTrackingEnabled, enableTrackAllocation, 
                             isRestrictedBackupMode || !normalMode, app.persistent, 
                             new Configuration(getGlobalConfiguration()), app.compat, 
                             getCommonServicesLocked(app.isolated), 
                             mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, 
                             isAutofillCompatEnabled); 
    } else {
      thread.bindApplication(processName, appInfo, providers, null, profilerInfo, null, null, 
                             null, testMode, mBinderTransactionTrackingEnabled, 
                             enableTrackAllocation, isRestrictedBackupMode || !normalMode, 
                             app.persistent, new Configuration(getGlobalConfiguration()), 
                             app.compat, getCommonServicesLocked(app.isolated), 
                             mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, 
                             isAutofillCompatEnabled);
    }
	} catch (Exception e) {
    ...
  }
  // See if the top visible activity is waiting to run in this process...
  if (normalMode) {
    try {
      if (mStackSupervisor.attachApplicationLocked(app)) {
        didSomething = true;
      }
    } catch (Exception e) {
      ...
    }
  }
}

2.5.2 send message to main thread

Continue to execute bindApplication() method of ActivityThread, save AppBindData information, and send message to main thread. Because AMS creation Application operation is executed in Binder pool, send message to main thread of AMS through Handler message mechanism;

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 services, 
                                  Bundle coreSettings, String buildSerial, 
                                  boolean autofillCompatibilityEnabled) {
  ...
  AppBindData data = new AppBindData();
  data.processName = processName;
  data.appInfo = appInfo;
  ...
  sendMessage(H.BIND_APPLICATION, data);
}

The main thread receives the message. The Handler in the main thread, class H, processes the message and executes the handleBindApplication() method;

class H extends Handler {
  public void handleMessage(Message msg) {
    case BIND_APPLICATION:
    	...
    	AppBindData data = (AppBindData)msg.obj;
    	handleBindApplication(data);
    	...
    	break;
  }
  ...
}

2.5.3 life cycle method of Application execution

Execute the handleBindApplication() method, in which the onCreate() method of Application is executed through the instrumentation class;

private void handleBindApplication(AppBindData data) {
  // Register the UI Thread as a sensitive thread to the runtime.
  VMRuntime.registerSensitiveThread();
  ...
  VMRuntime.setProcessPackageName(data.appInfo.packageName);
  ...
  final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
  updateLocaleListFromAppContext(appContext, mResourcesManager.getConfiguration().getLocales());
  ...
  Application app;
  try {
    app = data.info.makeApplication(data.restrictedBackupMode, null);
    ...
    try {
      // The onCreate() method is an empty implementation in the instrumentation class
      mInstrumentation.onCreate(data.instrumentationArgs);
    }
    try {
      // Execute onCreate() method of Application
      mInstrumentation.callApplicationOnCreate(app);
    }
    ...
  }
  ...
}

The callApplicationOnCreate() method of the Instrumentation class, in which the onCreate() method of the Application class is called, has now been executed in the onCreate() method of the Application of the new APP;

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

2.5.4 start Activity

After the Application is created, continue to the process of starting Activity after 2.5.1, execute attachApplicationLocked() method in AMS, obtain relevant Task, Stack, package information, etc., and call realStartActivityLocked() method to start Activity;

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
  final String processName = app.processName;
  boolean didSomething = false;
  // Traverse all the stacks and find the ActivityStack in the foreground
 	for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
    final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
    for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
      final ActivityStack stack = display.getChildAt(stackNdx);
      if (!isFocusedStack(stack)) {
        continue;
      }
      // Find the ActivityRecord at the top of the stack
      final ActivityRecord top = stack.topRunningActivityLocked();
      for (int i = 0; i < size; i++) {
        final ActivityRecord activity = mTmpActivityList.get(i);
        if (activity.app == null && app.uid == activity.info.applicationInfo.uid && processName.equals(activity.processName)) {
          try {
            // Call the realstartActivityLocked method to start the target Activity
            if (realStartActivityLocked(activity, app, top == activity /* andResume */, true /* checkConfig */)) {
              didSomething = true;
            }
          }
        }
      }
    }
  }
}

Continue to execute the realStartActivityLocked() method to create the Activity, save the new app process information to the app variable, obtain the corresponding stack information, etc., encapsulate the logic of creating the Activity into the ClientTransaction transaction transaction, add the callback and LifecycleCallback callback, and obtain the LifecycleManager through AMS to execute;

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException {
  try {
  	// Save the information of the new process to the app variable of ActivityRecord
    r.setProcess(app);
    // Get the corresponding stack information, etc
    ...
    try {
      final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread, r.appToken);
      clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), 
      	System.identityHashCode(r), r.info, 
        // TODO: Have this take the merged configuration instead of separate global
        // and override configs. 
        mergedConfiguration.getGlobalConfiguration(),
        mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, 
        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, 
        newIntents, mService.isNextTransitionForward(), profilerInfo));
      // Set desired final state.
      final ActivityLifecycleItem lifecycleItem;
      if (andResume) {
        lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
      }
      clientTransaction.setLifecycleStateRequest(lifecycleItem);
      // Schedule transaction.
      mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    }
  }
}

2.5.5 notify APP process to create Activity

Here, the ClientTransaction transaction is used to execute. getLifecycleManager() of AMS gets the ClientLifecycleManager object and executes its scheduleTransaction() method;

public class ActivityManagerService {
  ClientLifecycleManager getLifecycleManager() {
    return mLifecycleManager;
  }
}

The scheduleTransaction() method of clientlecyclemanager;

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
  final IApplicationThread client = transaction.getClient();
  transaction.schedule();
  ...
}

The schedule() method of ClientTransaction class, where mClient object is the ApplicationThread object passed in, that is to say, it enters the APP process to execute through Binder mechanism;

public void schedule() throws RemoteException {
  mClient.scheduleTransaction(this);
}

2.6 APP process stage

Enter the application thread of APP process to execute;

private class ApplicationThread extends IApplicationThread.Stub {
  @Override
  public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
  }
}

2.6.1 send a message to the main process to create an Activity

ActivityThread inherits from ClientTransactionHandler class, sends messages to ActivityThread, and executes the execute() method of TransactionExecutor class;

public void execute(ClientTransaction transaction) {
  final IBinder token = transaction.getActivityToken();
  executeCallbacks(transaction);
  executeLifecycleState(transaction);
}

Where Callback is the LaunchActivityItem object, execute its execute() method in the executeCallbacks() method;

public class LaunchActivityItem extends ClientTransactionItem {
  @Override
  public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, 
                                                      mOverrideConfig, mCompatInfo, mReferrer, 
                                                      mVoiceInteractor, mState, 
                                                      mPersistentState, mPendingResults, 
                                                      mPendingNewIntents, mIsForward, 
                                                      mProfilerInfo, client);
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
  }
}

2.6.2 main thread creates Activity through reflection

Where the client object is the current ActivityThread object, execute its handleLaunchActivity() method;

@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
  ...
  final Activity a = performLaunchActivity(r, customIntent);
  ...
  return a;
}

performLaunchActivity, in this method, obtain packageInfo information, Comment information, etc., then execute the newActivity() method of the Instrumentation class to create an activity, then execute the attach() method of the activity, and then execute the onCreate() method of the activity through the Instrumentation class after the creation;

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  // Get packageInfo information
  ActivityInfo aInfo = r.activityInfo;
  if (r.packageInfo == null) {
    r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE);
  }
  ...
  ContextImpl appContext = createBaseContextForActivity(r);
  Activity activity = null;
  try {
    // Call the Instrumentation class to create an Activity object based on the Activity's information
    java.lang.ClassLoader cl = appContext.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);
    }
  }
  try {
    ...
  	// After creation, call the attach method of Activity to initialize Activity
    if (activity != null) {
      activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, 
                      r.activityInfo, title, r.parent, r.embeddedID, 
                      r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, 
                      window, r.configCallback);
      ...
      // Call onCreate method of Activity
      if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
      } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);
      }
    }
  }
}

After creating an Activity, call its attach() method;

public Activity newActivity(Class<?> clazz, Context context,  IBinder token, 
                            Application application, Intent intent, ActivityInfo info,  
                            CharSequence title, Activity parent, String id, 
                            Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {
  Activity activity = (Activity)clazz.newInstance();
  ActivityThread aThread = null;
  // Activity.attach expects a non-null Application Object.
  if (application == null) {
    application = new Application();
  }
  activity.attach(context, aThread, this, token, 0 /* ident */, application, intent, info, 
                  title, parent, id, 
                  (Activity.NonConfigurationInstances)lastNonConfigurationInstance, 
                  new Configuration(), null /* referrer */, null /* voiceInteractor */, 
                  null /* window */, null /* activityConfigCallback */);
  return activity;
}

2.6.3 implementation of Activity life cycle method

Execute the attach() method of activity, and then execute the onCreate() method of activity through the Instrumentation class;

public void callActivityOnCreate(Activity activity, Bundle icicle) {
  prePerformCreate(activity);
  activity.performCreate(icicle);
  postPerformCreate(activity);
}

Execute the activity's perform() method, in which the activity's onCreate() method is executed, thus entering the activity's onCreate() method to create layout, etc., and then the new APP will be displayed in front of the user, and continue to execute its onResume() and other methods;

final void performCreate(Bundle icicle) {
  performCreate(icicle, null);
}

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
  mCanEnterPictureInPicture = true;
  restoreHasCurrentPermissionRequest(icicle);
  if (persistentState != null) {
    onCreate(icicle, persistentState);
  } else {
    onCreate(icicle);
  }
  writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");
  mActivityTransitionState.readState(icicle);
  mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(com.android.internal.R.styleable.Window_windowNoDisplay, false);
  mFragments.dispatchActivityCreated();
  mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
32 original articles published, 14 praised, 60000 visitors+
Private letter follow

Posted by fnbcprog on Sat, 01 Feb 2020 03:50:50 -0800