Eccezioni di cattura generate da codice nativo in esecuzione su Android



Answers

EDIT: vedi anche questa risposta più elegante .

Il meccanismo sottostante è basato su una macro del preprocessore C che ho implementato con successo all'interno di un livello JNI .

La precedente macro CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION converte le eccezioni C ++ in eccezioni Java.

Sostituisci mypackage::Exception dalla tua eccezione C ++. Se non hai definito il corrispondente my.group.mypackage.Exception in Java, sostituisci "my/group/mypackage/Exception" con "java/lang/RuntimeException" .

#define CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION              \
                                                                  \
  catch (const mypackage::Exception& e)                           \
  {                                                               \
    jclass jc = env->FindClass("my/group/mypackage/Exception");   \
    if(jc) env->ThrowNew (jc, e.what());                          \
    /* if null => NoClassDefFoundError already thrown */          \
  }                                                               \
  catch (const std::bad_alloc& e)                                 \
  {                                                               \
    /* OOM exception */                                           \
    jclass jc = env->FindClass("java/lang/OutOfMemoryError");     \
    if(jc) env->ThrowNew (jc, e.what());                          \
  }                                                               \
  catch (const std::ios_base::failure& e)                         \
  {                                                               \
    /* IO exception */                                            \
    jclass jc = env->FindClass("java/io/IOException");            \
    if(jc) env->ThrowNew (jc, e.what());                          \
  }                                                               \
  catch (const std::exception& e)                                 \
  {                                                               \
    /* unknown exception */                                       \
    jclass jc = env->FindClass("java/lang/Error");                \
    if(jc) env->ThrowNew (jc, e.what());                          \
  }                                                               \
  catch (...)                                                     \
  {                                                               \
    /* Oops I missed identifying this exception! */               \
    jclass jc = env->FindClass("java/lang/Error");                \
    if(jc) env->ThrowNew (jc, "unidentified exception");          \
  }

Il file Java_my_group_mypackage_example.cpp utilizza la macro precedente:

JNIEXPORT jlong JNICALL Java_my_group_mypackage_example_function1
  (JNIEnv *env, jobject object, jlong value)
{
  try 
  {
    /* ... my processing ... */
    return jlong(result);
  }
  CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
  return 0;
}

JNIEXPORT jstring JNICALL Java_my_group_mypackage_example_function2
  (JNIEnv *env, jobject object, jlong value)
{
  try 
  {
    /* ... my processing ... */
    jstring jstr = env->NewStringUTF("my result");
    return  jstr;
  }
  CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
  return 0;
}

JNIEXPORT void JNICALL Java_my_group_mypackage_example_function3
  (JNIEnv *env, jobject object, jlong value)
{
  try 
  {
    /* ... my processing ... */
  }
  CATCH_CPP_EXCEPTION_AND_THROW_JAVA_EXCEPTION
}

Solo per informazioni o curiosità, fornisco sotto il corrispondente codice Java (file example.java ). Si noti che " my-DLL-name " è il codice C / C ++ sopra compilato come una DLL (" my-DLL-name " senza l'estensione " .dll "). Funziona perfettamente anche usando la libreria condivisa Linux / Unix *.so .

package my.group.mypackage;

public class Example {
  static {
    System.loadLibrary("my-DLL-name");
  }

  public Example() {
    /* ... */
  }

  private native int    function1(int); //declare DLL functions
  private native String function2(int); //using the keyword
  private native void   function3(int); //'native'

  public void dosomething(int value) {
    int result = function1(value);  
    String str = function2(value);  //call your DLL functions
    function3(value);               //as any other java function
  }
}

Innanzitutto, generate example.class da example.java (utilizzando javac o il proprio IDE preferito o Maven ...). In secondo luogo, generare il file di intestazione C / C ++ Java_my_group_mypackage_example.h da example.class utilizzando javah .

Question

Il progetto al quale sto lavorando attualmente richiede di codificare la parte Android di un'implementazione di un programma multipiattaforma.

Un insieme di funzionalità di base viene creato e incluso nella mia app tramite android-ndk . Ho scoperto che ogni eccezione / crash che si verifica nel codice nativo viene segnalata solo di tanto in tanto. Quando si verifica un errore, ottengo uno dei seguenti comportamenti:

  • Un dump di memoria / stacktrace si verifica e viene scritto nel file di registro. Il programma scompare (sul dispositivo non viene fornita alcuna indicazione sul motivo per cui improvvisamente l'app non è più lì).
  • Non viene fornito stacktrace / dump o altra indicazione che il codice nativo si sia arrestato in modo anomalo. Il programma scompare.
  • Il codice java si blocca con una NullPointerException (di solito nello stesso posto per eccezione di codice nativo che è un enorme dolore). Di solito mi fa passare un po 'di tempo cercando di eseguire il debug perché il codice Java ha generato un errore solo per scoprire che il codice Java va bene e l'errore del codice nativo è stato interamente mascherato.

Non riesco a trovare alcun modo per "isolare" il mio codice dagli errori che si verificano nel codice nativo. Le dichiarazioni try / catch sono clamorosamente ignorate. A parte il momento in cui il mio codice viene toccato come colpevole, non ho nemmeno la possibilità di avvertire l'utente di un errore.

Qualcuno può aiutarmi a capire come rispondere alla situazione di crash del codice nativo?




Related