Vérifier le comportement de l'application dans l'environnement d'exécution Android (ART)

Android Runtime (ART) est l'environnement d'exécution par défaut pour les appareils exécutant Android 5.0 (niveau d'API 21) ou version ultérieure. Cet environnement d'exécution offre un certain nombre de fonctionnalités qui améliorent les performances et la fluidité de la plate-forme et des applications Android. Vous trouverez plus d'informations sur les nouvelles fonctionnalités d'ART dans l'article Présentation ART

Cependant, certaines techniques qui fonctionnent avec Dalvik ne fonctionnent pas avec ART. Ce sur les éléments à surveiller lors de la migration pour qu'elle soit compatible avec ART. La plupart des applications devraient simplement fonctionner avec L'ART.

Résoudre les problèmes de récupération de mémoire

Sous Dalvik, les applications trouvent souvent utile d'appeler explicitement System.gc() pour demander la récupération de mémoire. Il doit s'agir beaucoup moins nécessaire avec ART, en particulier si vous appelez la récupération de mémoire pour empêcher les types GC_FOR_ALLOC ou pour réduire la fragmentation. Vous pouvez vérifier quel environnement d'exécution est utilisé en appelant System.getProperty("java.vm.version"). Si ART est utilisée, la valeur de la propriété est supérieur ou égal à "2.0.0".

ART utilise le collecteur de copie simultanée (CC) qui compacte simultanément le tas de mémoire Java. Pour cette raison, vous devez éviter d'utiliser des techniques incompatibles avec le compactage de la récupération de mémoire (par exemple, l'enregistrement de pointeurs vers données d'instance). Cela est particulièrement important pour les applications qui utilisent Java Native Interface (JNI) Pour en savoir plus, consultez la section Prévenir les problèmes JNI.

Éviter les problèmes JNI

La JNI d'ART est un peu plus stricte que celle de Dalvik. C'est une bonne idée particulièrement pour utiliser le mode CheckJNI pour détecter les problèmes courants. Si votre application utilise C/C++ consultez l'article suivant:

Débogage JNI Android avec CheckJNI

Vérifier le code JNI pour détecter des problèmes de récupération de mémoire

Le collecteur de copie simultanée peut déplacer des objets en mémoire pour le compactage. Si vous utilisez du code C/C++, effectuer des opérations incompatibles avec le compactage de la récupération de mémoire. Nous avons amélioré CheckJNI pour identifier certains problèmes potentiels (comme décrit dans JNI) "Local Reference Changes in ICS" (Modifications des références locales dans ICS)).

Un domaine à surveiller en particulier est l'utilisation Get...ArrayElements() et Release...ArrayElements() fonctions. Dans les environnements d'exécution avec une récupération de mémoire non compacte, Les fonctions Get...ArrayElements() renvoient généralement une référence au la mémoire réelle de l'objet de tableau. Si vous modifiez l'un des renvoie des éléments de tableau, l'objet de tableau est lui-même modifié (et les arguments sur Release...ArrayElements() sont généralement ignorés). Toutefois, si de compactage de récupération de mémoire est en cours d'utilisation, les fonctions Get...ArrayElements() peuvent renvoyer une copie du souvenir. Si vous faites un usage abusif de la référence lors du compactage de la récupération de mémoire, en cours d'utilisation, cela peut entraîner une corruption de la mémoire ou d'autres problèmes. Exemple :

  • Si vous apportez des modifications aux éléments du tableau renvoyés, vous devez appeler la fonction la fonction Release...ArrayElements() appropriée quand vous avez terminé, pour vous assurer que vos modifications sont correctement recopiées ARRAY.
  • Lorsque vous libérez les éléments du tableau de mémoire, vous devez utiliser les en fonction des modifications que vous avez apportées: <ph type="x-smartling-placeholder">
      </ph>
    • Si vous n'avez apporté aucune modification aux éléments du tableau, utilisez Mode JNI_ABORT, qui libère la mémoire sans la copier à l'objet de tableau sous-jacent.
    • Si vous avez modifié le tableau et que vous n'avez pas besoin de la référence utilisez le code 0 (qui met à jour l'objet ARRAY et libère la copie du souvenir).
    • Si vous avez apporté des modifications au tableau que vous souhaitez valider Pour conserver la copie du tableau, utilisez JNI_COMMIT (qui met à jour l'objet de tableau sous-jacent et en conserve la copie).
  • Lorsque vous appelez Release...ArrayElements(), renvoyez le même pointeur initialement renvoyé par Get...ArrayElements(). Pour exemple, il n'est pas prudent d'incrémenter le pointeur d'origine (pour parcourir les les éléments de tableau renvoyés), puis transmettez le pointeur incrémenté à Release...ArrayElements() La transmission de ce pointeur modifié peut entraîner la mauvaise mémoire à libérer, ce qui entraîne une corruption de la mémoire.

Gestion des exceptions

Le JNI d'ART génère des erreurs dans un certain nombre de cas contraires à Dalvik. (Une fois à nouveau, vous pouvez détecter de nombreux cas de ce type en effectuant un test avec CheckJNI.)

Par exemple, si RegisterNatives est appelé avec une méthode qui n'existe pas (peut-être parce que la méthode a été supprimée par un outil ProGuard), ART génère désormais correctement NoSuchMethodError:

08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
    no static or non-static method
    "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.nativeLoad(Native Method)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.doLoad(Runtime.java:421)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.loadLibrary(Runtime.java:362)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.System.loadLibrary(System.java:526)

ART consigne également une erreur (visible dans Logcat) si RegisterNatives est appelé sans méthode:

W/art     ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
methods for <classname>

De plus, les fonctions JNI GetFieldID() et GetStaticFieldID() génère désormais correctement NoSuchFieldError au lieu de simplement renvoyer la valeur null. De même, GetMethodID() et GetStaticMethodID() génère désormais correctement NoSuchMethodError. Cela peut entraîner des échecs de CheckJNI en raison des exceptions non gérées ou du des exceptions sont générées pour les appelants Java de code natif. Ainsi, Il est particulièrement important de tester les applications compatibles avec ART avec le mode CheckJNI.

ART attend des utilisateurs des méthodes JNI CallNonvirtual...Method() (comme CallNonvirtualVoidMethod()) pour utiliser la déclaration de la méthode et non une sous-classe, comme l'exige la spécification JNI.

Prévention des problèmes liés à la taille de la pile

Dalvik avait des piles séparées pour le code natif et le code Java, avec un code Java par défaut une taille de pile de 32 Ko et une taille de pile native par défaut de 1 Mo. ART propose une plate-forme unifiée pour une meilleure localité. Habituellement, la pile Thread ART doit être à peu près identique à celle de Dalvik. Toutefois, si vous indiquez explicitement des tailles de pile définies, vous devrez peut-être revoir ces valeurs pour les applications exécutées dans L'ART.

  • En Java, examinez les appels au constructeur Thread qui spécifient une pile explicite. la taille de l'image. Par exemple, vous devrez augmenter la taille si StackOverflowError se produit.
  • En C/C++, examinez l'utilisation de pthread_attr_setstack() et pthread_attr_setstacksize() pour les threads qui exécutent également du code Java via JNI Voici un exemple d'erreur consignée lorsqu'une application tente d'appeler JNI AttachCurrentThread() lorsque la taille du thread est trop petite:
    F/art: art/runtime/thread.cc:435]
        Attempt to attach a thread with a too-small stack (16384 bytes)

