Android啟動系列之Activity啟動流程

前言

Activity的啟動有兩種流程,一種是入口Activity的啟動,另外一種就是普通Activity啟動。入口Activity是指應用程序啟動的第一個Activity,它的啟動過程也可以理解為應用程序的啟動過程。普通Activity的流程相對簡單很多,是入口Activity啟動流程中的一部分,所以我們這里只看入口Activity啟動流程。

Launcher請求AMS

前面的文章中知道Launcher啟動后會將已安裝程序的圖標顯示到桌面上,當點擊這個圖標的時候,Launcher就會請求AMS啟動應用。過程如下:

image.png

可以看到依次調用了Activity的startActivity和startActivityForResult函數(shù),這里來看看startActivityForResult的代碼:

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 {
    ...
  }
}

因為入口Activity還沒創(chuàng)建出來,所以mParent是空(如果不為空說明應用已經啟動,則就進入了普通Activity的流程),這樣就執(zhí)行了Instrumentation的execStartActivity方法。

在execStartActivity中會調用ActivityManager的getService方法來獲取AMS的代理對象,然后調用它的startActivity方法,這樣就將啟動請求發(fā)送到AMS中了。

AMS處理請求

在AMS中會對請求進行一系列處理,最終會讓ApplicationThread來處理,這部分時序圖如下:

image.png

AMS的startActivity的代碼如下:

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

直接調用了startActivityAsUser,這里通過 UserHandle.getCallingUserId() 獲取了調用者的UserId,AMS就是根據(jù)這個id來確定調用者的權限,如果權限不夠則不能啟動該應用。

在startActivityAsUser中會依次調用ActivityStarter的startActivityMayWait、startActivityLocked和startActivity。這里重點說一下startActivity方法,它的主要代碼如下:

private int startActivity(...) {
  ...

  ProcessRecord callerApp = null;
  if (caller != null) {
    callerApp = mService.getRecordForAppLocked(caller);
    if (callerApp != null) {
      callingPid = callerApp.pid;
      callingUid = callerApp.info.uid;
    } else {
      Slog.w(TAG, "Unable to find app for caller " + caller
             + " (pid=" + callingPid + ") when starting: "
             + intent.toString());
      err = ActivityManager.START_PERMISSION_DENIED;
    }
  }
  ...
  ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                                        callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                                        resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                                        mSupervisor, container, options, sourceRecord);
  if (outActivity != null) {
    outActivity[0] = r;
  }
  ...
  return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                       options, inTask, outActivity);
}

首先判斷caller是否為null,這個caller就是發(fā)起請求的應用進程(因為我們是從Launcher開始的,所以這里就是Launcher)的ApplicationThread對象。

然后看到調用了AMS的getRecordForAppLocked獲取callerApp對象,它是ProcessRecord類型(ProcessRecord這個類用來描述應用程序進程)。

繼續(xù)往下看,接下來創(chuàng)建了一個ActivityRecord對象,與ProcessRecord類似ActivityRecord用來記錄一個Activity的信息。

最后調用了另外一個startActivity方法,在這個方法中會調用startActivityUnchecked方法,這個方法的代碼如下:

private int startActivityUnchecked(...) {
  ...
  if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
      && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    newTask = true;
    result = setTaskFromReuseOrCreateNewTask(
      taskToAffiliate, preferredLaunchStackId, topStack);
  } else if (mSourceRecord != null) {
    result = setTaskFromSourceRecord();
  } else if (mInTask != null) {
    result = setTaskFromInTask();
  } else {
    setTaskToCurrentTopOrCreateNewTask(); //代碼1
  }
  ...
  if (mDoResume) {
    final ActivityRecord topTaskActivity =
      mStartActivity.getTask().topRunningActivityLocked();
    if (!mTargetStack.isFocusable()
        || (topTaskActivity != null && topTaskActivity.mTaskOverlay
            && mStartActivity != topTaskActivity)) {
      ...
    } else {
      ...
      mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions);  //代碼2
    }
  } else {
    mTargetStack.addRecentActivityLocked(mStartActivity);
  }
  ...
}

這個方法主要處理與棧管理相關邏輯,在代碼1處的setTaskToCurrentTopOrCreateNewTask方法會創(chuàng)建一個新的TaskRecord,用來描述Activity任務棧,也就是說會創(chuàng)建一個新的Activity任務棧。

然后在代碼2處調用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法,代碼如下:

boolean resumeFocusedStackTopActivityLocked(
      ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
  if (targetStack != null && isFocusedStack(targetStack)) {
      return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
  }
  final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
  if (r == null || r.state != RESUMED) {
    mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
  } else if (r.state == RESUMED) {
    mFocusedStack.executeAppTransition(targetOptions);
  }
  return false;
}

