從Activity的啟動流程理解Binder


簡述

關於Activity啟動流程和Binder的文章很多,大多數是分開來講的,本文將二者結合起來,着重分析啟動流程中跨進程方面的細節,其實,啟動流程看似調用繁多,主要是復雜在Activity棧管理等方面,如果將其看作一個整體,整個啟動流程就簡單很多。在啟動流程中,App和AMS的跨進程調用是其中的重點,理解了這個,會加深對Binder和啟動流程的理解認知,也能窺到Framework層的冰山一角。另外我也發現,很多文章在講啟動流程的時候,關於ActivityMangagerService進程如何調用App進程的細節都沒有講清楚,這個問題也是我寫這篇文章的初衷。閱讀本文前建議了解一下AIDL,對Binder,Stub,Proxy等有一些印象。建議讀一下這篇文章寫給 Android 應用工程師的 Binder 原理剖析

Binder簡介

對於Binder,初學的人會對里面的概念比較模糊,因為看起來確實有些繞,我在這兒寫幾點幫助理解。

  • 所謂的“跨進程”能力指的是兩個方面:一個是能夠作為客戶端調用遠程服務的能力,一個是能夠作為服務端接收客戶端進程消息的能力,二者都是跨進程的一部分,分別對應transact和onTransact方法,而這兩個方法的實現,分別位於BinderProxy和Binder兩個類中,這兩個類都在Binder.java這個文件中,讀者可以自行閱讀。
  • BinderProxy具有發送消息的能力,通過transact方法,調用底層binder驅動,服務端的Binder具有接收底層binder驅動傳過來的消息的能力,當接收到消息會調用onTransact方法。
  • 剛開始看AIDL的時候需要反復記憶理解一下,否則看別的代碼容易混淆。這里說幾個比較容易記憶的點:一個類繼承了Stub類,表示這個類是遠程服務端,Stub類有個asInterface的靜態方法,這個方法用在拿到binder驅動傳過來的BinderProxy對象時,將該對象轉化成client端使用的本地代理xxxProxy,客戶端用它調用遠程service的方法。該代理跟service實現了同樣的接口,只不過一個是真實現,一個是假實現,這里假實現指的是它通過Binder驅動調用S端方法,真正做工作的在Service端。簡言之,Stub代表service端,Proxy代表service在客戶端的代理。
  • 以AMS為例
public class ActivityManagerService extends IActivityManager.Stub

AMS繼承了Stub類,而Stub類一共實現了三個接口:IActivityManger,IBinder,IInterface,分別對應了三種能力,管理activity、跨進程,以及IInterface的asBinder,前兩者好理解,那么這里的asBinder能力是干嘛的呢?這里先賣個關子,等下講啟動流程的時候會說明。

啟動流程

有了Binder的基礎,我們去看啟動流程,AMS和APP跨進程的過程簡單說就是C端和S端分別通過二者在對方的代理去互相調用對方方法的過程。我們先從宏觀角度思考,為什么要跨進程呢?我自己在客戶端new一個Activity不行嗎?不可以的,因為Android的安全機制以及為了統一管理Activity(比如activity棧),需要有個大管家去進行所有Activity的管理和控制,而這個管家是運行在一個單獨進程的,因此App端如果想發起一個Activity的請求,需要先把“申請”提交給大管家,也就是AMS。AMS處理完這個請求之后,需要再次通過跨進程通知App端,去執行剩下的相應的工作。因此這里的核心就在於兩者如何互相調用對方了。

App端如何調用AMS方法

下面看代碼:用戶啟動一個頁面時,會依次調用activity的startActivity-->Instrumentation的executestartActivity-->execStartActivitiesAsUser,這幾個調用很容易找到,就簡單帶過,在最后這個方法里,執行了遠程調用,即:

 int result = ActivityManager.getService()
                .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
                        token, options, userId);

