Activity是如何顯示出來的?(上)

前言

如題所示,Activity是如何顯示出來的呢?簡單,調用startActivity就能夠啓動目標Activity了。很方便,但其實也隱藏了不少細節。startActivity後發生了什麼事?怎麼一個簡單的接口就能啓動一個界面,且該界面所在進程還未啓動過。本篇文章承接《我是怎麼把一個個App進程建立起來的》,描述接下來發生的事。java

概述

想要啓動一個Activity,首先得啓動它的進程,由AMS將啓動進程的需求發給Zygote,由這位大佬fork出一個進程,而後啓動。啓動的入口是ActivityThread類的main方法,分析從這裏開始。android

ActivityThread的main方法

咱們總說UI的刷新是在主線程進行的,但卻沒找到相關主線程的痕跡。今天它來了,UI主線程就在此處。這裏列出main方法關鍵代碼進行分析。微信

//frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {

    ....
    //①建立一個Loop實體,用於消息處理
    Looper.prepareMainLooper();
    ....
    //②建立ActivityThread對象,而後在attach方法中會完成Application對象的初始化,而後調用Application的onCreate()方法
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    //③獲取Handler對象
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    ....
    ④啓動Loop,表示能夠接收Handler發過來的消息
    Looper.loop();

}
複製代碼

如上按照註釋,main方法中作的事情主要有三件,建立Loop實體,獲取Handler,用於消息處理,建立ActivityThread對象,而後調用attach方法完成Application的初始化。咱們先看看attach方法作了什麼事:app

//frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ViewRootImpl.addFirstDrawHandler(new Runnable() {
            @Override
            public void run() {
                //啓動JIT編譯器,開始編譯
                ensureJitEnabled();
            }
        });
        
        //設置進程名
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        //看app進程內存狀況,若是太大則釋放內存
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                //使用的內存超過最大內存的四分之三,則請求釋放內存
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        mgr.releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
    
        ....
    }
    
    ....

}
複製代碼

應用進程調用的attach方法傳入的第一個參數爲false,因此咱們這裏主要看false分支的代碼就行了。這裏面主要作了以下幾件事:框架

1.啓動JIT編譯器,開始編譯;&emsp;//這是啥,我也不清楚,後面再找時間補充學習
2.設置進程名;
3.經過ActivityManager獲取AMS服務代理對象IActivityManager,經過它來完成一次跨進程操做,主要是用來綁定ApplicationThread對象;
4.內存使用檢測,若發現使用的內存超過最大內存的四分之三,則申請進行內存釋放;
複製代碼

bind Application

這裏還看不出Activity的顯示相關,還須要進入AMS進行查看attachApplication方法:ide

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
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);
    }
}
複製代碼

這裏又封裝了一層,調用attachApplicationLocked方法:oop

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
        
    ....
    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);
    ....
    
    
    // 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) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true;
        }
    }
    
    ....
}
複製代碼

attachApplicationLocked方法比較長,在進行bind以前,前面部分在進行一些app的準備工做。一切準備就緒,會回調ActivityThread對象自己的bindApplication方法進行綁定。接着若是這個進程有待顯示的Activity在棧頂,則會調用ActivityStackSupervisor類的attachApplicationLocked方法進行顯示。post

realStartActivityLocked

/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {

    ....
    try {
        if (realStartActivityLocked(activity, app,
                top == activity /* andResume */, true /* checkConfig */)) {
            didSomething = true;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Exception in new application when starting activity "
                + top.intent.getComponent().flattenToShortString(), e);
        throw e;
    }
    ....
}
複製代碼

最終調用realStartActivityLocked方法:學習

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
        
    ...
    // Create activity launch transaction.
    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));
    ...
    // Schedule transaction.
    mService.getLifecycleManager().scheduleTransaction(clientTransaction);
    ...
}
複製代碼

該方法建立了一個加載Activity的事務,等一切狀態就緒,調用ClientLifecycleManager類的scheduleTransaction方法開始處理事務。ui

處理啓動Activity的事務

/frameworks/base/services/core/java/com/android/server/am/ClientLifecycleManager.java
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if (!(client instanceof Binder)) {
        // If client is not an instance of Binder - it's a remote call and at this point it is
        // safe to recycle the object. All objects used for local calls will be recycled after
        // the transaction is executed on client in ActivityThread.
        transaction.recycle();
    }
}
複製代碼

