Android RemoteExceptions和服务

所以我已经为Android OS编写了一个Service和一个Activity。

我的服务运行在它自己的过程中,所以我的活动和服务之间的所有通信都是通过IPC进行的。 我使用标准的Android .aidl机制。

到目前为止一切正常。 但是,AIDL使用“throws RemoteException”生成所有的方法存根,所以我必须处理它们。

我对整个Android源代码做了一个快速的grep,只发现了三个这种例外的情况。 这些是在不同的服务,我不连接。

我也检查了C源,因为理论上可以使用JNI接口生成RemoteExceptions。没有任何东西出现。

我有这样的印象,每个人都只是这样处理他们:

try { mService.someMethodCall (someArguments); } catch (RemoteException e) { e.printStackTrace(); } 

这不是固定的代码,我不想在我的代码库中这样的东西。

除此之外:我试图通过IPC自己抛出一个RemoteException,我得到的只是一个堆栈跟踪和一个系统日志消息,告诉我exception现在还不被支持。 我的应用程序从来没有看到exception,并抛出exception的服务结束了一个非常奇怪的状态(中途工作):-(

问题是:

  • 这些exception是否被抛出?

  • 有没有人见过这样的try-catch块捕获RemoteException?

  • 难道是他们不存在,我们只是被迫处理他们,因为“抛出RemoteException”是死代码或遗留在AIDL编译器内?

Disclamer:我没有阅读完整的源代码。 我使用Grep来查找RemoteException的出现,所以我可能由于不同的空白使用而错过了一些。

Solutions Collecting From Web of "Android RemoteExceptions和服务"

这些exception确实会被抛出,您应该编写适当的try / catch逻辑来处理您在服务上调用的远程方法没有完成的情况。

就你的调查而言,你是在正确的轨道上浏览本地资源。 你可能会忽略的是, android.os.RemoteException实际上只是其他Binder相关exception的基类,它是一个在Binder的本地代码中抛出的子类android.os.DeadObjectException

如果活动使用在执行请求过程中死于另一个进程的服务,则活动将看到此exception。 我能够通过对Marko Gargenta的AIDLDemo示例进行如下小修改来certificate这一点。

首先,通过更新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 

我想象一下,如果你的服务和你的活动在同一个进程中运行,你可能永远不会看到这个exception,但是如果那样的话你可能不会用AIDL来打扰。

另外,正如您发现的那样,Android不会在进程之间传递exception。 如果您需要将错误传回给调用活动,那么您需要使用其他方法。

如果托pipe远程对象的进程不再可用,则抛出RemoteException,这通常意味着进程崩溃。

然而,以前的评论,以及正式的Android文档是错误的关于DeadObjectException是唯一的exception抛出回到客户端。 在您的AIDL服务实现中抛出的一些types的RuntimeException将被传回给客户端并在那里重新抛出。 如果查看Binder.execTransact()方法,您将看到它捕获了RuntimeException,并将一些select返回给客户端。

下面列出了接收此特殊处理的RuntimeException。 您也可以检查Parcel.writeException来validation。 Binder类使用该方法将exception封送到Parcel中,并将其传回给客户端,在那里它将作为Parcel.readException的一部分重新抛出。

  • 抛出:SecurityException
  • BadParcelableException
  • 抛出:IllegalArgumentException
  • 空指针exception
  • IllegalStateExceptionexception
  • NetworkOnMainThreadException
  • UnsupportedOperationExceptionexception

我无意中偶然发现了这种行为,我在客户端看到意外的exception,而且我的服务在IllegalStateException时应该没有崩溃。 全文: https ://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63

在这个过程中,“例外还不支持跨进程”。 RemoteException的确被抛出,但不是直接的。 在正在处理aidl调用的过程中,在您的远程服务中抛出的每个exception都将导致应用程序接收到RemoteException。