Android RemoteExceptions и сервисы

Таким образом, я записал Обслуживание и Действие для ОС Android.

Моя услуга работает в своем собственном процессе, таким образом, вся коммуникация между моими Операциями и Обслуживанием происходит через IPC. Я использую стандартный Android .aidl механизм для этого.

До сих пор все хорошо работает. Однако AIDL генерирует все тупики метода с помощью "броски RemoteException", таким образом, я должен обработать их.

Я сделал быстрый grep на всем исходном коде Android и только нашел три случая, где это исключение когда-либо выдается. Они находятся в другом сервисе, с которым я не соединяюсь.

Я проверил C-источники также, потому что в теории RemoteExceptions может быть сгенерирован с помощью интерфейса JNI.. Ничто не поднялось.

У меня есть впечатление, что все просто обрабатывают их как это:

  try {

    mService.someMethodCall (someArguments);

  } catch (RemoteException e) {

    e.printStackTrace();

  }

Это не основательный код, и я не хочу что-то вроде этого в своей кодовой базе.

Помимо этого: Я пытался бросить RemoteException через IPC сам и все, что я получил, было отслеживание стека и системное сообщение журнала, которое говорит мне, что исключения еще не поддерживаются. Мое приложение никогда не видело исключение и услуги, которые выдали исключение, законченное в очень странном состоянии (на полпути работающий) :-(

Вопросы:

  • Эти исключения когда-либо становятся брошенными?

  • Кто-либо когда-либо видел, что такой блок try-catch ловит RemoteException?

  • Могло случиться так, что они не существуют и что мы просто вынуждены иметь дело с ними, потому что "броски RemoteException" являются мертвым кодом или остатком в компиляторе AIDL?

Disclamer: Я не прочитал весь исходный код. Я использовал Grep для нахождения случаев RemoteException, таким образом, я, возможно, скучал по некоторым из-за другого пробельного использования.

26
задан Nils Pipenbrinck 1 July 2010 в 09:07
поделиться

1 ответ

Эти исключения действительно возникают, и вам следует написать соответствующую логику try / catch для обработки ситуации, когда удаленный метод, который вы вызвали для службы, не завершился.

Что касается вашего расследования, вы были на правильном пути, просматривая родные источники. Возможно, вы упустили из виду, что android.os.RemoteException на самом деле является просто базовым классом для других исключений, связанных с Binder, и что это подкласс android.os.DeadObjectException , который выбрасывается внутри собственного кода Binder .

Действие увидит это исключение, если оно использует службу, запущенную в другом процессе, который умирает в середине выполнения запроса.Я смог доказать это самому себе, внеся следующие незначительные изменения в пример 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 не туннелирует исключения между процессами. Если вам нужно сообщить об ошибке вызывающему действию, вам нужно использовать другие средства.

54
ответ дан 28 November 2019 в 06:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: