Weryfikowanie działania aplikacji w środowisku wykonawczym Androida (ART)

Środowisko wykonawcze Androida (ART) to domyślne środowisko wykonawcze dla urządzeń z Androidem 5.0 (poziom interfejsu API 21) lub nowszy. To środowisko wykonawcze udostępnia wiele funkcji które zwiększają wydajność i płynność działania platformy Androida i aplikacji. Więcej informacji o nowych funkcjach ART znajdziesz w Prezentacjach REKLAMA GRAFICZNA

Jednak niektóre techniki, które działają w Dalviku, nie działają w ART. Ten informuje, na co zwracać uwagę przy migracji istniejącego dokumentu aby była zgodna z ART. Większość aplikacji powinna po prostu działać ART.

Rozwiązywanie problemów z czyszczeniem pamięci

W dziedzinie Dalvik aplikacje często przydają się bezpośredniemu wywołaniu System.gc(), aby wyświetlić monit czyszczenia pamięci. Powinien to być w przypadku ART, zwłaszcza jeśli wywołujesz czyszczenie pamięci. aby zapobiec konwersjom typu GC_FOR_ALLOC wystąpieniami lub ograniczeniu fragmentacji. Możesz sprawdzić, które środowisko wykonawcze jest używane dzwoniąc pod numer System.getProperty("java.vm.version"). Jeśli używana jest reklama ART, wartość właściwości wynosi "2.0.0" lub więcej.

ART używa kolektora równoczesnego kopiowania (CC), który jednocześnie kompresuje stertę Java. Z tego powodu nie należy stosować metod które są niezgodne z kompresowaniem GC (np. przez zapisywanie wskaźników do obiektów danych instancji). Jest to szczególnie ważne w przypadku aplikacji, które korzystają z Java Native Interface (JNI). Więcej informacji znajdziesz w artykule na temat zapobiegania problemom z JNI.

Zapobieganie problemom JNI

JNI w ART jest nieco bardziej restrykcyjne niż Dalvik. Szczególnie dobrym pomysłem jest do wykrywania typowych problemów w trybie CheckJNI. Jeśli Twoja aplikacja używa języka C/C++ zapoznaj się z tym artykułem:

Debugowanie Android JNI z CheckJNI

Sprawdzam kod JNI pod kątem problemów z odśmiecaniem pamięci

Kolektor równoczesny kopiowania (CC) może przenosić obiekty w pamięci w celu kompresowania. Jeśli używasz kodu w języku C/C++, nie dodawaj wykonywać operacje niezgodne z kompresowaniem GC. Ulepszyliśmy Sprawdź JNI, aby zidentyfikować potencjalne problemy (zgodnie z opisem w JNI) Lokalne zmiany plików referencyjnych w ICS).

