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的啓動,並執行它的生命週期方法。

在ApplicationThreaad中,對應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圖



一個圖是關於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圖附上一點業務邏輯,應該是這樣。紅色部分的是業務邏輯






重點二: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

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章