【Android原始碼】Activity的啟動流程

指間沙似流年發表於2017-12-23

通常情況下,我們在顯式呼叫Activity的情況下,只需要通過如下程式碼就能啟動一個Activity:

Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);
複製程式碼

通過上面的程式碼就能啟動一個Activity,之後新的Activity就能被系統展示給使用者。 那麼系統是如何啟動一個Activity? 新的Activity物件是在什麼情況下被建立的? onCreate是在什麼時機被系統回撥的?

帶著這些問題,我們來一起分析下Activity的啟動過程。

我們通過startActivity開始分析:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
   if (mParent == null) {
       Instrumentation.ActivityResult ar =
           mInstrumentation.execStartActivity(
               this, mMainThread.getApplicationThread(), mToken, this,
               intent, requestCode, options);
       if (ar != null) {
           mMainThread.sendActivityResult(
               mToken, mEmbeddedID, requestCode, ar.getResultCode(),
               ar.getResultData());
       }
       if (requestCode >= 0) {
           // If this start is requesting a result, we can avoid making
           // the activity visible until the result is received.  Setting
           // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
           // activity hidden during this time, to avoid flickering.
           // This can only be done when a result is requested because
           // that guarantees we will get information back when the
           // activity is finished, no matter what happens to it.
           mStartedActivity = true;
       }

       cancelInputsAndStartExitTransition(options);
       // TODO Consider clearing/flushing other event sources and events for child windows.
   } else {
       if (options != null) {
           mParent.startActivityFromChild(this, intent, requestCode, options);
       } else {
           // Note we want to go through this method for compatibility with
           // existing applications that may have overridden it.
           mParent.startActivityFromChild(this, intent, requestCode);
       }
   }
}
複製程式碼

通過上面的程式碼可以發現呼叫了mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options)這個方法:

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
   IApplicationThread whoThread = (IApplicationThread) contextThread;
   Uri referrer = target != null ? target.onProvideReferrer() : null;
   if (referrer != null) {
       intent.putExtra(Intent.EXTRA_REFERRER, referrer);
   }
   if (mActivityMonitors != null) {
       synchronized (mSync) {
           final int N = mActivityMonitors.size();
           for (int i=0; i<N; i++) {
               final ActivityMonitor am = mActivityMonitors.get(i);
               if (am.match(who, null, intent)) {
                   am.mHits++;
                   if (am.isBlocking()) {
                       return requestCode >= 0 ? am.getResult() : null;
                   }
                   break;
               }
           }
       }
   }
   try {
       intent.migrateExtraStreamToClipData();
       intent.prepareToLeaveProcess(who);
       int result = ActivityManagerNative.getDefault()
           .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;
}
複製程式碼

通過上面的程式碼可以發現,啟動Activity的真正實現是ActivityManangerNative.getDefault()startActivity方法來完成的。

public abstract class ActivityManagerNative extends Binder implements IActivityManager{
}
複製程式碼

通過觀察ActivityManangerNative可以發現繼承了Binder並實現了IActivityManager,所以ActivityManangerNative是一個Binder物件:

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
   protected IActivityManager create() {
       IBinder b = ServiceManager.getService("activity");
       if (false) {
           Log.v("ActivityManager", "default service binder = " + b);
       }
       IActivityManager am = asInterface(b);
       if (false) {
           Log.v("ActivityManager", "default service = " + am);
       }
       return am;
   }
};
複製程式碼

通過ActivityManangerNative.getDefault()方法可以看到這是一個單例的封裝:

IBinder b = ServiceManager.getService("activity");
複製程式碼

通過ServiceManger來獲取到真正的Binder物件並返回,而這個物件就是ActivityManagerService,那麼怎麼確定就是它呢?可以參考PackageManagerService的建立過程

到此為止,Activity的啟動過程就轉到了ActivityManagerService中(不同版本的原始碼略有區別):

   ActivityManagerService.startActivity
-> ActivityManagerService.startActivityAsUser
-> ActivityStarter.startActivityMayWait
-> ActivityStarter.startActivityLocked
-> ActivityStarter.startActivityUnchecked
-> ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
-> ActivityStack.resumeTopActivityUncheckedLocked
-> ActivityStack.resumeTopActivityInnerLocked
-> ActivityStackSupervisor.startSpecificActivityLocked
-> ActivityStackSupervisor.realStartActivityLocked
複製程式碼

通過不斷的跳轉最終跳轉到了ActivityStackSupervisor.realStartActivityLocked方法中:

app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
複製程式碼

app.threadIApplicationThread的型別:

public interface IApplicationThread extends IInterface {}
複製程式碼