Zwróć szczególną uwagę na Get...ArrayElements() i Release...ArrayElements() funkcji. W środowiskach wykonawczych z niekompaktowym czyszczeniem pamięci Funkcje Get...ArrayElements() zwykle zwracają odwołanie do funkcji w pamięci podręcznej obiektu tablicy. Jeśli zmienisz którąś z tych opcji zwróconych elementów tablicy, obiekt tablicy został zmieniony (a argumenty do Release...ArrayElements() są zwykle ignorowane). Jeśli jednak Używasz kompresowania GC, funkcje Get...ArrayElements() mogą spowoduje zwrócenie kopii wspomnienia. Jeśli użyjesz odwołania niewłaściwie podczas kompresowania zawartości GC, może to spowodować uszkodzenie pamięci lub inne problemy. Na przykład:

  • Jeśli wprowadzisz zmiany w zwróconych elementach tablicy, musisz wywołać metodę Gdy skończysz, odpowiednią funkcję Release...ArrayElements(), aby mieć pewność, że zmiany zostaną prawidłowo skopiowane obiektu tablicy.
  • Przy zwalnianiu elementów tablicy pamięci musisz użyć odpowiedniej w zależności od wprowadzonych zmian:
    • Jeśli nie zostały wprowadzone żadne zmiany w elementach tablicy, użyj funkcji tryb JNI_ABORT, który zwalnia pamięć bez kopiowania. zmienia się z powrotem na bazowy obiekt tablicy.
    • Jeśli wprowadzono zmiany w tablicy i nie potrzebujesz odwołania użyj kodu 0 (który aktualizuje obiekt tablicy i zwalnia kopii wspomnienia).
    • Jeśli wprowadzono zmiany w tablicy, które chcesz zatwierdzić, i chcesz aby zachować kopię tablicy, należy użyć funkcji JNI_COMMIT (która aktualizuje bazowego obiektu tablicy i zachowuje kopię).
  • Gdy zadzwonisz do: Release...ArrayElements(), zwróć wskaźnik, który został pierwotnie zwrócony przez użytkownika Get...ArrayElements(). Dla: na przykład zwiększenie wartości oryginalnego wskaźnika nie jest bezpieczne (aby przeskanować zwróconych elementów tablicy), a następnie przekazać rosnący wskaźnik do Release...ArrayElements() Przekazanie tego zmodyfikowanego wskaźnika może spowodować niewłaściwą pamięć do zwolnienia, co skutkuje jej uszkodzeniem.

Obsługa błędów

JNI ART zamieszcza błędy w wielu przypadkach, a Dalvik ich nie popełnia. (Raz możesz wykryć wiele takich przypadków, testując je za pomocą CheckJNI).

Jeśli na przykład funkcja RegisterNatives jest wywoływana za pomocą metody, która nie istnieje (prawdopodobnie dlatego, że metoda została usunięta przez narzędzie, ProGuard), ART teraz prawidłowo przesyła 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 również rejestruje błąd (widoczny w logcat), jeśli RegisterNatives nie można wywołać żadnej metody:

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

Ponadto funkcje JNI GetFieldID() i GetStaticFieldID() teraz poprawnie przesyła NoSuchFieldError zamiast zwracania wartości null. Podobnie GetMethodID() oraz GetStaticMethodID() teraz poprawnie zgłasza NoSuchMethodError. Może to prowadzić do błędów CheckJNI z powodu nieobsługiwanych wyjątków lub wysyłane do elementów wywołujących kod natywny w Javie wyjątki. Dzięki temu szczególnie ważne przy testowaniu aplikacji zgodnych z ART w trybie CheckJNI.

ART wymaga od użytkowników metod CallNonvirtual...Method() JNI (np. CallNonvirtualVoidMethod()), aby użyć deklaracji metody class, a nie podklasy, zgodnie z wymaganiami specyfikacji JNI.

Zapobieganie problemom z rozmiarem stosu

Dalvik miał oddzielne stosy dla kodu natywnego i Javy z domyślną przeglądarką rozmiar stosu 32 KB i domyślny rozmiar stosu natywnego wynoszący 1 MB. ART tworzy ujednolicone na podstawie lokalizacji. Zwykle stos ART Thread powinien być mniej więcej taki sam jak w przypadku Dalvik. Jeśli jednak wyraźnie ustalasz rozmiary stosu, być może trzeba będzie sprawdzić te wartości w przypadku aplikacji działających ART.

  • W języku Java przejrzyj wywołania konstruktora Thread, które określają jawny stos rozmiaru. Musisz na przykład zwiększyć rozmiar, jeśli wystąpi StackOverflowError.
  • W C/C++ przejrzyj użycie pakietów pthread_attr_setstack() i pthread_attr_setstacksize() w przypadku wątków, w których uruchamiany jest również kod w języku Java JNI Oto przykład błędu rejestrowanego, gdy aplikacja próbuje wywołać JNI AttachCurrentThread(), gdy rozmiar pthread jest zbyt mały:
    F/art: art/runtime/thread.cc:435]
        Attempt to attach a thread with a too-small stack (16384 bytes)

