我有一个MainActivity
,它会向远程AutoCompleteService
服务发出IPC调用。
在执行AutoCompleteService
的IPC功能期间,该服务将向MainActivity
发出另一个IPC回叫。
// 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();
}
}
});
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调用返回。
MainActivity
通过AutoCompleteService
向autoCompleteApi.handle
发出IPC号召。MainActivity
现在将等到AutoCompleteService
完成执行。AutoCompleteService
通过MainActivity
向stockInfoObserver.update
发出IPC号召。AutoCompleteService
现在将等到MainActivity
完成执行。MainActivity
的线程仍在等待,没有线程可以执行update
功能。但是,上述情况不会发生。这是我得到的日志。一切都是完美无瑕的。
// 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接收ipc调用。不是具有Id 1的线程。如果不是,则应该发生死锁。
如果您有兴趣尝试外出,请在此处下载完整的源代码:https://www.dropbox.com/s/8hd7v5acjd213l1/jstock-android2.zip
答案 0 :(得分: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
...
所有这一切都发生在同一个线程中。来电看起来像是拨出电话的子程序调用。实现这一目标的神奇之处在于本机代码(或者可能在内核中)。有一个interesting paper by Thorsten Schreiber解释了Binder机制的一些内部结构。不幸的是,它不会讨论与此示例中发生的相同过程的反向调用。
关于this blog post中的功能有一点点评论:
请注意,原始线程在等待回复时也可能会收到BR_TRANSACTION命令。这表示接收线程在原始进程中调用对象的进程之间的递归。驱动程序负责跟踪所有活动事务,因此它可以在递归发生时将事务调度到正确的线程。
也许在OpenBinder website中找到更多内容,这是Android Binder实施的根源。