IApplicationThreadIInterface型別,所以它也是一個Binder型別的介面,從IApplicationThread的宣告可以看出,其中包含了大量的啟動、停止Activity的介面,還包含啟動和停止Service的介面。通過宣告可以猜測這個Binder介面完成了大量的Activity和Service啟動和停止相關的功能。

那麼IApplicationThread的實現又是什麼呢?

我們通過追溯thread可以知道是ApplicationThread

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
      ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
      CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
      int procState, Bundle state, PersistableBundle persistentState,
      List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
      boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

  updateProcessState(procState, false);

  ActivityClientRecord r = new ActivityClientRecord();

  r.token = token;
  r.ident = ident;
  r.intent = intent;
  r.referrer = referrer;
  r.voiceInteractor = voiceInteractor;
  r.activityInfo = info;
  r.compatInfo = compatInfo;
  r.state = state;
  r.persistentState = persistentState;

  r.pendingResults = pendingResults;
  r.pendingIntents = pendingNewIntents;

  r.startsNotResumed = notResumed;
  r.isForward = isForward;

  r.profilerInfo = profilerInfo;

  r.overrideConfig = overrideConfig;
  updatePendingConfiguration(curConfig);

  sendMessage(H.LAUNCH_ACTIVITY, r);
}
複製程式碼

這個方法很簡單,就是構造了ActivityClientRecord並賦值,之後傳送一個訊息給Handler,這個Handler就是主執行緒的H:

case LAUNCH_ACTIVITY: {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
        
        r.packageInfo = getPackageInfoNoCheck(
                r.activityInfo.applicationInfo, r.compatInfo);
        handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    } break;
    
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    Activity a = performLaunchActivity(r, customIntent);
}
複製程式碼

最終performLaunchActivity完成了Activity物件的建立和啟動過程。

這個方法主要完成了這幾個操作:

  1. 通過ActivityClientRecord獲取到需要啟動的Activity的元件資訊

    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
      r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
              Context.CONTEXT_INCLUDE_CODE);
    }
    
    ComponentName component = r.intent.getComponent();
    if (component == null) {
      component = r.intent.resolveActivity(
          mInitialApplication.getPackageManager());
      r.intent.setComponent(component);
    }
    
    if (r.activityInfo.targetActivity != null) {
      component = new ComponentName(r.activityInfo.packageName,
              r.activityInfo.targetActivity);
    }
    
    複製程式碼
  2. 通過類載入器建立Activity

    Activity activity = null;
    try {
      java.lang.ClassLoader cl = r.packageInfo.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);
      }
    } catch (Exception e) {
      if (!mInstrumentation.onException(activity, e)) {
          throw new RuntimeException(
              "Unable to instantiate activity " + component
              + ": " + e.toString(), e);
      }
    }
    public Activity newActivity(ClassLoader cl, String className,
       Intent intent)
       throws InstantiationException, IllegalAccessException,
       ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }
    複製程式碼
  3. 通過makeApplication嘗試建立Application

    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    複製程式碼

    從makeApplication中也可以看到如果Application已經存在了,那麼就不會在建立Application,保證一個應用只有一個Application物件。Application也是通過類載入器來建立的。

    instrumentation.callApplicationOnCreate(app);
    複製程式碼

    當Application第一次建立之後就會呼叫Application的onCreate方法,這就是為什麼當啟動一個App的時候,Application會被首先呼叫的原因。

  4. 建立ContextImpl物件並通過Activity的attach方法來完成一系列操作

    Context appContext = createBaseContextForActivity(r, activity);
     CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
     Configuration config = new Configuration(mCompatConfiguration);
     if (r.overrideConfig != null) {
         config.updateFrom(r.overrideConfig);
     }
     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
             + r.activityInfo.name + " with config " + config);
     Window window = null;
     if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
         window = r.mPendingRemoveWindow;
         r.mPendingRemoveWindow = null;
         r.mPendingRemoveWindowManager = 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);
    
    複製程式碼

    attach方法會關聯ContextImpl物件,還會關聯Window物件,並建立自己和Window物件的關聯。

  5. 呼叫Activity的onCreate方法

    mInstrumentation.callActivityOnCreate(activity, r.state);
    -> activity.performCreate(icicle);
    
    final void performCreate(Bundle icicle) {
       restoreHasCurrentPermissionRequest(icicle);
       onCreate(icicle);
       mActivityTransitionState.readState(icicle);
       performCreateCommon();
    }
    複製程式碼

    最終呼叫了我們熟悉的onCreate的生命週期中,此時Activity就完成了整個的啟動過程。

相關文章