天天看點

android Activity啟動過程 簡析

概括

先簡略概括一下Activity的啟動過程,以下拿點選Launcher來說。

1.開始請求執行Activity,Launcher程序發送指令到AMS

Launcher就是一個App,點選Launcher會隐式啟動一個新的應用。是以跑的也是Activity.startActivity的流程。

接着就是Activity.startActivityForResult()  ——> Instrumentation.execStartActivity()...一系列方法。

2.AMS執行Launcher(棧頂Activity)的onPause方法

AMS通過Binder執行Launcher的onPause方法

3.啟動Activity所屬的應用程序

-從Zygote中fork一個新應用程序出來。裡面有負責排程ActivityRecord和Task的代碼。

排程Task的算法涉及的判斷很多,和目前回退棧,要啟動的activity的啟動模式,以及taskAffinity屬性,啟動Activity時設定的intent的flag等諸多要素相關

-之後會執行ActivityThread類的main方法。Activity就在這個ActivityThread執行個體中運作。

4.執行啟動Activity

AMS通過代理,請求啟動Activity。ApplicationThread通知主線程執行該請求。然後,ActivityThread執行Activity的啟動,并執行它的生命周期方法。

在ApplicationThread中,對應AMS管理Activity生命周期的方法都以scheduleXXXActivity,ApplicationThread在Binder線程中,它會向主線程發送消息,ActivityThread的Handler會調用相應的handleXXXActivity方法,然後會執行performXXXActivity方法,最終調用Activity的onXXX方法。

5.AMS執行Launcher(棧頂Activity)的onStop方法

AMS通過Binder執行Launcher的onStop方法

--------------------------分割線--------------------------

前置說明:安卓衆多應用來回切換,肯定不是兩兩應用進行通信能協調好的事,是以需要一個總管家的身份。這裡就是我們的AMS。它掌管着所有Activity的生命周期。

已知AMS是運作在SystemServer這個程序上,衆多Activity運作在各種應用程序中,那麼問題來了...

重點一:衆多Activity怎麼與AMS通信的

先來兩張UML圖

android Activity啟動過程 簡析
android Activity啟動過程 簡析

一個圖是關于ActivityManager,一個是關于ApplicationThread。

拿ActivityManager這個UML圖來分析一下。ApplicationThread跟這個差不多。

我們知道用android實作IPC,寫個XXX.aidl,ide會為我們生成一個同檔案名不同字尾的XXX.java檔案。這個檔案裡面的結構就像這張UML圖的結構。

1.這個XXX.java類首先是一個接口,繼承IInterface接口。裡面一般聲明了需要提供的業務方法。在這裡就是IActivityManager。

2.然後XXX.java有一個内部有個抽象類Stub繼承Binder實作XXX接口。在這裡就是ActivityManagerNative+ActivityManagerProxy。

3.Stub裡面還有内部類Proxy實作了XXX接口。在這裡就是ActivityManagerProxy。

ActivityManagerNative即Stub相當于服務端。ActivityManagerProxy即Proxy相當于用戶端。是以ActivityManager設計成這樣的aidl結構完成通信。

再具體一點,來看看這個機制怎麼完成startActivity方法。

首先是從Activity.startActivity --> Activity.startActivityForResult() --> Instrumentation.execStartActivity()  

然後就會調用ActivityManagerNative.getDefault().startActivity()方法

getDefault會嘗試通過ServiceManager.getService("activity")遠端服務的Binder對象,然後進行asInterface轉換成IActivityManager,其實傳回的就是ActivityManagerProxy。

源碼是這個樣子的。

先看getDefault部分,使用了自帶的Singleton類實作單例模式,并且聲明是靜态方法。

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


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

然後看startActivity部分,類ActivityManagerProxy的startActivity方法

class ActivityManagerProxy implements IActivityManager {
    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
}
           

裡面是對參數使用Parcel序列化,然後調用transact方法,參數是方法名辨別,參數,盛放傳回值的容器。

這樣就會跳轉到ActivityManagerService的onTransact方法,ActivityManagerService會調用父類ActivityManagerNative的onTransact方法。

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        case START_ACTIVITY_TRANSACTION:
        {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            String callingPackage = data.readString();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            IBinder resultTo = data.readStrongBinder();
            String resultWho = data.readString();
            int requestCode = data.readInt();
            int startFlags = data.readInt();
            ProfilerInfo profilerInfo = data.readInt() != 0
                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
            Bundle options = data.readInt() != 0
                    ? Bundle.CREATOR.createFromParcel(data) : null;
            int result = startActivity(app, callingPackage, intent, resolvedType,
                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
            reply.writeNoException();
            reply.writeInt(result);
            return true;
        }
		}
	}
           