ActivityManager.getService獲取的是什么?看ActivityMangaer.getService()這個代碼里面:

    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

如果對Binder有所了解,應該很容易知道,這里取得的是AMS在客戶端的代理,也就是代碼中的最后一行返回的am。因為App要頻繁的調用AMS的方法,因此用單例模式緩存在本地了一個AMS的本地代理,從單例的第一次獲取可以看到,AMS的Binder是通過ServiceManager.getService()獲取到的,那么ServiceMangaer是個什么東西,其實這個就是Android系統統一管理所有遠程服務的“大管家”,比如AMS,WMS等系統服務都在這里注冊了,客戶端想調用任意一個服務,只需要知道名字就可以通過SM獲取到相應的Server的Binder。拿到Binder之后便可以通過asInterface靜態方法轉化成本地代理,從而調用server的方法了。因此第一次獲取AMS的Binder的過程實際上是客戶端跟ServiceManager的一次跨進程通信。

AMS如何通知App進程

(1)AMS如何獲取到App進程的Binder的

從上面的分析知道,App獲取AMS的Binder實際上是通過ServiceManager這個大管家間接獲取的,那反過來AMS處理完activity的管理任務(棧操作等)之后又如何通知App的呢?
一個App總不可能像AMS那樣在ServiceManger中注冊吧,而且也沒這個必要。那么到底是怎么通知的呢?
答案就是:App跨進程調用AMS的方法時,還順便把App進程(這個時候App可以看作是服務端了)的Binder作為參數傳給了AMS,AMS拿到這個APP的Binder之后,通過asInterface方法轉化成在server端可以使用的代理,然后在需要回調App進程的時候通過這個代理來通知客戶端。其實跟App端邏輯是一致的,只不過C/S調了一下順序,C變成了S,S變成了C。下面我們從代碼里驗證:
我們以6.0之前版本的源碼為例,新版本改成事務了,有些源碼不容易看到,不如直接看老版本的,便於理解。
首先看APP調用startActivity時是如何把App進程的Binder參數傳過去的,剛才說了,startActivity實際上調用的是AMS本地代理的startActivity,而AMS本地代理是ActivityMangerProxy,這里AMP是AIDL自動生成的

class ActivityManagerProxy implements IActivityManager
{
    public ActivityManagerProxy(IBinder remote)
    {
        mRemote = remote;
    }
    
    public IBinder asBinder()
    {
        return mRemote;
    }
    
