Binder java層實現(xiàn)原理

https://www.bilibili.com/video/BV1zb4y187MW/

一、aidl文件

下面是自己寫的一個aidl文件

package android.os;

interface IHelloService
{
void setVal(int val);
int getVal();
}
注意,這是一個aidl文件倘屹,編譯后會生成一個IHelloService.java圆雁。我們來看一下這個文件的內(nèi)容隱藏著什么奧秘,可以這么神奇地支持進(jìn)程間通信。

在java中有一個aidl文件,讓我們省去了很多工作,其實下了下面這段將aidl文件展開其實很c++很像斑响。

/*

  • This file is auto-generated. DO NOT MODIFY.

  • Original file: frameworks/base/core/java/android/os/IHelloService.aidl
    /
    package android.os;
    public interface IHelloService extends android.os.IInterface
    {
    /
    * Local-side IPC implementation stub class. /
    public static abstract class Stub extends android.os.Binder implements android.os.IHelloService//相當(dāng)于是一個Server端菱属,需要一個子類來繼續(xù)繼承它,完成接口的實現(xiàn)
    {
    private static final java.lang.String DESCRIPTOR = "android.os.IHelloService";
    /
    * Construct the stub at attach it to the interface. */
    public Stub()
    {
    this.attachInterface(this, DESCRIPTOR);
    }

     /**
     * Cast an IBinder object into an android.os.IHelloService interface,
     * generating a proxy if needed.
     */
     public static android.os.IHelloService asInterface(android.os.IBinder obj)//和c++類似舰罚,如果在client端才去new一個proxy
     {
         if ((obj==null)) {
             return null;
         }
         android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
         if (((iin!=null)&&(iin instanceof android.os.IHelloService))) {
             return ((android.os.IHelloService)iin);
         }
         return new android.os.IHelloService.Stub.Proxy(obj);
     }
    
     public android.os.IBinder asBinder()
     {
         return this;
     }
    
     @Override 
     public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
     {
         switch (code)
         {
             case INTERFACE_TRANSACTION:
             {
                 reply.writeString(DESCRIPTOR);
                 return true;
             }
             case TRANSACTION_setVal:
             {
                 data.enforceInterface(DESCRIPTOR);
                 int _arg0;
                 _arg0 = data.readInt();
                 this.setVal(_arg0);
                 reply.writeNoException();
                 return true;
             }
             case TRANSACTION_getVal:
             {
                 data.enforceInterface(DESCRIPTOR);
                 int _result = this.getVal();
                 reply.writeNoException();
                 reply.writeInt(_result);
                 return true;
             }
         }
         return super.onTransact(code, data, reply, flags);
     }
    
     private static class Proxy implements android.os.IHelloService//這個內(nèi)部類纽门,相當(dāng)于一個client端和C++類似
     {
         private android.os.IBinder mRemote;
    
         Proxy(android.os.IBinder remote)
         {
             mRemote = remote;
         }
    
         public android.os.IBinder asBinder()
         {
             return mRemote;
         }
    
         public java.lang.String getInterfaceDescriptor()
         {
             return DESCRIPTOR;
         }
    
         public void setVal(int val) throws android.os.RemoteException
         {
             android.os.Parcel _data = android.os.Parcel.obtain();
             android.os.Parcel _reply = android.os.Parcel.obtain();
             try {
                 _data.writeInterfaceToken(DESCRIPTOR);
                 _data.writeInt(val);
                 mRemote.transact(Stub.TRANSACTION_setVal, _data, _reply, 0);
                 _reply.readException();
             }
             finally {
                 _reply.recycle();
                 _data.recycle();
             }
         }
    
         public int getVal() throws android.os.RemoteException
         {
             android.os.Parcel _data = android.os.Parcel.obtain();
             android.os.Parcel _reply = android.os.Parcel.obtain();
             int _result;
             try {
                 _data.writeInterfaceToken(DESCRIPTOR);
                 mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply, 0);
                 _reply.readException();
                 _result = _reply.readInt();
             }
             finally {
                 _reply.recycle();
                 _data.recycle();
             }
             return _result;
         }
     }
    
     static final int TRANSACTION_setVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
     static final int TRANSACTION_getVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    

    }

    public void setVal(int val) throws android.os.RemoteException;
    public int getVal() throws android.os.RemoteException;
    }
    這里我們可以看到IHelloService.aidl這個文件編譯后的真面目,原來就是根據(jù)IHelloService接口的定義生成相應(yīng)的Stub和Proxy類沸停,這個就是我們熟悉的Binder機(jī)制的內(nèi)容了膜毁,即實現(xiàn)這個HelloService的Server必須繼續(xù)于這里的IHelloService.Stub類,而這個HelloService的遠(yuǎn)程接口就是這里的IHelloService.Stub.Proxy對象獲得的IHelloService接口愤钾。接下來的內(nèi)容瘟滨,我們就可以看到IHelloService.Stub和IHelloService.Stub.Proxy是怎么創(chuàng)建或者使用的。

