Pregunta

Así que he escrito un servicio y una actividad para el sistema operativo Android.

Mi servicio se ejecuta en su propio proceso, de modo que toda la comunicación entre mis actividades y el servicio pasa a través del IPC. Yo uso el mecanismo .aidl estándar de Android para esto.

Hasta ahora todo funciona bien. Sin embargo, el AIDL genera todos los apéndices de método usando "tiros RemoteException" por lo que tengo para manejarlos.

Hice un grep rápido en todo el código fuente de Android y sólo encontré tres casos en los que esta excepción se meten. Éstos están en un servicio diferente que no me conecto con.

he comprobado las fuentes de C, así porque en teoría RemoteExceptions se pueden generar utilizando la interfaz JNI .. Nada se presentó.

Tengo la impresión de que todo el mundo sólo se ocupa de ellos de esta manera:

  try {

    mService.someMethodCall (someArguments);

  } catch (RemoteException e) {

    e.printStackTrace();

  }

Esto no es un código sólido, y no quiero que algo como esto en mi código base.

Además de eso: Traté de lanzar una RemoteException a través de IPC mí mismo y todo lo que tengo una pila de traza y un mensaje de registro del sistema que me dice que las excepciones no son compatibles todavía. Mi solicitud nunca vio la excepción y los servicios que lanzaron la excepción terminó en un estado muy extraño (a medio camino de trabajo): - (

Las preguntas son:

  • ¿Estas excepciones cada vez son arrojados?

  • ¿Alguien ha visto un bloque try-catch como la captura de un RemoteException?

  • ¿Podría ser que no existen y que sólo están obligados a tratar con ellos debido a que el "tiros RemoteException" es código muerto o un sobrante en el interior del compilador AIDL?

Renuncia: No he leído todo el código fuente. Solía ??Grep para encontrar las ocurrencias de RemoteException, por lo que puede haber perdido algunos debido a diverso uso de espacio en blanco.

¿Fue útil?

Solución

Estas excepciones en efecto, son arrojados y se debe escribir la lógica try / catch apropiado para manejar la situación en la que un método remoto se invocó en un servicio no se ha completado.

En cuanto a su investigación, usted estaba en el camino correcto mirando a través de las fuentes nativas. Lo que puede haber pasado por alto es que android.os.RemoteException es una sólo una clase base realidad para otras excepciones relacionadas Binder y que es una subclase, android.os.DeadObjectException , que es arrojado dentro de la Carpeta de código nativo .

Una actividad verá esta excepción si se hace uso de un servicio que se ejecuta en otro proceso que muere en el medio de la realización de una solicitud. Yo era capaz de demostrar esto a mí mismo haciendo las siguientes menores cambios en ejemplo AIDLDemo de Marko Gargenta .

En primer lugar, asegúrese de que se ejecuta el servicio en su propio proceso de actualización del 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> 

A continuación, modificar el método add para salir prematuramente:

@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;
        }

    };
}

En LogCat ves el troquel proceso de servicio, la actividad recibir un DeadObjectException, y en última instancia el sistema de reaparición del proceso de servicio.

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

Me imagino si el servicio se ejecuta en el mismo proceso que su actividad puede que nunca vea esta excepción, pero, de nuevo, si ese fuera el caso, es probable que no estar molestando con AIDL.

Además, como has descubierto, Android no excepciones túnel entre procesos. Si necesita comunicar un error volver a una actividad llamando a continuación, es necesario utilizar otros medios.

Otros consejos

RemoteException se lanza si el proceso alojamiento del objeto remoto ya no está disponible, lo que generalmente significa que el proceso se estrelló.

Sin embargo, el comentario anterior, así como la documentación oficial de Android es equivocada sobre DeadObjectException siendo la única excepción vez lanzado de vuelta al cliente. Algunos tipos de RuntimeExceptions lanzadas en su implementación del servicio AIDL serán pasados ??al cliente y relanza allí. Si se echa un vistazo en el método Binder.execTransact (), verá que atrapa RuntimeException y pasa a un grupo selecto de vuelta al cliente.

Los RuntimeExceptions que reciben este tratamiento especial se enumeran a continuación. También puede comprobar Parcel.writeException para verificar. Ese método es utilizado por la clase de vínculo para reunir la excepción en un paquete y transferirlo de nuevo al cliente, donde se relanza como parte de Parcel.readException.

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

Me encontré con este comportamiento por accidente, que estaba viendo excepciones inesperadas en el lado del cliente, y mi servicio no estaba fallando cuando debería hacerlo en una IllegalStateException. writeup completo: https://blog.classycode.com/dealing-with-exceptions-in -aidl-9ba904c6d63

Las "excepciones todavía no están soportados a través de procesos" es la clave aquí. de hecho RemoteException se tiran, pero no directamente. cada excepción lanzada en su servicio a distancia mientras una llamada está siendo manejado AIDL dará lugar a una RemoteException siendo recibido por su aplicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top