    public int startActivity(IApplicationThread caller, Intent intent,
            String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
            IBinder resultTo, String resultWho,
            int requestCode, boolean onlyIfNeeded,
            boolean debug, String profileFile, ParcelFileDescriptor profileFd,
            boolean autoStopProfiler) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeTypedArray(grantedUriPermissions, 0);
        data.writeInt(grantedMode);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(onlyIfNeeded ? 1 : 0);
        data.writeInt(debug ? 1 : 0);
        data.writeString(profileFile);
        if (profileFd != null) {
            data.writeInt(1);
            profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        data.writeInt(autoStopProfiler ? 1 : 0);
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

startActivity方法的第一個參數caller,這個東西是IApplicationThread,這個IApplicationThread就是AMS去通知App做相應處理的接口,它跟IActivityManger配合組成了App和AMS交互的“協議”。那么這個傳過來的IApplicationThread的是誰呢,通過看代碼里的調用鏈:

Instrumentation:
int result = ActivityManager.getService()
                .startActivityAsUser(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, resultWho,
                        requestCode, 0, null, options, user.getIdentifier());


ContextImpl:
        mMainThread.getInstrumentation().execStartActivities(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intents, options);

ActivityThread:
    public ApplicationThread getApplicationThread()
    {
        return mAppThread;
    }

可以查到,首先是instrumentation類里傳入的whoThread,whoThread是ContextImpl傳進來的mMainThread.getApplicationThread(),而最后這個是mAppThread,這個東西就是ActivityThread這個類的內部類ApplicationThread,我們看代碼:

 private class ApplicationThread extends IApplicationThread.Stub {

繼承自Stub,因此從AIDL語法看出,是一個服務端,對應的客戶端是誰呢?當然是AMS了,所以ApplicationThread這個類就是AMS向App進程發消息時的服務端。

思路回到主線上,上面已經說明了,在客戶端調用Binder的時候把ApplicationThread參數傳給了AMP的startActivity方法,接下來會執行到:

data.writeStrongBinder(caller != null ? caller.asBinder() : null);

注意這里的caller.asBinder,這個方法就解釋了前面遺留的問題,IInterface接口的方法asBinder就是在這個時候用的,即把S端(相對的)轉成一個binder,之后binder寫入到Parcel里,然后通過transact方法調用底層Binder驅動傳給其他進程,這里也要注意,transact方法調用的是mRemote的transact,而mRemote本質上是一個BinderProxy,千萬不要理解成Binder了,因為這兩個類都實現了IBinder接口,我們看代碼的時候很可能會誤認為調用的Binder的transact。binderProxy的transact會調用transactNative函數,傳給jni層,將之前保存在Parcel里的數據data傳給Binder驅動,之后在傳給AMS。可以這樣理解,對於Binder驅動來說,它可以看成跨進程的一個“傳送帶”,從A進程傳遞給B進程,只要你實現了IInterface,就可以放到這個傳送帶上傳送(writeStrongBinder方法)。總結一下就是IInterface接口表明了這個類可以轉成一個binder從而在binder驅動中跨進程運輸,IBinder接口表明了類具有跨進程的能力,即可以通過調用transact方法“使用”Binder驅動。

(2)獲取到了Binder之后

上面的討論已經知道,AMS其實在App跨進程調用AMS的時候就把ApplicationThread轉成Binder傳過來了,傳過來以后,AMS如果要用,必須得拿到ApplicationThread的代理,怎么拿到的呢?
剛才說了AMS的onTransact方法會監聽驅動傳過來的對象,我們看onTransact的代碼:AMS繼承自IActivityManager.Stub,在源碼中叫ActivityManagerNative:

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

可以看到:
IBinder b = data.readStrongBinder();客戶端將binder write到Parcel中,服務端從Parcel中讀了出來,然后通過asInterface轉換成ApplicationThread的代理ApplicationThreadProxy這個類。注意:Binder驅動過來的IBinder不是Binder,而是BinderProxy,但是為什么我們之前傳的參數是ApplicationThread,這個類是一個binder,為什么讀出來以后變成了BinderProxy了呢?答案就在這個readStrongBinder里,看jni層的源碼可以知道,系統在客戶端收到(readStrongBinder)IBinder以后,會保存下來,通過Binder驅動傳給Service時,會通過之前保存的Binder在底層創建BinderProxy,然后傳給上層,其實看framework的源碼,BinderProxy沒有看到在java層的new方法,原來都在底層創建好了。
有了代理對象后接下來既可以直接用了:

int result = startActivity(app, intent, resolvedType,
                    grantedUriPermissions, grantedMode, resultTo, resultWho,
                    requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);

即進入到AMS對Activity啟動管理流程中了,經過復雜的跳轉,最后跑到ActivityStackSupervisor這個類的realStartActivityLocked方法中,里面最終會執行到這行代碼:

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

這里的app.thread就是前面ApplicationThread在AMS中的代理,到了這里大家應該理清楚了,接下來通過代理調起App進程的ApplicationThread里的相應方法,即:scheduleLaunchActivity方法,這個方法會發送一個Message給主線程的handler :H,然后在handleMessage里通過類加載器創建出一個Activity對象,並執行onCreate方法.balabala....

最后用圖片總結一下:
binder.png

最后推薦一篇文章,目前發現的講的binder最詳細的,聽說你 Binder 機制學的不錯,來解決下這幾個問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM