ネイティブレイヤのサービスを実装するには、以下のような Binder 関連クラスを使用します。
RefBase …… 各種オブジェクトの生存期間を参照カウンタ
+-- IBinder …… サービスの基底クラス。プロセス間通信の共通インタフェースとしても使われる。
| +-- BpBinder …… クライアント側のプロキシクラス(ServiceManager が自動的にインスタンスを生成する)
| +-- BBinder …… サービスの基底クラス(基本的な実装を提供)
| +-- BnInterface
+-- IInterface …… クライアントに提供するサービスインタフェースの基底クラス
+-- BpRefBase
+-- BpInterface …… クライアントに提供するサービスインタフェースの実装
(a) さえ準備してサービスを立ち上げれば、クライアントは IBinder
インタフェースでサービスにアクセスできるようになります。
(b)、(c) はまともなサービスインタフェースとしてクライアントに公開する場合に必要です。
RefBase
クラスは、すべての Binder 関連クラスの基底クラスで、インスタンスの生存期間をリファレンスカウンタで管理しています。
class IInterface : public virtual RefBase {
public:
sp<IBinder> asBinder();
sp<const IBinder> asBinder() const;
protected:
virtual IBinder* onAsBinder() = 0;
};
IInterface
クラスは、ユーザが定義するサービスのインタフェースのベースクラスになります。
class IEchoService : public IInterface {
public:
virtual int add(int lhs, int rhs);
};
IInterface
クラスには、サービスへアクセスするための IBinder
オブジェクトを取得するための asBinder()
メソッドが実装されています。
この中で使用している onAsBinder()
メソッドは、pure virtual メソッドなので、サービス側で実装する必要があります。
sp<IBinder> IInterface::asBinder() {
return this ? onAsBinder() : NULL;
}
sp<const IBinder> IInterface::asBinder() const {
return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
}
asBinder()
は、スマートポインタである sp
クラスのインスタンスを返すため、IBinder
オブジェクトは参照カウンタを使って自動的に生存期間が制御されます。
class IBinder : public virtual RefBase {
public:
virtual sp<IInterface> queryLocalInterface(const String16& descriptor);
virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
BBinder
クラスは IBinder
を継承しており、BBinder::transact()
の中で abstract method である onTransact()
を呼び出すようになっています。
この onTransact()
を実装するようにすれば OK です。
class BBinder : public IBinder {
public:
virtual const String16& getInterfaceDescriptor() const;
virutal bool isBinderAlive() const;
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t transact(...);
virtual status_t linkToDeath(...);
virtual status_t unlinkToDeath(...);
virtual void attachObject(...);
virtual void* findObject(const void* objectID) const;
virtual void detachObject(const void* objectID);
virtual BBinder* localBinder();
protected:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
...
};
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase {
...
};
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder {
...
};
使い方は、こんな感じ。
class BnMyClass : public BnInterface<IMyClass> {
public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};