是以用戶端調用的方法都要經過onTransact方法轉化。是以裡面switch判斷一下辨別,就進入START_ACTIVITY_TRANSACTION的case裡面。裡面也有一個startActivity方法(注意此時已經位于AMS程序中了),在ActivityManagerNative這個抽象類裡沒有實作這個方法,是以交給AMS具體實作的方法來處理了。

是以ActivityManagerNative主要是負責Binder機制中,接受參數,轉換處理參數這些功能。之後把參數整理好,才會交個AMS,AMS才是具體的處理業務的邏輯。

之後就是AMS的startActivity方法了,這裡面的調用鍊和處理邏輯就多了。

比如判斷這個新程序是不是已經啟動了,不需要再從zygote中fork一個程序出來。。。。。。。。。

ps:是以在我腦裡,我覺得這兩張UML圖附上一點業務邏輯,應該是這樣。紅色部分的是業務邏輯

android Activity啟動過程 簡析

重點二:ActivityThread的Main方法幹了什麼

從zygote中fork出一個新程序後,就會執行ActivityThread的main方法。

經典問題,一個App的程式入口到底是什麼?回答的就是這個ActivityThread的main方法了

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

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

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        AndroidKeyStoreProvider.install();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
           

1.這裡有關于主線程Looper的操作

我們知道如果主線程像子線程發送消息,需要有Looper.prepare()和Looper.loop()操作。

在這裡就是prepareMainLooper(),因為這是主線程,這名字簡直不能更形象了。

2.這裡有new ActivityThread()。

3.thread.attach(false); 執行ActivityThread的attach方法。看下源碼,挑出重點

private void attach(boolean system) {
		...
        if (!system) {
            ...
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
            ...
    }
           

裡面依舊ActivityManagerNative.getDefault()擷取到ActivityManagerProxy。執行attachApplication方法,傳的參數mAppThread類型是ApplicationThread。

這個mAppThread是在new ActivityThread()時做為成員變量同時初始化的。

然後中間過程同上面之前說的ActivityManager的binder機制調用流程,這裡忽略這些流程,直接看AMS的attachApplication方法。

AMS的attachApplication方法調用attachApplicationLocked方法,裡面參數就是當初傳過去的ApplicationThread。

接着在這裡面又用了這個ApplicationThread調用了bindApplication方法。

public final void bindApplication(String processName, ApplicationInfo appInfo,
		List<ProviderInfo> providers, ComponentName instrumentationName,
		ProfilerInfo profilerInfo, Bundle instrumentationArgs,
		IInstrumentationWatcher instrumentationWatcher,
		IUiAutomationConnection instrumentationUiConnection, int debugMode,
		boolean enableOpenGlTrace, boolean trackAllocation, boolean isRestrictedBackupMode,
		boolean persistent, Configuration config, CompatibilityInfo compatInfo,
		Map<String, IBinder> services, Bundle coreSettings) {

	if (services != null) {
		// Setup the service cache in the ServiceManager
		ServiceManager.initServiceCache(services);
	}

	setCoreSettings(coreSettings);

	AppBindData data = new AppBindData();
	data.processName = processName;
	data.appInfo = appInfo;
	data.providers = providers;
	data.instrumentationName = instrumentationName;
	data.instrumentationArgs = instrumentationArgs;
	data.instrumentationWatcher = instrumentationWatcher;
	data.instrumentationUiAutomationConnection = instrumentationUiConnection;
	data.debugMode = debugMode;
	data.enableOpenGlTrace = enableOpenGlTrace;
	data.trackAllocation = trackAllocation;
	data.restrictedBackupMode = isRestrictedBackupMode;
	data.persistent = persistent;
	data.config = config;
	data.compatInfo = compatInfo;
	data.initProfilerInfo = profilerInfo;
	sendMessage(H.BIND_APPLICATION, data);
}
           

最後一行看到發消息了,其實發到mH這個Handler裡面。

點進去handleMessage方法,能看到很多case,比如LAUNCH_ACTIVITY, PAUSE_ACTIVITY, RESUME_ACTIVITY, DESTROY_ACTIVITY這種跟Activity相關的

還有CREATE_SERVICE, BIND_SERVICE, UNBIND_SERVICE, STOP_SERVICE跟Service相關的。

大概能猜出,這是AMS管理App的一道關卡。

我們找到BIND_APPLICATION辨別,看到他進入了handleBindApplication方法裡面。

private void handleBindApplication(AppBindData data) {
	...
	if (data.instrumentationName != null) {
		...
			mInstrumentation = (Instrumentation)
				cl.loadClass(data.instrumentationName.getClassName()).newInstance();
		...
	} else {
		mInstrumentation = new Instrumentation();
	}

	...

	try {
		...
		Application app = data.info.makeApplication(data.restrictedBackupMode, null);
		mInitialApplication = app;

		...
		try {
			mInstrumentation.onCreate(data.instrumentationArgs);
		}
		catch (Exception e) {
			throw new RuntimeException(
				"Exception thrown in onCreate() of "
				+ data.instrumentationName + ": " + e.toString(), e);
		}

		try {
			mInstrumentation.callApplicationOnCreate(app);
		} catch (Exception e) {
			if (!mInstrumentation.onException(app, e)) {
				throw new RuntimeException(
					"Unable to create application " + app.getClass().getName()
					+ ": " + e.toString(), e);
			}
		}
	}
	...
}
           

裡面有建立Instrumentation的代碼,能了解,Activity的生命周期方法都是Instrumentation調用的,當然要先new一個。

然後是makeApplication這個方法,這名字+傳回值是個Application,很容易猜到是建立應用的Application。進去裡面一看,果然是這樣。

這個建立方法需要在LoadedApk中轉一手,需要需要這個類是可以讀取到xml裡面的自定義Application的類名字元串(如果有自定義Application的話,沒有會用預設字元串“android.app.Application”)。

然後根據類的全名用反射newInstance出來一個Application。

最後調用callApplicationOnCreate,裡面隻有一個代碼,就是執行application的onCreate方法。

是以其中一個重要流程是,運作應用Application的相關業務。接下來回到ActivityManagerService的attachApplicationLocked方法中,下一步是mStackSupervisor.attachApplicationLocked(app)。

這個app是ProcessRecord的類型,本來我覺得這是AMS(服務端)儲存某一個應用(用戶端)資訊的實體,心裡稱它為“應用實體資訊類”。後來發現并不能這樣想,因為一個程序裡面可能有多個應用的Activity,是以還是隻能稱為“程序實體資訊類”。

attachApplicationLocked方法裡面會調用realStartActivityLocked方法,裡面有一句代碼app.thread.scheduleLaunchActivity。這個thread是實際上是ApplicationThreadProxy類的實體,是以這句話會通過binder機制,調用到ApplicationThread裡面的scheduleLaunchActivity方法。

在這個方法的後一行看到發送一個LAUNCH_ACTIVITY的消息到H這個Hander裡面。找到LAUNCH_ACTIVITY這個case,我們看到執行了handleLaunchActivity方法。

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
	...
	Activity a = performLaunchActivity(r, customIntent);
	...
	if (a != null) {
		...
		handleResumeActivity(r.token, false, r.isForward,
				!r.activity.mFinished && !r.startsNotResumed);
	...	
}
           

裡面有兩行重要的代碼,重要代碼一,執行perforLaunchActivity方法。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
		...
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
         ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
        ...
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
		...

        return activity;
    }
           