Zmiany modelu obiektu

Dalvik nieprawidłowo zezwolił podklasom na zastępowanie metod prywatnych pakietów. ART przesyła ostrzeżenie w takich przypadkach:

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

Jeśli chcesz zastąpić metodę klasy w innym pakiecie, zadeklaruj parametr jako public lub protected.

Object ma teraz pola prywatne. Aplikacje, które refleksują nad polami w ich hierarchiach klas, należy uważać, aby nie brać pod uwagę Object. Jeśli na przykład powtarzasz klasę, jako część platformy serializacji, zatrzymaj, gdy

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

zamiast kontynuować, dopóki metoda nie zwróci wartości null.

Serwer proxy InvocationHandler.invoke() otrzymuje teraz null, jeśli nie ma żadnych zamiast pustej tablicy. To zachowanie było wcześniej udokumentowane, ale nie jest prawidłowo obsługiwany w Dalvik. Poprzednie wersje Mockito mają problemy z dlatego podczas testowania w ART używaj zaktualizowanej wersji Mockito.

Rozwiązywanie problemów z kompilacją AOT

Kompilacja oprogramowania Ahead-Of-Time (AOT) firmy ART powinna działać w przypadku wszystkich standardowych plików Java. w kodzie. Kompilację wykonuje aplikacja ART narzędzie dex2oat; w przypadku problemów związanych z dex2oat podczas instalacji poinformuj nas o tym (patrz Zgłaszanie problemów), abyśmy mogli jak najszybciej je rozwiązać. jak to tylko możliwe. Pamiętaj o kilku kwestiach:

  • Podczas instalacji ART przeprowadza bardziej szczegółową weryfikację przy użyciu kodu bajtowego niż Dalvik. Kod wygenerowany przez narzędzia do kompilacji na Androida powinien być prawidłowy. Jednak niektóre za pomocą narzędzi do obróbki kodu (zwłaszcza narzędzi do zaciemniania kodu), nieprawidłowe pliki są tolerowane przez Dalvik, ale odrzucone przez ART. Byliśmy we współpracy z dostawcami narzędzi, aby wykryć i rozwiązać tego typu problemy. W wielu przypadkach uzyskanie najnowsze wersje narzędzi i ponowne wygenerowanie plików DEX mogą rozwiązać te problemy. .
  • Typowe problemy, które weryfikator ART powiadamia:
    • nieprawidłowy przepływ kontroli
    • niezbilansowane monitorenter/monitorexit
    • Rozmiar listy typów parametrów o długości 0
  • Niektóre aplikacje zależą od zainstalowanego pliku .odex format w formacie /system/framework, /data/dalvik-cache lub w zoptymalizowanym katalogu wyjściowym aplikacji DexClassLoader. Te są teraz plikami ELF, a nie rozszerzoną formą plików DEX. Gdy ART próbuje aby były zgodne z zasadami nazewnictwa i blokowania co Dalvik, aplikacje nie powinny formatu pliku, format może ulec zmianie bez powiadomienia.

    Uwaga: na Androidzie 8.0 (poziom interfejsu API 26) i , jest to DexClassLoader zoptymalizowany katalog wyjściowy została wycofana. Więcej informacji znajdziesz w dokumentacji DexClassLoader() za pomocą konstruktora.

Problemy z raportowaniem

Jeśli napotkasz problemy, które nie są spowodowane problemami z JNI dotyczącymi aplikacji, zgłoś można je przesłać za pomocą narzędzia Android Open Source Project Issue Tracker na stronie https://code.google.com/p/android/issues/list. Umieść w Google link "adb bugreport" i link do aplikacji Sklepu Play, jeśli jest dostępny. Jeśli to możliwe, załącz plik APK, który umożliwia odtwarzanie i rozpoznają problem. Pamiętaj, że problemy (w tym załączniki) są widoczne publicznie widoczne.