AMS與ApplicationThread通信

1.引言

利用幾個星期的時間,搞懂以下幾個問題:

  • window 添加view的過程
  • ActivityThread啟動Activity得過程
  • Instrumentation 類
  • WindowManager 和Window的關系
  • Dialog 和Activity 顯示流程
  • ViewRootImp學習
  • WindowManagerImpl
  • WindowManagerService 與WindowManager的交互

2.正題

transact():將 IBinder object 的引用跨進程傳遞到服務端,服務端回應客戶端也會帶上相同的IBinder 引用。transact() 是一個同步的過程,當執行到transact()得時候,會陷入阻塞狀態;例如A進程向B進程通信,會將一個IBinder對象通過transact()方法發送到進程B,進程B運算好后,會調用onTransact將運算結果返回的IBinder對象,都是同一個引用。

 public final boolean transact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

code參數決定了是發送數據還是接收數據。

onTransact()方法:

 protected boolean onTransact(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException {
        if (code == INTERFACE_TRANSACTION) {
            reply.writeString(getInterfaceDescriptor());//推測是向遠程進程發送數據
            return true;
        } else if (code == DUMP_TRANSACTION) {//Dump  TRANSACTION 英文單詞是卸載交流,大概意思就是接收到遠程服務器換回 的值,
            ParcelFileDescriptor fd = data.readFileDescriptor();
            String[] args = data.readStringArray();//讀取返回的結果
            if (fd != null) {
                try {
                    dump(fd.getFileDescriptor(), args);
                } finally {
                    IoUtils.closeQuietly(fd);
                }
            }
            // Write the StrictMode header.
            if (reply != null) {
                reply.writeNoException();
            } else {
                StrictMode.clearGatheredViolations();
            }
            return true;
        } else if (code == SHELL_COMMAND_TRANSACTION) {
            ParcelFileDescriptor in = data.readFileDescriptor();
            ParcelFileDescriptor out = data.readFileDescriptor();
            ParcelFileDescriptor err = data.readFileDescriptor();
            String[] args = data.readStringArray();
            ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data);
            ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
            try {
                if (out != null) {
                    shellCommand(in != null ? in.getFileDescriptor() : null,
                            out.getFileDescriptor(),
                            err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
                            args, shellCallback, resultReceiver);
                }
            } finally {
                IoUtils.closeQuietly(in);
                IoUtils.closeQuietly(out);
                IoUtils.closeQuietly(err);
                // Write the StrictMode header.
                if (reply != null) {
                    reply.writeNoException();
                } else {
                    StrictMode.clearGatheredViolations();
                }
            }
            return true;
        }
        return false;
    }

ActivityThread中的attach(false),方法涉及到通過Binder通信,如何進行通信的呢?

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault(); // 重點1
            try {
                mgr.attachApplication(mAppThread);// 重點2
            } catch (RemoteException ex) {
                // Ignore
            }
            // Watch for getting close to heap limit.
        .............//省略
}

下面的是AMS與ApplicationThread 通過Binder通信中,一些相關的類:


image.png

ActivityManagerNative.getDefault() 返回的就是ActivityManagerNative的內部類ActivityManagerProxy,這個代理的構造方法需要傳入一個服務端的IBinder。

ActivityManagerNative得gDefault 內部create方法有這么一句代碼:

IBinder b = ServiceManager.getService("activity");
然后通過:asInterface()方法得到ActivityManagerProxy。

ActivityManagerProxy的attachApplication(applicationThread)代碼如下:

 public void attachApplication(IApplicationThread app) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(app.asBinder());
        mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }

mRemote 就是我們上面ServiceManager.getService("activity")返回的,也就是AMS得BinderProxy,這個BinderProxy會將ApplicationThread的binder 傳遞到AMS進程,那么AMS就相當于擁有了ApplicationThread得引用。那么就可以遠程調用了、

當客戶端調用了startActivity得時候,會通過ipc與AMS通信,然后AMS調用Application得handleLaunchActivity(上面分析得到,AMS持有ApplicationThread得Binder)。進而執行了一下幾個方法

 Activity a = performLaunchActivity(r, customIntent);//方法1
 
handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);//方法2

mInstrumentation.callActivityOnPause(r.activity);//方法3

handleResumeActivity 放先回調Activity的onResume方法,之后在將DecorView添加進Window。

 if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow();
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (a.mVisibleFromClient) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                }
}

關于java層Binder的調用順序描述:
binder通信是一種client-server的通信結構,
1.從表面上來看,是client通過獲得一個server的代理接口,對server進行直接調用;
2.實際上,代理接口中定義的方法與server中定義的方法是一一對應的;
3.client調用某個代理接口中的方法時,代理接口的方法會將client傳遞的參數打包成為Parcel對象;
4.代理接口將該Parcel發送給內核中的binder driver.
5.server會讀取binder driver中的請求數據,如果是發送給自己的,解包Parcel對象,處理并將結果返回;
6.整個的調用過程是一個同步過程,在server處理的時候,client會block住。


image.png

參考文章:https://blog.csdn.net/coding_glacier/article/details/7520199
參考文章:http://weishu.me/2016/01/12/binder-index-for-newer/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容