Modifications apportées au modèle d'objet

Dalvik autorisait à tort des sous-classes à remplacer les méthodes "package-private". ART émet un avertissement dans les cas suivants:

Before Android 4.1, method void com.foo.Bar.quux()
would have incorrectly overridden the package-private method in
com.quux.Quux

Si vous avez l'intention de remplacer la méthode d'une classe dans un autre package, déclarez le comme public ou protected.

Object comporte désormais des champs privés. Applications qui réfléchissent aux champs de leur hiérarchie de classe doivent veiller à ne pas tenter d'examiner de Object. Par exemple, si vous itérez une classe dans le cadre d'un framework de sérialisation, arrêtez

Class.getSuperclass() == java.lang.Object.class

au lieu de continuer jusqu'à ce que la méthode renvoie null.

Le proxy InvocationHandler.invoke() reçoit désormais null s'il n'existe aucun au lieu d'un tableau vide. Ce comportement a été documenté précédemment, mais n'est pas gérée correctement dans Dalvik. Les versions précédentes de Mockito présentent des difficultés Utilisez donc une version mise à jour de Mockito lors des tests avec ART.

Résoudre les problèmes de compilation anticipée

La compilation Java anticipée (Ahead Of Time, AOT) d'ART devrait fonctionner pour tous les langages Java standards du code source. La compilation est réalisée par ART Outil dex2oat si vous rencontrez des problèmes liés à dex2oat au moment de l'installation, veuillez nous en informer (voir la section Problèmes liés aux rapports) afin que nous puissions les résoudre le plus rapidement possible que possible. Quelques points à noter:

  • ART effectue une vérification du bytecode plus stricte au moment de l'installation que Dalvik. Le code produit par les outils de compilation Android ne devrait pas poser de problème. Cependant, certaines les outils de post-traitement (en particulier ceux qui effectuent l'obscurcissement) peuvent produire fichiers non valides tolérés par Dalvik, mais rejetés par ART. Nous avons en collaborant avec les fournisseurs d’outils pour détecter et résoudre ces problèmes. Dans de nombreux cas, les dernières versions de vos outils et regénérer les fichiers DEX. des problèmes.
  • Voici quelques problèmes courants signalés par le vérificateur ART: <ph type="x-smartling-placeholder">
      </ph>
    • flux de contrôle non valide
    • déséquilibré monitorenter/monitorexit
    • Taille de la liste de types de paramètres de longueur 0
  • Certaines applications ont des dépendances sur le fichier .odex installé format dans /system/framework, /data/dalvik-cache ou dans le répertoire de sortie optimisé de DexClassLoader. Ces sont désormais des fichiers ELF et non une forme étendue de fichiers DEX. Alors qu'ART, doivent respecter les mêmes règles de verrouillage et de dénomination que Dalvik, les applications ne doivent pas dépendre sur le format de fichier, ce format est susceptible d'être modifié sans préavis.

    Remarque:Dans Android 8.0 (niveau d'API 26) et supérieur, le répertoire de sortie optimisé DexClassLoader est obsolète. Pour en savoir plus, consultez la documentation DexClassLoader() d'un constructeur.

Problèmes liés à la création de rapports

Si vous rencontrez des problèmes qui ne sont pas dus à des problèmes JNI d'application, signalez-les via l'outil Issue Tracker du projet Android Open Source disponible à l'adresse https://code.google.com/p/android/issues/list. Incluez un "adb bugreport" et un lien vers l'application dans la Play Store, si disponible. Sinon, si possible, joignez un APK qui reproduit le problème. Notez que les problèmes (pièces jointes comprises) sont publics visible.