34

そこで、Android OS 用の Service と Activity を作成しました。

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

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

Android のソースコード全体を簡単に grep したところ、この例外がスローされるケースが 3 つしか見つかりませんでした。これらは、私が接続していない別のサービスにあります。

理論的にはJNIインターフェースを使用してRemoteExceptionsを生成できるため、Cソースも確認しました..何も表示されませんでした。

誰もが次のように処理しているという印象があります。

  try {

    mService.someMethodCall (someArguments);

  } catch (RemoteException e) {

    e.printStackTrace();

  }

これは堅固なコードではありません。コードベースにこのようなものは必要ありません。

それに加えて、私は自分で IPC を介して RemoteException をスローしようとしましたが、得られたのはスタック トレースと、例外がまだサポートされていないことを示すシステム ログ メッセージだけでした。私のアプリケーションは例外を見たことがなく、例外をスローしたサービスは非常に奇妙な状態になりました (途中で動作しています) :-(

質問は次のとおりです。

  • これらの例外はスローされますか?

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

  • それらが存在せず、"throws RemoteException" がデッド コードまたは AIDL コンパイラ内の残り物であるため、それらに対処することを余儀なくされているのでしょうか?

免責事項: ソースコード全体を読んでいません。私は Grep を使用して RemoteException の発生を見つけました。

4

3 に答える 3

64

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

あなたの調査に関する限り、あなたはネイティブソースを調べて正しい方向に進んでいました。見落としているかもしれませんが、これandroid.os.RemoteExceptionは実際には他のBinder関連の例外の単なる基本クラスであり、Binderのネイティブコード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はプロセス間で例外をトンネリングしません。エラーを呼び出し元のアクティビティに戻す必要がある場合は、他の手段を使用する必要があります。

于 2010-07-05T03:56:27.550 に答える
13

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

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

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

  • セキュリティ例外
  • BadParcelableException
  • IllegalArgumentException
  • NullPointerException
  • IllegalStateException
  • NetworkOnMainThreadException
  • サポートされていない操作例外

クライアント側で予期しない例外が発生し、IllegalStateException でサービスがクラッシュするはずがありませんでした。完全な記事: https://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63

于 2017-01-08T12:47:59.597 に答える
2

ここで重要なのは、「例外はまだプロセス間でサポートされていない」ということです。RemoteExceptionは実際にスローされますが、エラーが発生した時点では直接スローされません。aidl呼び出しの処理中にリモートサービスでキャッチされなかったRuntimeExceptionが発生すると、アプリケーションで例外が受信され、明示的に渡されないものは代わりに汎用RemoteExceptionをトリガーします(リモートプロセスで例外が発生したことを通知します) 。

バインダーメソッドの実装ごとにサービスにジェネリック例外キャッチブロックを設定し、その時点でサービスを実行し続けるか強制終了するかを決定し、エラーコードを返すか、例外(おそらく、渡されるものとしてサポートされているもの)をスローすることをお勧めします。 IPC全体)。

于 2011-02-10T19:57:12.360 に答える