一つの Service を複数の AIDL から利用する

AIDL を使って Service を内部利用したり一般公開したい時ってあると思います。
Read/Write 出来る Service だけれど、一般公開するにあたっては ReadOnly な AIDL を公開したい。
けれど、一つの Service で実現されているにも関わらず、権限や利用方法によっていくつも AIDL と Service を増やすのは、コードの肥大化、また少ないメモリで動作する Android 端末上で多くの Service を作ることでメモリ不足の原因ともなります。

Service の onBinder() 内で、何故 Binder を返しているか、不思議に思ったことはありませんか?
実はあの部分で Service のインタフェースを切り替えることが出来るのです。

まず、それぞれの AIDL を作ります。 (今回は面倒なので ReadOnly と WriteOnly だけ作ります。)

  • IReadTestService.aidl
interface IReadTestService {
    int getNum();
}
  • IWriteTestService.aidl
interface IWriteTestService {
    void setNum(int num);
}

AIDL を作ったら、 Service の onBind() 内で振り分けをすることが出来ます。

@Override
public IBinder onBind(Intent intent) {
    if (IReadTestService.class.getName().equals(intent.getAction())) {
        return mReadTestServiceIf;
    }
    else if (IWriteTestService.class.getName.equals(intent.getAction())) {
        return mWriteTestServiceIf;
    }

    return null
}

private static int mNum = 0;

/** 読み込み用 AIDL の実装 */
private IReadTestService.Stub mReadTestService = new IReadTestService.Stub() {
    @Override
    public int getNum() {
       return mNum;
    }
};

/** 書き込み用 AIDL の実装 */
private IWriteTestService.Stub mWriteTestService = new IWriteTestService.Stub() {
    @Override
    public void setNum(int num) {
       mNum = num;
    }
};

このように返却する binder を別々にすれば、一つの Service を複数の AIDL から利用することが出来るのです。

自分自身からのサービス呼び出しや信頼出来るアプリ(自分の作ったアプリなど)からは読み書き出来る AIDL を利用し、一般公開には Read Only として AIDL を公開するということも出来るようになります。

また、 intent.getAction() == null な場合は、ローカルからの (AIDL 経由でない) Service 呼び出しですので、さらにそこで振り分けることも出来ます。

追記

実際メモリ使用量が減ってるかは知らない。