Android Remoteexceptionsとサービス
-
01-10-2019 - |
質問
それで、私はAndroid OSのサービスとアクティビティを書きました。
私のサービスは独自のプロセスで実行されているため、私の活動とサービスの間のすべてのコミュニケーションはIPCを介して行われます。これには標準のAndroid .Aidlメカニズムを使用しています。
これまでのところ、すべてが正常に機能しています。ただし、AIDLは「Remoteexceptionをスロー」を使用してすべてのメソッドスタブを生成します。そのため、それらを処理する必要があります。
Androidソースコード全体ですばやくグレップしましたが、この例外がスローされる3つのケースしか見つかりませんでした。これらは私が接続しない別のサービスにあります。
理論的には、JNIインターフェイスを使用してRemoteExceptionsを生成できるため、C-Sourcesもチェックしました。何も表示されません。
私は誰もがこのようにそれらを扱うだけであるという印象を持っています:
try {
mService.someMethodCall (someArguments);
} catch (RemoteException e) {
e.printStackTrace();
}
これは堅実なコードではなく、コードベースにこのようなものが欲しくありません。
それに加えて、私はIPCを介してRemoteexceptionを自分でスローしようとしましたが、私が得たのは、例外がまだサポートされていないことを示すスタックトレースとシステムログメッセージだけでした。私のアプリケーションは例外を見たことがなく、例外を投げたサービスは非常に奇妙な状態になりました(途中で動作します):-(
質問は次のとおりです。
これらの例外は投げかけられますか?
そのようなトライキャッチブロックがRemoteexceptionをキャッチするのを見たことがありますか?
「Remoteexception」が死んだコードまたはAIDLコンパイラ内の残り物であるため、それらが存在しないことであり、私たちは彼らに対処することを余儀なくされているだけでしょうか?
Disclamer:ソースコード全体を読んでいません。 Grepを使用してRemoteexceptionの発生を見つけるため、Whitespaceの使用が異なるため、いくつかを見逃した可能性があります。
解決
これらの例外は実際に投げられます。また、サービスで呼び出したリモートメソッドが完了しなかった状況を処理するために、適切な試行/キャッチロジックを記述する必要があります。
あなたの調査に関しては、あなたはネイティブのソースを調べて正しい軌道に乗っていました。あなたが見落としていたかもしれないのはそれです 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はプロセス間の例外をトンネルしません。エラーを通信する必要がある場合は、呼び出しアクティビティに戻り、他の手段を使用する必要があります。
他のヒント
remoteexceptionがスローされます 処理する リモートオブジェクトをホストすることは使用できなくなります。これは、通常、プロセスがクラッシュしたことを意味します。
ただし、以前のコメント、および公式のAndroidドキュメントは、DeadObjectExceptionがクライアントに投げかけた唯一の例外であることについて間違っています。 AIDLサービスの実装に投げ込まれたいくつかのタイプのruntimeexceptionsは、クライアントに渡され、そこでretまたは再巻き上げられます。 binder.exectransact()メソッドを見てみると、runtimeexceptionをキャッチし、選択した少数をクライアントに渡すことがわかります。
この特別な治療を受けたruntimeexceptionsを以下に示します。 Parcel.writeExceptionを確認して確認することもできます。その方法は、バインダークラスによって使用され、例外を小包にマーシャリングし、それをクライアントに戻し、そこでParcel.ReadExceptionの一部として再洗練されます。
- SecurityException
- BadParcelableException
- IllegalargumentException
- nullpointerexception
- IllegalStateException
- NetworkOnMainThreadException
- UnsportedoperationException
私は偶然この行動に出くわしました、私はクライアント側で予期しない例外を見ていました、そして、私のサービスは、それが違法な標準であるべきであるときにクラッシュしていませんでした。完全な書き込み:https://blog.classycode.com/dealing-with-exceptions-in-904c6d63
ここでは、「例外はプロセス全体でまだサポートされていません」が重要です。 Remoteexceptionは確かに投げられますが、直接ではありません。 毎日 AIDLコールが処理されている間にリモートサービスにスローされた例外は、アプリケーションによってRemoteExceptionが受信されます。