裡面有一句mInstrumentation.newActivity方法。點進去隻有一句代碼,功能就是通過反射建立出一個Activity實體。

然後下面會有mInstrumentation.callActivityOnCreate方法。裡面的調用鍊是Activity.performCreate()——>Activity.onCreate()這樣就執行了我們熟悉的onCreate方法。

後面又有activity.performStart()。裡面的調用鍊是Instrumentation.callActivityOnStart()——>Activity.onStart()。

然後回到handleLaunchActivity的重要代碼二,handleResumeActivity裡面的調用鍊是ActivityThread.performResumeActivity()——>Activity.performResume()——>Instrumentation.callActivityOnResume()——>Activity.onResume().執行了我們熟悉的onResume方法。這樣Activity啟動的主要流程就跑完了。

總結一下重點二。

首先想講一下之前一直沒搞清ApplicationThread和ActivityThread這兩者的差別。這兩個名字實在給我造成了很大的誤會。

看了源碼後,才知道。ActivityThread本質是主線程應該處理的代碼,它沒有繼承Thread!!我們常說的UI線程,就是運作在上面的代碼。

ApplicationThread跟Thread沒多大關系,它主要是配合ApplicationThreadNative和ApplicationThreadProxy完成Binder程序間通信的。是以為啥元老Android發明者一開始要給定這個名字呢??

然後想講其實整個ActivityThread的attach方法,裡面涉及的代碼,所有方法調用鍊,随便拿出一個來我感覺細聊的話都可以寫篇文章。

很多細節比如intent的傳遞,ActivityThread時候時候會建立程序什麼時候會尋找已有程序,activity啟動是在具體什麼時候讀取的xml裡面該activity标簽的自定義屬性的等等,都暫時忽略了。

//TODO

//給上面代碼調用畫個時序圖。。。