1

リモートサービスMainActivityに IPC 呼び出しを発行する があります。AutoCompleteService

の IPC 関数の実行中AutoCompleteServiceに、サービスは別の IPC コールを に発行しMainActivityます。

MainActivity.java

// Receive IPC call from AutoCompleteService.
private StockInfoObserver.Stub stockInfoObserver = new StockInfoObserver.Stub() {

    @Override
    public void update(StockInfo stockInfo) throws RemoteException {
        // TODO Auto-generated method stub
        Log.i(TAG, android.os.Process.myPid() + " : MainActivity receive ipc call : " + Thread.currentThread().getId());
    }

};

...
...
...

// Issue IPC call to AutoCompleteService.
button.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View arg0) {
        // Test on API.
        try {
            Log.i(TAG, android.os.Process.myPid() + " : MainActivity start issue IPC call to remote service : " + Thread.currentThread().getId());
            // autoCompleteApi.handle will issue IPC call to remote service.
            autoCompleteApi.handle("abc");
            Log.i(TAG, android.os.Process.myPid() + " : MainActivity end issue IPC call to remote service : " + Thread.currentThread().getId());
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

});

AutoCompleteService.java

private AutoCompleteApi.Stub autoCompleteApi = new AutoCompleteApi.Stub() {    
    private List<StockInfoObserver> stockInfoObservers = new ArrayList<StockInfoObserver>();

    @Override
    public void handle(String string) {
        Log.i(TAG, android.os.Process.myPid() + " : AutoCompleteService start receive ipc call : " + Thread.currentThread().getId());
        try {
            for (StockInfoObserver stockInfoObserver : stockInfoObservers) {    
                Log.i(TAG, android.os.Process.myPid() + " : AutoCompleteService start IPC call to MainActivity : " + Thread.currentThread().getId());
                // stockInfoObserver.update will issue IPC call back to MainActivity
                stockInfoObserver.update(null);
                Log.i(TAG, android.os.Process.myPid() + " : AutoCompleteService end IPC call to MainActivity : " + Thread.currentThread().getId());
            }
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Log.i(TAG, android.os.Process.myPid() + " : AutoCompleteService end receive ipc call : " + Thread.currentThread().getId());
    }

    @Override
    public void attachStockInfoObserver(StockInfoObserver stockInfoObserver)
            throws RemoteException {
        if (stockInfoObservers.contains(stockInfoObserver) == false) {
            stockInfoObservers.add(stockInfoObserver);
        }
    }
};

私の最初の予想は、デッドロックが発生することです。これは私の観察によるものです。IPC 呼び出しを発行する場合、IPC レシーバーが IPC 関数の実行を終了した後、発行者は IPC 呼び出しからのみ戻ります。

  1. MainActivityAutoCompleteServicethroughに IPC 呼び出しを発行しautoCompleteApi.handleます。
  2. MainActivityAutoCompleteService実行が完了するまで待機します。
  3. AutoCompleteServiceMainActivitythroughに IPC 呼び出しを発行しstockInfoObserver.updateます。
  4. AutoCompleteServiceMainActivity実行が完了するまで待機します。
  5. ただし、のスレッドはまだ待機中です。関数MainActivityを実行するスレッドはありません。update
  6. 両方のプロセスが互いに待機し続けます。

ただし、上記は発生しません。これは私が取得しているログです。すべてが完璧に機能します。

// Log in MainActivity TAG
3930 : MainActivity start issue IPC call to remote service : 1
3930 : MainActivity receive ipc call : 1
3930 : MainActivity end issue IPC call to remote service : 1

// Log in AutoCompleteService TAG
3961 : AutoCompleteService start receive ipc call : 494
3961 : AutoCompleteService start IPC call to MainActivity : 494
3961 : AutoCompleteService end IPC call to MainActivity : 494
3961 : AutoCompleteService end receive ipc call : 494

しかし、私はよくわかりません。MainActivity スレッド (ID 1 の) が関数呼び出し ( autoCompleteApi.handle) から戻っていない場合、別の関数 ( ) を実行するために「ジャンプ」するにはどうすればよいupdate(StockInfo stockInfo)でしょうか?

MainActivity receive ipc 呼び出しが別のスレッドによって出力されることを期待しています。ID 1 のスレッドではありません。そうでない場合は、デッドロックが発生するはずです。

試してみたい場合は、https ://www.dropbox.com/s/8hd7v5acjd213l1/jstock-android2.zip から完全なソース コードをダウンロードしてください。

4

1 に答える 1

2

興味深い質問です。着信 IPC 呼び出しが別のスレッドで処理されると最初に考えた (通常は着信 IPC 呼び出しで発生する) が、この特定のシナリオでは間違っていることが判明しました。

着信呼び出しが到着したときに実行スタックを見ると、次のように表示されます (最新のスタック フレームが上部に表示されます)。

MainActivity$1.update
MainActivity$1.onTransact
MainActivity$1.execTransact         <- this gets called by the incoming IPC call
BinderProxy.transact                <- this is where the outgoing IPC call is made
AutoCompleteApi$Stub$Proxy.handle
MainActivity$3.onClick
...

したがって、すべてが同じスレッドで行われています。着信コールは、発信コールのサブルーチン コールのように見えます。これを可能にする魔法は、ネイティブ コード (またはおそらくカーネル) で発生しています。Thorsten Schreiberによる興味深い論文で、Binder メカニズムの内部構造の一部が説明されています。残念ながら、この例で発生するのと同じプロセスへのバック コールについては説明しません。

このブログ投稿には、この機能に関する小さなコメントがあります。

元のスレッドも、応答を待っている間に BR_TRANSACTION コマンドを受信する場合があることに注意してください。これは、受信スレッドが元のプロセスに戻ってオブジェクトを呼び出すプロセス全体の再帰を表します。再帰が発生したときにトランザクションを正しいスレッドにディスパッチできるように、すべてのアクティブなトランザクションを追跡するのはドライバーの役割です。

おそらく、Android Binder 実装のルートであるOpenBinder Web サイトには、さらに多くの情報があります。

于 2013-01-11T16:06:00.273 に答える