Domanda

Così ho scritto un Servizio e un'attività per il sistema operativo Android.

Il mio servizio è in esecuzione in proprio processo di esso è, quindi tutte le comunicazioni tra le mie attività e il servizio avviene tramite IPC. Io uso il meccanismo .aidl Android standard per questo.

Finora tutto funziona bene. Tuttavia, l'AIDL genera tutti stub metodo che utilizza "getta RemoteException" quindi devo gestirli.

Ho fatto un rapido grep su tutto il codice sorgente di Android e solo trovato tre casi in cui tale eccezione è mai gettato. Questi sono in un servizio diverso che non mi connetto con.

Ho controllato il codice sorgente C e perché in teoria RemoteException possono essere generati utilizzando l'interfaccia JNI .. Niente alzato.

Ho l'impressione che tutti appena li gestisce in questo modo:

  try {

    mService.someMethodCall (someArguments);

  } catch (RemoteException e) {

    e.printStackTrace();

  }

Questo non è il codice solido, e non voglio che qualcosa di simile nel mio codice-base.

Oltre a questo: ho cercato di lanciare una RemoteException tramite IPC me stesso e tutto quello che ho ottenuto è stato uno stack-traccia e un messaggio di log di sistema che mi dice che le eccezioni non sono ancora supportati. La mia applicazione non ha mai visto l'eccezione e dei servizi che ha generato l'eccezione finito in uno stato molto strano (a metà strada di lavoro): - (

Le domande sono:

  • Fare queste eccezioni mai gettati?

  • Qualcuno ha mai visto un tale blocco try-catch cattura di un RemoteException?

  • E 'possibile che non esistono e che ci sono solo costretti a trattare con loro perché il "tiri RemoteException" è il codice morto o una parte di sinistra-over all'interno del compilatore AIDL?

Disclamer: non ho letto l'intero codice sorgente. Ho usato Grep per trovare le occorrenze di RemoteException, quindi forse ho perso un po 'a causa di diverso utilizzo spazi bianchi.

È stato utile?

Soluzione

Queste eccezioni effettivamente vengono gettati e si dovrebbe scrivere la logica try / catch appropriato per gestire la situazione in cui un metodo remoto è stato richiamato su un servizio non è stato completato.

Per quanto riguarda l'indagine, eri sulla strada giusta guardando attraverso le fonti indigene. Che cosa si può avere trascurato è che android.os.RemoteException è una solo una classe di base in realtà per le altre eccezioni legate Binder e che si tratta di una sottoclasse, android.os.DeadObjectException , che è gettato all'interno della codice nativo di Binder .

Un'attività vedrà questa eccezione se si fa uso di un servizio in esecuzione in un altro processo che muore nel mezzo di esecuzione di una richiesta. Sono stato in grado di dimostrare a me stesso apportando le seguenti modifiche minori a esempio AIDLDemo di Marko Gargenta .

Per prima cosa, assicurarsi che l'esecuzione del servizio nel proprio processo aggiornando l'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> 

Quindi modificare il metodo add per uscire 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;
        }

    };
}

In Logcat si vede il dado processo di servizio, l'attività di ricevere un DeadObjectException, e, infine, il sistema di respawn il processo di servizio.

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

immagino se il servizio è stato eseguito nello stesso processo, come la vostra attività si potrebbe mai vedere questa eccezione, ma poi di nuovo, se così fosse probabilmente non sarebbe avere a che fare con AIDL.

Inoltre, come avete scoperto, Android non eccezioni tunnel tra i processi. Se avete bisogno di comunicare un errore ritornare a un'attività chiama allora avete bisogno di usare altri mezzi.

Altri suggerimenti

RemoteException viene emessa se il processo che ospita l'oggetto remoto non è più disponibile, che di solito significa che il processo è bloccato.

Tuttavia, il commento precedente, e anche la documentazione ufficiale Android è sbagliato DeadObjectException essere l'unica eccezione mai gettato al client. Alcuni tipi di RuntimeExceptions gettati nella vostra implementazione del servizio AIDL verranno passati al client e rilanciati lì. Se si dà un'occhiata al metodo Binder.execTransact (), vedrete che cattura RuntimeException e passa pochi eletti al client.

I RuntimeExceptions che ricevono questo trattamento speciale sono elencate di seguito. È inoltre possibile controllare Parcel.writeException per verificare. Questo metodo viene utilizzato dalla classe Binder al maresciallo l'eccezione in un pacco e trasferirlo al client, dove verrà rilanciati come parte di Parcel.readException.

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

sono inciampato in questo comportamento per caso, stavo vedendo eccezioni impreviste sul lato client, e il mio servizio non è stato blocca quando si deve su un IllegalStateException. writeup completa: https://blog.classycode.com/dealing-with-exceptions-in -aidl-9ba904c6d63

I "Eccezioni non sono ancora supportati attraverso i processi" è la chiave qui. RemoteException di sono infatti gettati, ma non direttamente. ogni Eccezione gettata nel vostro servizio remoto durante una chiamata AIDL viene gestita si tradurrà in una RemoteException vengono ricevuti dalla vostra applicazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top