二. HelloService的啟動過程

    在討論HelloService的啟動過程之前能颁,我們先來看一下實現(xiàn)HelloService接口的Server是怎么定義的杂瘸。

我們在frameworks/base/services/java/com/android/server目錄下新增了一個HelloService.java文件:

package com.android.server;

import android.content.Context;
import android.os.IHelloService;
import android.util.Slog;

public class HelloService extends IHelloService.Stub {//實現(xiàn)aidl文件解析后,里面的內(nèi)部類
private static final String TAG = "HelloService";

HelloService() {
    init_native();
}

public void setVal(int val) {
    setVal_native(val);
}   

public int getVal() {
    return getVal_native();
}

private static native boolean init_native();
    private static native void setVal_native(int val);
private static native int getVal_native();

}
這里伙菊,我們可以看到败玉,HelloService繼續(xù)了IHelloService.Stub類,它通過本地方法調(diào)用實現(xiàn)了getVal和setVal兩個函數(shù)镜硕。
有了HelloService這個Server類后运翼,下一步就是考慮怎么樣把它啟動起來了。在frameworks/base/services/java/com/android/server/SystemServer.java文件中兴枯,定義了SystemServer類血淌。SystemServer對象是在系統(tǒng)啟動的時候創(chuàng)建的,它被創(chuàng)建的時候會啟動一個線程來創(chuàng)建HelloService财剖,并且把它添加到Service Manager中去悠夯。
我們來看一下這部份的代碼:

class ServerThread extends Thread {
......

@Override
public void run() {

    ......

    Looper.prepare();

    ......

    try {
        Slog.i(TAG, "Hello Service");
        ServiceManager.addService("hello", new HelloService());//加入serviceManager中
    } catch (Throwable e) {
        Slog.e(TAG, "Failure starting Hello Service", e);
    }

    ......

    Looper.loop();

    ......
}

}

......

public class SystemServer
{
......

/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);

......

public static final void init2() {
    Slog.i(TAG, "Entered the Android system server!");
    Thread thr = new ServerThread();
    thr.setName("android.server.ServerThread");
    thr.start();
}
......

}

三. Client獲取HelloService的Java遠(yuǎn)程接口的過程

    我們看看它是如何借助Service Manager這個Java遠(yuǎn)程接口來獲得HelloService的遠(yuǎn)程接口的。在Hello這個Activity的onCreate函數(shù)躺坟,通過IServiceManager.getService函數(shù)來獲得HelloService的遠(yuǎn)程接口:

public class Hello extends Activity implements OnClickListener {
......

private IHelloService helloService = null;  

......

@Override  
public void onCreate(Bundle savedInstanceState) {  

    helloService = IHelloService.Stub.asInterface(  
                        ServiceManager.getService("hello"));//調(diào)用自定義的helloservice沦补,不過需要自己asInterface轉(zhuǎn)成自己的接口
}

......

}
至于,java調(diào)用c++的那些JNI就不分析了咪橙。

四夕膀、在c層service中實現(xiàn)java層回調(diào)

還有有時候我們自己寫了一個c層的binder service,然后通過java調(diào)用service中代碼美侦,然后其實又需要在c層中注冊回調(diào)产舞。這個時候可以在c層service的注冊接口中增加binder參數(shù),然后在java中實現(xiàn)aidl文件音榜,再把binder參數(shù)通過service調(diào)用傳入c層service,到時候就可以在c層service中回調(diào)java代碼了捧弃。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赠叼,一起剝皮案震驚了整個濱河市擦囊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘴办,老刑警劉巖瞬场,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涧郊,居然都是意外死亡贯被,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門妆艘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彤灶,“玉大人,你說我怎么就攤上這事批旺』仙拢” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵汽煮,是天一觀的道長搏熄。 經(jīng)常有香客問我,道長暇赤,這世上最難降的妖魔是什么心例? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鞋囊,結(jié)果婚禮上止后,老公的妹妹穿的比我還像新娘。我一直安慰自己失暴,他們只是感情好坯门,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逗扒,像睡著了一般古戴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矩肩,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天现恼,我揣著相機(jī)與錄音,去河邊找鬼黍檩。 笑死叉袍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的刽酱。 我是一名探鬼主播喳逛,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼棵里!你這毒婦竟也來了润文?” 一聲冷哼從身側(cè)響起姐呐,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎典蝌,沒想到半個月后曙砂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡骏掀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年鸠澈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片截驮。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡笑陈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出侧纯,到底是詐尸還是另有隱情新锈,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布眶熬,位于F島的核電站妹笆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏娜氏。R本人自食惡果不足惜拳缠,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贸弥。 院中可真熱鬧窟坐,春花似錦、人聲如沸绵疲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盔憨。三九已至徙菠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郁岩,已是汗流浹背婿奔。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留问慎,地道東北人萍摊。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像如叼,于是被迫代替她去往敵國和親冰木。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容