最終調用了ClientTransaction對象的schedule方法,ClientTransaction對象在上個方法中被建立,即上述所說的事務。回到ClientTransaction的實現:

frameworks/base/core/java/android/app/servertransaction/ClientTransaction.java
public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}
複製代碼

mClient又是什麼?這是一個IApplicationThread類型的變量,該變量在建立事務的時候被賦值:

public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
    ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
    if (instance == null) {
        instance = new ClientTransaction();
    }
    instance.mClient = client;
    instance.mActivityToken = activityToken;

    return instance;
}
複製代碼

兜兜轉轉,咱們須要返回realStartActivityLocked方法中查看client究竟是個啥:

final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
            r.appToken);
複製代碼

建立啓動Activity事務時,傳入了一個IApplicationThread引用,這只是個代理,真正的實如今ApplicationThread類中,這是ActivityThread類的內部類,看看具體實現:

frameworks/base/core/java/android/app/ActivityThread.java
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        ActivityThread.this.scheduleTransaction(transaction);
}
複製代碼

這裏直接調用ActivityThread父類的方法,發出一個處理事務的msg:

frameworks/base/core/java/android/app/ClientTransactionHandler.java
void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
複製代碼

具體處理仍是ActivityThread中:

public void handleMessage(Message msg) {

    ...
    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;
    ...
}
複製代碼

還未到終點,又是一個execute方法,進入看看:

frameworks/base/core/java/android/app/servertransaction/TransactionExecutor.java
public void execute(ClientTransaction transaction) {
    final IBinder token = transaction.getActivityToken();
    log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

    executeCallbacks(transaction);

    executeLifecycleState(transaction);
    mPendingActions.clear();
    log("End resolving transaction");
}

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    ....
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
        ....
        item.execute(mTransactionHandler, token, mPendingActions);
        item.postExecute(mTransactionHandler, token, mPendingActions);
        ....
    }
    ....
}
複製代碼

這裏若是直接進入到ClientTransactionItem類中,會發現並沒有具體實現,這就是個抽象類。item是從事務中獲取的回調,還記得在realStartActivityLocked方法中建立事務的過程麼?建立了事務以後,還作了一件事:

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));
複製代碼

這裏增長了一個LaunchActivityItem類的回調,而LaunchActivityItem正是繼承ClientTransactionItem類,因此這裏的execute方法應該是在LaunchActivityItem類中實現:

frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    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 */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
複製代碼

又回調了ActivityThread(繼承ClientTransactionHandler抽象類)的handleLaunchActivity方法:

frameworks/base/core/java/android/app/ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    ....
    final Activity a = performLaunchActivity(r, customIntent);
    ....
}
複製代碼

真正處理Activity啓動的地方

真正啓動Activity的核心即將到來:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ....
    activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
    
    ....
    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);
    
    ....
    mInstrumentation.callActivityOnPostCreate(activity, r.state);
    ....

}
複製代碼

這裏主要作了三件事:

1.經過Instrumentation類建立出activity;
2.調用activity的attach方法建立窗口,爲onCreate方法作準備;
3.經過callActivityOnPostCreate方法,最終調用activity的onCreate方法,在該方法中,經過setContentView方法將activity具體的view樹加載到窗口。
複製代碼

到了這裏,Activity還未真正顯示出來,只是該作的準備都作好了,下一步就是將具體的view加載到窗口中進行顯示。這部份內容留到下一章節分析。

結語

Activity的啓動確實複雜,到如今也只是大概捋了個流程,並無深刻理解。在本章節中,大概分析了startActivity的流程。若是Activity所在進程是首次啓動,則還須要經過AMS向Zygote進程發起進程建立的需求,而後在建立出來的子進程中,使用反射的方法,找到App的ActivityThread的main方法,並啓動運行。

先掌握大概的流程框架,再逐步深刻了解各個模塊。下一個章節分析view的加載。

微信公衆號

我在微信公衆號也有寫文章,更新比較及時,有興趣者能夠掃描以下二維碼,或者微信搜索【Android系統實戰開發】,關注有驚喜哦!

相關文章
相關標籤/搜索