【面試】【binder】

java編寫binder服務實例

https://www.cnblogs.com/winfu/p/7521372.html

1.編寫AIDL 文件

IHelloService.aidl:

/** {@hide} */
interface IHelloService
{
    void sayhello();
    int sayhello_to(String name);
}

   1.把 IHelloService.aidl 放入 frameworks/base/core/java/android/os

   2.修改 frameworks/base/Android.mk 添加一行

core/java/android/os/IVibratorService.aidl \
+ core/java/android/os/IHelloService.aidl \

   3. 編譯/framework/base

   4.系統自動生成IHelloService.java

public interface IHelloService extends android.os.IInterface
{
    public static abstract class Stub extends android.os.Binder implements IHelloService{
      private static final java.lang.String DESCRIPTOR = "IHelloService";
      
      public Stub()
      {
          this.attachInterface(this, DESCRIPTOR);
      }

      public static IHelloService asInterface(android.os.IBinder obj)
      { ... ...
          return new IHelloService.Stub.Proxy(obj);
      }

      @Override public android.os.IBinder asBinder()

      @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) ... 
      {
          switch (code)
          {
              case INTERFACE_TRANSACTION:
              case TRANSACTION_sayhello:
              case TRANSACTION_sayhello_to:
          }
      }

      private static class Proxy implements IHelloService

      static final int TRANSACTION_sayhello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);

      static final int TRANSACTION_sayhello_to = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  }

   public void sayhello() throws android.os.RemoteException;
    public int sayhello_to(java.lang.String name) throws android.os.RemoteException;
}

IHelloService.java 的結構爲:

1.名字爲IHelloService 的interface:

 2.IHelloService 這個interface 中有一個繼承Binder 的抽象類stub

    IHelloService.aidl 中已經定義好的service 中的幾個函數的虛函數

public interface IHelloService extends android.os.IInterface
{
    public static abstract class Stub extends android.os.Binder implements IHelloService ...
   
    public void sayhello() throws android.os.RemoteException; 

    public int sayhello_to(java.lang.String name) throws android.os.RemoteException;

}

    2.HelloService.java

import android.util.Slog;

public class HelloService extends IHelloService.Stub {
    private static final String TAG = "HelloService";
    ... ...
    public void sayhello() throws android.os.RemoteException {
    ... ...
    }
    
    public int sayhello_to(java.lang.String name) throws android.os.RemoteException {
     ... ...
    }
}

  1. HelloService.java 繼承 IHelloService.Stub  這個內部類;

  2.  HelloService.java 中複寫 之前在IHelloService.aidl 中定義好的函數

 

3.Client端代碼

import android.util.Slog;
import android.os.ServiceManager;
import android.os.IBinder;

public class TestClient {
    public static void main(String args[])
    {

        if (args[0].equals("hello"))
        {
            /* 1. getService */
            IBinder binder = ServiceManager.getService("hello");

            IHelloService svr = IHelloService.Stub.asInterface(binder);

            svr.sayhello();

            int cnt = svr.sayhello_to(args[1]);

        }
    }
}

總結:

1.自己先寫一個IHelloService.aidl ,系統編譯後生成IHelloService.java

2.IHelloService.java是一個接口,其中定義了一個繼承了binder 的抽象的 內部類stub,stub中實現了在IHelloService.aidl中定義方法的實現:將需要傳輸的數據打包爲Parcel 類型,調用super.onTransact傳輸出去。

3.內部類stub中定義了一個實現了IHelloService接口的內部類proxy,proxy中實現了之前定義方法在client端的實現:初始化Parcel,調用mRemote.transact 發送出去。

4.內部類stub 中定義了一個返回  stub中內部類proxy類 的函數asInterface()

5.HelloService 繼承IHelloService.stub

6.client端通過ServiceManager.getService("hello")得到IBinder 對象,傳入到IHelloService.stub.asInterface() 這個靜態方法中獲取IHelloService對象,就可以直接調用函數了。

 

 

 

=========================================================================================

https://www.jianshu.com/p/adaa1a39a274

* Parcel

Parcel是一個容器,主要就是用來進行IPC通信的。

  1.Parcel的獲取 :

Parcel parcle = Parcel.Obtain();

或者

new Parcel();

  2.Parcel 傳入數據

parcel.writeInt(int val); // 傳入Int 型數據

parcel.writeString(String val); //傳入String 型 數據

  3.Parcel 獲取數據


private PrintJobInfo(@NonNull Parcel parcel) {
   .. .. ..
        mLabel = parcel.readString();
        mState = parcel.readInt();
   .. .. ..

 

 

 

1. 如何確定目標binder 實體,喚醒進程/線程

 binder_proc 結構體

struct binder_proc {
    struct hlist_node proc_node;
    struct rb_root threads;
    struct rb_root nodes;
    struct rb_root refs_by_desc;
    struct rb_root refs_by_node;
... ...
    struct list_head todo;
    wait_queue_head_t wait;
... ...
};

nodes : Binder實體在內核中對應的數據結構

binder_node : 記錄進程相關的binder_proc

1.SM.addService(XXXservice) ,將XXXservice 對應的binder_ref 放入SM 的binder_ref

2.SM.getService(XXXservice),查詢SM 的binder_ref,將XXXservice 對應的binder_ref返回給client

3.client將binder_transaction事物插入到XXXservice 的binder_proc待處理隊列

 

2.Binder傳輸數據的大小限制

ProcessState類中,限制每次傳輸大小不超過4M

 

3.系統服務與bindService服務的區別

    1.系統服務:通過SM.addService 添加的service,由ServiceManager 進行管理

    2.BinderService:通過Activity的startService啓動,Service 只是一個封裝,主要是Binder服務實類,不是ServiceManager管理,是AMS 在管理;Activity.binderService添加的service 無法被SM.getService 獲取到;

    3.BinderService是去ActivityManagerService中去查找相應的Service組件,最終會將Service內部Binder的句柄傳給Client。

     

4.Binder請求的同步與異步

 

5.Binder協議中BC_TRANSACTION與BR_TRANSACTION

  BC與BR主要是標誌數據及Transaction流向;

  BC_TRANSACTION從用戶空間流向內核

  BR_TRANSACTION從內核流線用戶空間

 

6.Binder 傳輸數據的封裝

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