Android Remoteexceptions and Services
-
01-10-2019 - |
题
因此,我为Android OS写了一项服务和活动。
我的服务在其自己的过程中运行,因此我的活动与服务之间的所有通信都是通过IPC进行的。我为此使用标准的Android .AIDL机制。
到目前为止,一切都很好。但是,AIDL使用“ Remoteexception”生成所有方法存根,因此我必须处理它们。
我在整个Android源代码上进行了快速的GREP,只发现了三种例外情况。这些是我不连接的不同服务。
我也检查了C源,因为从理论上讲,可以使用JNI界面生成Remoteexceptions ..什么都没出现。
我的印象是每个人都这样处理:
try {
mService.someMethodCall (someArguments);
} catch (RemoteException e) {
e.printStackTrace();
}
这不是可靠的代码,我不希望在我的代码库中这样的东西。
除此之外:我试图通过IPC自己进行remoteexception,而我所得到的只是堆栈跟踪和系统日志消息,告诉我尚未支持例外。我的应用程序从未看到过例外,而抛出例外的服务最终处于一个非常奇怪的状态(中途工作):-(
问题是:
这些例外是否被抛弃了?
有没有人见过这样的尝试捕捉障碍,抓住了remoteexception?
难道他们不存在,而我们只是被迫与他们打交道,因为“ thr thr thr thr thr the the dead Code”或AIDL编译器内部的剩下的代码?
Disclamer:我还没有阅读整个源代码。我使用GREP找到了Remoteexception的出现,因此由于使用不同的使用情况,我可能会错过一些。
解决方案
这些例外确实确实被抛弃了,您应该编写适当的尝试/捕获逻辑来处理您在服务上调用的远程方法未完成的情况。
就您的调查而言,您正在正确的轨道上浏览本地资源。您可能忽略了 android.os.RemoteException
实际上只是用于其他粘合剂相关例外的基类,它是一个子类, android.os.DeadObjectException
, ,被扔在 粘合剂的本地代码.
如果它利用在执行请求中间死亡的另一个过程中运行的服务,则活动将看到此异常。我能够通过对以下较小的更改来证明自己 Marko Gargenta的AIDLDEMO示例.
首先,通过更新androidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.marakana" android:versionCode="1" android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:theme="@android:style/Theme.Light">
<activity android:name=".AIDLDemo" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--ADD THE android:process TAG TO THE SERVICE-->
<service android:name=".AdditionService" android:process=":process2"/>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
然后修改 add
过早退出的方法:
@Override
public IBinder onBind(Intent intent) {
return new IAdditionService.Stub() {
/**
* Implementation of the add() method
*/
public int add(int value1, int value2) throws RemoteException {
Log.d(TAG, String.format("AdditionService.add(%d, %d)", value1,
value2));
System.exit(-1); // KILL THE PROCESS BEFORE IT CAN RESPOND
return value1 + value2;
}
};
}
在logcat中,您会看到服务过程死亡,活动接收了 DeadObjectException
, ,最终将系统重新启动服务过程。
D/AdditionService( 1379): AdditionService.add(1, 1)
I/AndroidRuntime( 1379): AndroidRuntime onExit calling exit(-1)
D/Zygote ( 32): Process 1379 exited cleanly (255)
I/ActivityManager( 58): Process com.marakana:process2 (pid 1379) has died.
W/ActivityManager( 58): Scheduling restart of crashed service com.marakana/.AdditionService in 5000ms
D/AIDLDemo( 1372): onClick failed with: android.os.DeadObjectException
W/System.err( 1372): android.os.DeadObjectException
W/System.err( 1372): at android.os.BinderProxy.transact(Native Method)
W/System.err( 1372): at com.marakana.IAdditionService$Stub$Proxy.add(IAdditionService.java:95)
W/System.err( 1372): at com.marakana.AIDLDemo$1.onClick(AIDLDemo.java:81)
W/System.err( 1372): at android.view.View.performClick(View.java:2408)
W/System.err( 1372): at android.view.View$PerformClick.run(View.java:8816)
W/System.err( 1372): at android.os.Handler.handleCallback(Handler.java:587)
W/System.err( 1372): at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err( 1372): at android.os.Looper.loop(Looper.java:123)
W/System.err( 1372): at android.app.ActivityThread.main(ActivityThread.java:4627)
W/System.err( 1372): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err( 1372): at java.lang.reflect.Method.invoke(Method.java:521)
W/System.err( 1372): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
W/System.err( 1372): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
W/System.err( 1372): at dalvik.system.NativeStart.main(Native Method)
D/AIDLDemo( 1372): onServiceDisconnected() disconnected
I/ActivityManager( 58): Start proc com.marakana:process2 for service com.marakana/.AdditionService: pid=1399 uid=10037 gids={1015}
D/AdditionService( 1399): onCreate()
D/AIDLDemo( 1372): onServiceConnected() connected
我可以想象,如果您的服务在与您的活动相同的过程中运行,您可能永远不会看到此例外,但是如果是这种情况,您可能不会对AIDL感到困扰。
此外,正如您发现的那样,Android不会在过程之间隧道异常。如果您需要将错误传达回通话活动,则需要使用其他方式。
其他提示
如果是 过程 托管远程对象不再可用,这通常意味着该过程崩溃了。
但是,以前的评论以及官方的Android文档对DeadoBjectException是唯一被送回客户的例外是错误的。在您的AIDL服务实施中抛出的某些类型的Runtime Exceptions将转回客户端并在此转移。如果您查看binder.exectransact()方法,您会发现它会捕获RuntimeException并将选择的几个回到客户端。
下面列出了接受此特殊待遇的Runtime Exceptions。您也可以检查Parcel.WriteException以验证。活页夹类使用该方法将异常填充到包裹中,然后将其转移回客户,在该客户将其作为Parcel.ReadException的一部分重新启用。
- SecurityException
- BadParcelableException
- 非法征收exception
- 空指针异常
- 非法施加感受
- NetworkOnMainThreadException
- 无支撑的exception
我偶然地偶然发现了这种行为,我在客户端看到了出乎意料的例外,而当它应该在illegalstateexception上时,我的服务并没有崩溃。完整写入:https://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63
“尚未跨流程支持”是这里的关键。 remoteexception的确被抛出,但不是直接的。 每一个 在处理AIDL呼叫时,在远程服务中抛出的例外将导致您的申请收到Remoteexception。