service aidl - Android RemoteExceptionsとサービス





proxy intent (4)


これらの例外は実際にスローされ、適切なtry / catchロジックを記述して、サービスで呼び出されたリモートメソッドが完了しなかった状況を処理する必要があります。

あなたの調査まで、あなたはネイティブの情報源を見て正しい道を歩いていました。 あなたが見落としている可能性があるのは、 android.os.RemoteExceptionは、実際には他のBinder関連の例外の基本クラスであり、サブクラスであり、 android.os.DeadObjectExceptionであり、Binderのネイティブコード内にスローされるということです

アクティビティは、要求の実行中に終了する別のプロセスで実行されているサービスを使用する場合、この例外を表示します。 私は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受信し、最終的にシステムがサービスプロセスを再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 OS用のサービスとアクティビティを書いた。

私のサービスはそれ自身のプロセスで実行されているので、私のアクティビティとサービスの間の通信はすべてIPC経由で行われます。 私はこれに標準のAndroid .aidlメカニズムを使用します。

これまでのところすべて正常に動作します。 しかし、AIDLは "throws RemoteException"を使用してすべてのメソッドスタブを生成するので、それらを処理する必要があります。

私はAndroidのソースコード全体で素早くgrepを行い、この例外が投げられる3つのケースしか見つけられませんでした。 これらは、私が接続していない別のサービスにあります。

理論ではRemoteExceptionsはJNIインターフェースを使って生成できるので、Cソースもチェックしました。何も表示されませんでした。

私は誰もが次のようにそれらを扱うという印象を持っています:

  try {

    mService.someMethodCall (someArguments);

  } catch (RemoteException e) {

    e.printStackTrace();

  }

これは実体のコードではなく、私のコードベースではこのようなことはしたくありません。

それ以外にも、IPC経由でRemoteExceptionをスローしようとしましたが、スタックトレースとシステムログメッセージがあり、例外はまだサポートされていません。 私のアプリケーションは例外を見たことがなく、例外を投げたサービスは非常に奇妙な状態になった(途中で動作する):-(

質問は次のとおりです。

  • これらの例外は今までに投げられるのでしょうか?

  • 誰かがRemoteExceptionをキャッチするtry-catchブロックを見たことがありますか?

  • 「throws RemoteException」がデッドコードであるか、AIDLコンパイラの中に残されているため、それらが存在しないこと、そしてそれらを処理することだけを強制されていることでしょうか?

私はソースコード全体を読んでいません。 私はGrepを使ってRemoteExceptionの出現を見つけましたので、空白の使い方が異なるためにいくつか見逃しているかもしれません。




「例外はプロセス間でまだサポートされていません」がここにあります。 RemoteExceptionは実際にスローされますが、直接は発生しません。 EVERY補助呼び出しが処理されている間にリモートサービスでスローされる例外は、アプリケーションによってRemoteExceptionが受信される原因となります。




リモートオブジェクトをホストしているプロセスがもはや使用できなくなると、RemoteExceptionがスローされます。これは通常、プロセスがクラッシュしたことを意味します。

しかし、これまでのコメントや公式のAndroidのドキュメントでは、DeadObjectExceptionが唯一例外としてクライアントに返されているという点では間違っています。 AIDLサービスの実装でスローされたRuntimeExceptionsのいくつかのタイプは、クライアントに戻され、そこで再スローされます。 Binder.execTransact()メソッドを調べると、RuntimeExceptionがキャッチされ、選択された数少ないものがクライアントに渡されることがわかります。

この特別な扱いを受けたRuntimeExceptionsは以下の通りです。 確認するためにParcel.writeExceptionをチェックすることもできます。 このメソッドは、Binderクラスが例外をParcelにマーシャリングしてクライアントに転送し、Parcel.readExceptionの一部として再スローされます。

  • SecurityException
  • BadParcelableException
  • IllegalArgumentException
  • NullPointerException
  • IllegalStateException
  • NetworkOnMainThreadException
  • UnsupportedOperationException

私は偶然この動作に遭遇しました。クライアント側で予期しない例外が発生しました。IllegalStateExceptionが発生したときにサービスがクラッシュすることはありませんでした。 フルライトアップ: https://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63 ://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63




コンテキストは、基本的にリソースへのアクセスとアプリケーションの環境の詳細(アプリケーションコンテキストの場合)またはアクティビティ(アクティビティのコンテキストの場合)またはその他のものを取得することです。

メモリリークを避けるために、コンテキストオブジェクトを必要とするすべてのコンポーネントにアプリケーションコンテキストを使用する必要があります。





android service aidl remoteexception