這里判斷如果Activity為null或者不是RESUMED狀態(tài)會調用ActivityStack的resumeTopActivityUncheckedLocked方法。在這個方法中會調用resumeTopActivityInnerLocked,然后會調用ActivityStackSupervisor的startSpecificActivityLocked方法,來重點看看這個方法:

void startSpecificActivityLocked(ActivityRecord r,
      boolean andResume, boolean checkConfig) {
  ProcessRecord app = mService.getProcessRecordLocked(r.processName,
          r.info.applicationInfo.uid, true);
  r.getStack().setLaunchTime(r);
  
  if (app != null && app.thread != null) {
    try {
      if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
          || !"android".equals(r.info.packageName)) {
        app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                       mService.mProcessStats);
      }
      realStartActivityLocked(r, app, andResume, checkConfig);
      return;
    } catch (RemoteException e) {
      Slog.w(TAG, "Exception when starting activity "
             + r.intent.getComponent().flattenToShortString(), e);
    }
  }
  mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
          "activity", r.intent.getComponent(), false, false, true);
}

可以看到一開始獲取了即將啟動的Activity所在的應用進程,然后判斷這個應用進程是否存在并且已經運行,如果沒運行則直接跳到方法尾部,可以看到這里會調用startProcessLocked啟動應用進程;如果已經運行則進入if語句,可以看到最終執(zhí)行到realStartActivityLocked方法,這個方法的代碼如下:

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,boolean andResume, boolean checkConfig) throws RemoteException {
  ...
  try {
    ...
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
              System.identityHashCode(r), r.info,
              mergedConfiguration.getGlobalConfiguration(),
              mergedConfiguration.getOverrideConfiguration(), r.compat,
              r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
              r.persistentState, results, newIntents, !andResume,
              mService.isNextTransitionForward(), profilerInfo);
    ...
  } catch (RemoteException e) {
    ...
  }
    ...
  return true;
}

這里app.thread是IApplicationThread,它的實現(xiàn)是ActivityThread的內部類ApplicationThread。這里調用scheduleLaunchActivity就是在目標應用程序的進程中啟動Activity。因為當前在AMS進程中,所以這里就需要通過ApplicationThread來與應用程序進程進行Binder通信,ApplicationThread就可以看作是AMS和應用程序進程的橋梁。

image.png

ActivityThread啟動Activity

通過ApplicationThread我們就進入了應用程序進程中,來看看最后這部分的流程是什么樣子的:

image.png

ApplicationThread將這個啟動的消息傳給ActivityThread,最后會調用它的handleLaunchActivity,代碼如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { 
    ......
    Activity a = performLaunchActivity(r, customIntent);   //1
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);             //2
        
        ...
    } else {
        ......
    }
}

代碼1處調用了performLaunchActivity來啟動Activity,并返回得到一個Activity對象。代碼2處則通過handleResumeActivity將這個Activity的狀態(tài)設置為Resume。

接下來看看performLaunchActivity這個方法,這是啟動環(huán)節(jié)一個很重要的節(jié)點,代碼如下:

  private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  ...
        ActivityInfo aInfo = r.activityInfo;    //1
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,       //2
                    Context.CONTEXT_INCLUDE_CODE);  
        }
        ComponentName component = r.intent.getComponent();  //3
      ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);   //4
           ...
            }
        } catch (Exception e) {
         ...
        }
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);      //5

        ...
            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);              
         ...
                }
                //6
                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);

              ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//7
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                ...
        }
        return activity;
}

代碼1處獲取ActivityInfo,這個info里存儲一些Activity的信息,比如theme和launchMode;代碼3處獲取要啟動Activity的ComponentName,這里存儲著Activity的包名和類名;代碼4則根據(jù)ComponentName創(chuàng)建了要啟動的Activity對象;代碼5調用makeApplication創(chuàng)建Application對象,這個方法內部會調用Application的onCreate方法;代碼6則調用了Activity的attach方法,這個方法中會做一些初始化的工作;最后代碼7調用Instrumentation的callActivityOnCreate來啟動Activity。

allActivityOnCreate中調用了Activity的performCreate方法,而這個方法中會調用Activity的onCreate方法,這樣Activity就啟動起來了。

總結

上面可以看到,入口Activity的啟動會涉及4個進程:Zygote進程,Launcher進程、AMS進程(SystemServer進程)和應用程序進程。

Launcher向AMS請求創(chuàng)建入口Activity,AMS先判斷這個Activity的應用程序進程是否存在并啟動,如果不存在會請求Zygote創(chuàng)建應用程序進程并啟動。應用程序進程啟動后,會通知給AMS, AMS這時候就會請求創(chuàng)建入口Activity并啟動。如圖:

image.png

注意:這個過程中,AMS與Zygote是Socket通信,而Launcher與AMS是Binder通信,同樣AMS與應用程序進程也是Binder通信。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容