Zmiany w działaniu Androida 7.0

Oprócz nowych funkcji i możliwości Android 7.0 wprowadza różne zmiany w zachowaniu systemu i interfejsów API. W tym dokumencie opisujemy niektóre z najważniejszych zmian, które musisz zrozumieć i uwzględnić w swoich aplikacjach.

Jeśli masz już opublikowaną aplikację na Androida, pamiętaj, że te zmiany na platformie mogą mieć na nią wpływ.

Bateria i pamięć

Android 7.0 zawiera zmiany w zachowaniu systemu, które mają na celu wydłużenie czasu pracy urządzenia na baterii i zmniejszenie wykorzystania pamięci RAM. Te zmiany mogą mieć wpływ na dostęp aplikacji do zasobów systemowych oraz na sposób, w jaki aplikacja współdziała z innymi aplikacjami za pomocą określonych intencji niejawnych.

Uśpienie

Wprowadzona w Androidzie 6.0 (poziom interfejsu API 23) funkcja Doze wydłuża czas pracy na baterii, odraczając aktywność procesora i sieci, gdy użytkownik pozostawia urządzenie odłączone, nieruchome i z wyłączonym ekranem. Android 7.0 wprowadza dalsze ulepszenia funkcji Doze, stosując podzbiór ograniczeń procesora i sieci, gdy urządzenie jest odłączone i ma wyłączony ekran, ale niekoniecznie jest nieruchome, np. gdy użytkownik nosi telefon w kieszeni.

Ilustracja pokazująca, jak funkcja Doze stosuje pierwszy poziom ograniczeń aktywności systemu, aby wydłużyć czas pracy na baterii

Rysunek 1. Ilustracja pokazująca, jak Doze stosuje pierwszy poziom ograniczeń aktywności systemu, aby wydłużyć czas pracy na baterii.

Gdy urządzenie jest zasilane z baterii, a ekran jest wyłączony przez określony czas, urządzenie przechodzi w tryb drzemki i stosuje pierwszy podzbiór ograniczeń: wyłącza dostęp aplikacji do sieci oraz odkłada zadania i synchronizacje. Jeśli urządzenie pozostaje nieruchome przez określony czas po przejściu w tryb drzemki, system stosuje pozostałe ograniczenia trybu drzemki do alarmów PowerManager.WakeLock, AlarmManager, GPS-a i skanowania Wi-Fi. Niezależnie od tego, czy stosowane są niektóre czy wszystkie ograniczenia drzemki, system wybudza urządzenie na krótkie okresy konserwacji, podczas których aplikacje mają dostęp do sieci i mogą wykonywać odroczone zadania lub synchronizacje.

Ilustracja pokazująca, jak Doze stosuje drugi poziom ograniczeń aktywności systemu, gdy urządzenie pozostaje nieruchome przez określony czas

Rysunek 2. Ilustracja pokazująca, jak Doze stosuje drugi poziom ograniczeń aktywności systemu, gdy urządzenie pozostaje nieruchome przez określony czas.

Pamiętaj, że aktywowanie ekranu lub podłączenie urządzenia powoduje wyjście z trybu drzemki i usunięcie tych ograniczeń przetwarzania. Dodatkowe działanie nie wpływa na rekomendacje i sprawdzone metody dostosowywania aplikacji do poprzedniej wersji trybu uśpienia wprowadzonej w Androidzie 6.0 (poziom interfejsu API 23), które zostały omówione w artykule Optymalizacja pod kątem trybu uśpienia i czuwania aplikacji. Nadal należy stosować się do tych zaleceń, takich jak używanie Komunikacji w chmurze Firebase (FCM) do wysyłania i odbierania wiadomości, oraz zacząć planować aktualizacje, aby uwzględnić dodatkowe zachowanie funkcji Doze.

Project Svelte: optymalizacje działania w tle

Android 7.0 usuwa 3 komunikaty ogólne, aby zoptymalizować wykorzystanie pamięci i zużycie energii. Ta zmiana jest konieczna, ponieważ komunikaty ogólne często uruchamiają aplikacje, które zostały zarejestrowane jako odbiorcy w tle. Usunięcie tych komunikatów może znacznie poprawić wydajność urządzenia i wrażenia użytkownika.

Urządzenia mobilne często zmieniają połączenia, np. podczas przełączania się między Wi-Fi a mobilną transmisją danych. Obecnie aplikacje mogą monitorować zmiany w połączeniu, rejestrując w pliku manifestu odbiornik komunikatu ogólnego CONNECTIVITY_ACTION. Ponieważ wiele aplikacji rejestruje się, aby otrzymywać tę transmisję, pojedyncze przełączenie sieci może spowodować, że wszystkie zostaną wybudzone i będą przetwarzać transmisję jednocześnie.

Podobnie w poprzednich wersjach Androida aplikacje mogły rejestrować się, aby otrzymywać niejawne komunikaty ACTION_NEW_PICTURE i ACTION_NEW_VIDEO z innych aplikacji, takich jak Aparat. Gdy użytkownik robi zdjęcie za pomocą aplikacji Aparat, te aplikacje budzą się, aby przetworzyć transmisję.

Aby rozwiązać te problemy, w Androidzie 7.0 zastosowano te optymalizacje:

Jeśli Twoja aplikacja używa którejkolwiek z tych intencji, jak najszybciej usuń zależności od nich, aby móc prawidłowo kierować reklamy na urządzenia z Androidem 7.0. Framework Androida udostępnia kilka rozwiązań, które pozwalają ograniczyć potrzebę stosowania tych komunikatów ogólnych. Na przykład interfejs API JobScheduler zapewnia niezawodny mechanizm planowania operacji sieciowych po spełnieniu określonych warunków, takich jak połączenie z siecią bez pomiaru. Możesz nawet używać JobScheduler, aby reagować na zmiany w mechanizmach dostarczania treści.

Więcej informacji o optymalizacjach w tle w Androidzie 7.0 (poziom interfejsu API 24) i o tym, jak dostosować aplikację, znajdziesz w artykule Optymalizacje w tle.

Zmiany uprawnień

Android 7.0 zawiera zmiany w uprawnieniach, które mogą mieć wpływ na Twoją aplikację.

Zmiany uprawnień systemu plików

Aby zwiększyć bezpieczeństwo plików prywatnych, dostęp do katalogu prywatnego aplikacji kierowanych na Androida 7.0 lub nowszego jest ograniczony (0700). To ustawienie zapobiega wyciekowi metadanych plików prywatnych, takich jak ich rozmiar czy istnienie. Ta zmiana uprawnień ma kilka skutków ubocznych:

Udostępnianie plików między aplikacjami

W przypadku aplikacji kierowanych na Androida 7.0 platforma Android wymusza zasady interfejsu API StrictMode, które zabraniają ujawniania identyfikatorów URI file:// poza aplikacją. Jeśli intencja zawierająca identyfikator URI pliku opuści aplikację, aplikacja zakończy działanie z wyjątkiem FileUriExposedException.

Aby udostępniać pliki między aplikacjami, wyślij identyfikator URI content:// i przyznaj tymczasowe uprawnienia dostępu do tego identyfikatora. Najłatwiejszym sposobem na przyznanie tego uprawnienia jest użycie klasy FileProvider. Więcej informacji o uprawnieniach i udostępnianiu plików znajdziesz w artykule Udostępnianie plików.

Udoskonalone ułatwienia dostępu

Android 7.0 zawiera zmiany, które mają na celu poprawę użyteczności platformy dla użytkowników niedowidzących lub z wadą wzroku. Te zmiany nie powinny wymagać modyfikacji kodu aplikacji, ale warto je sprawdzić i przetestować w aplikacji, aby ocenić ich potencjalny wpływ na wrażenia użytkowników.

Powiększenie ekranu

Android 7.0 umożliwia użytkownikom ustawienie rozmiaru interfejsu, który powiększa lub zmniejsza wszystkie elementy na ekranie, dzięki czemu urządzenie jest bardziej dostępne dla osób niedowidzących. Użytkownicy nie mogą powiększać ekranu poza minimalną szerokość ekranu sw320dp, która jest szerokością Nexusa 4, popularnego telefonu średniej wielkości.

Ekran pokazujący niepowiększony rozmiar wyświetlacza urządzenia z obrazem systemu Android 7.0
Ekran pokazujący efekt zwiększenia rozmiaru wyświetlacza na urządzeniu z obrazem systemu Android 7.0

Rysunek 3. Ekran po prawej stronie pokazuje efekt zwiększenia rozmiaru wyświetlacza na urządzeniu z obrazem systemu Android 7.0.

Gdy gęstość urządzenia się zmienia, system powiadamia uruchomione aplikacje w ten sposób:

  • Jeśli aplikacja jest kierowana na interfejs API na poziomie 23 lub niższym, system automatycznie zatrzymuje wszystkie jej procesy w tle. Oznacza to, że jeśli użytkownik przełączy się z takiej aplikacji, aby otworzyć ekran Ustawienia i zmienić ustawienie Rozmiar wyświetlacza, system zamknie aplikację w taki sam sposób, jak w przypadku braku pamięci. Jeśli aplikacja ma procesy na pierwszym planie, system powiadamia je o zmianie konfiguracji zgodnie z opisem w artykule Obsługa zmian w czasie działania, tak jakby zmieniła się orientacja urządzenia.
  • Jeśli aplikacja jest kierowana na Androida 7.0, wszystkie jej procesy (na pierwszym planie i w tle) są powiadamiane o zmianie konfiguracji zgodnie z opisem w artykule Obsługa zmian w czasie działania.

Większość aplikacji nie wymaga żadnych zmian, aby obsługiwać tę funkcję, pod warunkiem, że są zgodne ze sprawdzonymi metodami dotyczącymi Androida. Kwestie, które warto sprawdzić:

  • Przetestuj aplikację na urządzeniu o szerokości ekranu sw320dp i upewnij się, że działa prawidłowo.
  • Gdy konfiguracja urządzenia ulegnie zmianie, zaktualizuj wszystkie informacje z pamięci podręcznej zależne od gęstości, takie jak bitmapy z pamięci podręcznej lub zasoby wczytane z sieci. Sprawdź, czy nie wprowadzono zmian w konfiguracji, gdy aplikacja zostanie wznowiona ze stanu wstrzymania.

    Uwaga: jeśli przechowujesz w pamięci podręcznej dane zależne od konfiguracji, warto uwzględnić odpowiednie metadane, takie jak rozmiar ekranu lub gęstość pikseli. Zapisanie tych metadanych pozwala zdecydować, czy po zmianie konfiguracji trzeba odświeżyć dane z pamięci podręcznej.

  • Unikaj określania wymiarów w pikselach, ponieważ nie skalują się one wraz z gęstością ekranu. Zamiast tego określ wymiary w jednostkach pikseli niezależnych od gęstości (dp).

Ustawienia widoczności w kreatorze konfiguracji

Android 7.0 zawiera Ustawienia widzenia na ekranie powitalnym, gdzie użytkownicy mogą skonfigurować na nowym urządzeniu następujące ustawienia ułatwień dostępu: Gest powiększenia, Rozmiar czcionki, Rozmiar wyświetlacza i TalkBack. Ta zmiana zwiększa widoczność błędów związanych z różnymi ustawieniami ekranu. Aby ocenić wpływ tej funkcji, przetestuj aplikacje z włączonymi tymi ustawieniami. Ustawienia znajdziesz w sekcji Ustawienia > Ułatwienia dostępu.

Aplikacje NDK łączące się z bibliotekami platformy

Od Androida 7.0 system uniemożliwia aplikacjom dynamiczne łączenie się z bibliotekami innymi niż NDK, co może powodować awarie aplikacji. Ta zmiana zachowania ma na celu zapewnienie spójnych wrażeń użytkownika aplikacji na różnych urządzeniach i po aktualizacjach platformy. Nawet jeśli Twój kod nie jest połączony z bibliotekami prywatnymi, może to dotyczyć statycznej biblioteki innej firmy w Twojej aplikacji. Dlatego wszyscy deweloperzy powinni sprawdzić, czy ich aplikacje nie ulegają awarii na urządzeniach z Androidem 7.0. Jeśli aplikacja używa kodu natywnego, należy korzystać tylko z publicznych interfejsów API NDK.

Aplikacja może próbować uzyskać dostęp do prywatnych interfejsów API platformy na 3 sposoby:

  • Twoja aplikacja uzyskuje bezpośredni dostęp do prywatnych bibliotek platformy. Zaktualizuj aplikację, aby zawierała własną kopię tych bibliotek, lub użyj publicznych interfejsów NDK API.
  • Twoja aplikacja używa biblioteki innej firmy, która uzyskuje dostęp do prywatnych bibliotek platformy. Nawet jeśli masz pewność, że Twoja aplikacja nie uzyskuje bezpośredniego dostępu do bibliotek prywatnych, i tak przetestuj ją pod tym kątem.
  • Twoja aplikacja odwołuje się do biblioteki, która nie jest uwzględniona w jej pliku APK. Może się tak zdarzyć, jeśli na przykład próbujesz użyć własnej kopii OpenSSL, ale zapomnisz dołączyć ją do pakietu APK aplikacji. Aplikacja może działać normalnie na wersjach platformy Androida, które zawierają libcrypto.so. Jednak aplikacja może ulec awarii w nowszych wersjach Androida, które nie zawierają tej biblioteki (np. Android 6.0 lub nowszy). Aby rozwiązać ten problem, upewnij się, że wszystkie biblioteki inne niż NDK są dołączone do pakietu APK.

Aplikacje nie powinny używać bibliotek natywnych, które nie są zawarte w NDK, ponieważ mogą one ulec zmianie lub zostać usunięte w różnych wersjach Androida. Przykładem takiej zmiany jest przejście z OpenSSL na BoringSSL. Ponadto, ponieważ nie ma wymagań dotyczących zgodności bibliotek platformy, które nie są uwzględnione w NDK, różne urządzenia mogą oferować różne poziomy zgodności.

Aby zmniejszyć wpływ tego ograniczenia na obecnie opublikowane aplikacje, zestaw bibliotek, które są często używane – takich jak libandroid_runtime.so, libcutils.so, libcrypto.so i libssl.so – jest tymczasowo dostępny na Androidzie 7.0 (interfejs API na poziomie 24) w przypadku aplikacji kierowanych na interfejs API na poziomie 23 lub niższym. Jeśli aplikacja wczyta jedną z tych bibliotek, logcat wygeneruje ostrzeżenie, a na urządzeniu docelowym pojawi się powiadomienie. Jeśli zobaczysz te ostrzeżenia, zaktualizuj aplikację, aby zawierała własną kopię tych bibliotek lub używała tylko publicznych interfejsów API NDK. Przyszłe wersje platformy Androida mogą całkowicie ograniczyć korzystanie z bibliotek prywatnych i powodować awarie aplikacji.

Wszystkie aplikacje generują błąd środowiska wykonawczego, gdy wywołują interfejs API, który nie jest publiczny ani tymczasowo dostępny. W rezultacie System.loadLibrary i dlopen(3) zwracają NULL, co może spowodować awarię aplikacji. Sprawdź kod aplikacji, aby usunąć użycie prywatnych interfejsów API platformy, i dokładnie przetestuj aplikacje na urządzeniu lub emulatorze z Androidem 7.0 (poziom interfejsu API 24). Jeśli nie masz pewności, czy Twoja aplikacja używa bibliotek prywatnych, możesz sprawdzić logcat, aby zidentyfikować błąd środowiska wykonawczego.

W tabeli poniżej opisano oczekiwane zachowanie aplikacji w zależności od tego, czy używa ona prywatnych bibliotek natywnych, oraz od docelowego poziomu interfejsu API (android:targetSdkVersion).

Biblioteki Docelowy poziom interfejsu API Dostęp w czasie działania za pomocą dynamicznego tagu łączącego Działanie Androida 7.0 (poziom interfejsu API 24) Przyszłe działanie platformy Android
NDK Public Dowolna Ułatwienia dostępu Działa zgodnie z oczekiwaniami Działa zgodnie z oczekiwaniami
Prywatne (tymczasowo dostępne biblioteki prywatne) 23 lub mniej Tymczasowo dostępne Działa zgodnie z oczekiwaniami, ale otrzymujesz ostrzeżenie logcat. Błąd środowiska wykonawczego
Prywatne (tymczasowo dostępne biblioteki prywatne) 24 lub więcej, Ograniczony dostęp Błąd środowiska wykonawczego Błąd środowiska wykonawczego
Prywatny (inne) Dowolna Ograniczony dostęp Błąd środowiska wykonawczego Błąd środowiska wykonawczego

Sprawdzanie, czy aplikacja używa bibliotek prywatnych

Aby pomóc Ci zidentyfikować problemy z wczytywaniem bibliotek prywatnych, logcat może wygenerować ostrzeżenie lub błąd środowiska wykonawczego. Jeśli na przykład aplikacja jest kierowana na interfejs API na poziomie 23 lub niższym i próbuje uzyskać dostęp do biblioteki prywatnej na urządzeniu z Androidem 7.0, może pojawić się ostrzeżenie podobne do tego:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

Te ostrzeżenia logcat informują, która biblioteka próbuje uzyskać dostęp do prywatnego interfejsu API platformy, ale nie powodują awarii aplikacji. Jeśli jednak aplikacja jest kierowana na interfejs API na poziomie 24 lub wyższym, logcat generuje ten błąd środowiska wykonawczego i aplikacja może się zawiesić:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)

Te dane wyjściowe logcat mogą się też wyświetlać, jeśli aplikacja używa bibliotek innych firm, które dynamicznie łączą się z prywatnymi interfejsami API platformy. Narzędzie readelf w NDK Androida 7.0 umożliwia wygenerowanie listy wszystkich dynamicznie połączonych bibliotek współdzielonych danego pliku .so. Aby to zrobić, uruchom to polecenie:

aarch64-linux-android-readelf -dW libMyLibrary.so

Zaktualizuj aplikację

Oto kilka sposobów na rozwiązanie tego typu problemów i zapobieganie awariom aplikacji po przyszłych aktualizacjach platformy:

  • Jeśli Twoja aplikacja używa prywatnych bibliotek platformy, zaktualizuj ją, aby zawierała własną kopię tych bibliotek, lub użyj publicznych interfejsów API NDK.
  • Jeśli Twoja aplikacja korzysta z biblioteki innej firmy, która uzyskuje dostęp do symboli prywatnych, skontaktuj się z autorem biblioteki, aby ją zaktualizował.
  • Upewnij się, że wszystkie biblioteki inne niż NDK są spakowane w pliku APK.
  • Używaj standardowych funkcji JNI zamiast getJavaVM i getJNIEnv z libandroid_runtime.so:
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • Użyj __system_property_get zamiast prywatnego symbolu property_get z libcutils.so. Aby to zrobić, użyj __system_property_get z tą wartością include:
    #include <sys/system_properties.h>

    Uwaga: dostępność i zawartość właściwości systemowych nie są testowane przez CTS. Lepszym rozwiązaniem byłoby całkowite unikanie używania tych właściwości.

  • Użyj lokalnej wersji symbolu SSL_ctrl z: libcrypto.so. Na przykład należy statycznie połączyć libcyrpto.a w pliku .so lub dołączyć dynamicznie połączoną wersję libcrypto.so z BoringSSL/OpenSSL i umieścić ją w pakiecie APK.

Android for Work

Android 7.0 zawiera zmiany dotyczące aplikacji przeznaczonych na Androida for Work, w tym zmiany w instalacji certyfikatów, resetowaniu haseł, zarządzaniu użytkownikami dodatkowymi i dostępie do identyfikatorów urządzeń. Jeśli tworzysz aplikacje dla środowisk Android for Work, zapoznaj się z tymi zmianami i odpowiednio zmodyfikuj swoją aplikację.

  • Zanim kontroler zasad urządzeń (DPC) będzie mógł ustawić delegowany instalator certyfikatów, musisz go zainstalować. W przypadku aplikacji właściciela profilu i urządzenia kierowanych na Androida 7.0 (poziom interfejsu API 24) należy zainstalować instalator certyfikatów, zanim kontroler zasad dotyczących urządzeń (DPC) wywoła DevicePolicyManager.setCertInstallerPackage(). Jeśli instalator nie jest jeszcze zainstalowany, system zgłasza błąd IllegalArgumentException.
  • Ograniczenia dotyczące resetowania hasła dla administratorów urządzeń mają teraz zastosowanie do właścicieli profili. Administratorzy urządzeń nie mogą już używać DevicePolicyManager.resetPassword() do usuwania haseł ani zmieniania tych, które zostały już ustawione. Administratorzy urządzeń nadal mogą ustawić hasło, ale tylko wtedy, gdy urządzenie nie ma hasła, kodu PIN ani wzoru.
  • Właściciele urządzeń i profili mogą zarządzać kontami nawet wtedy, gdy ustawione są ograniczenia. Właściciele urządzeń i profili mogą wywoływać interfejsy API zarządzania kontem nawet wtedy, gdy obowiązują ograniczenia użytkownika DISALLOW_MODIFY_ACCOUNTS.
  • Właściciele urządzeń mogą zarządzać użytkownikami dodatkowymi. Gdy urządzenie działa w trybie właściciela, ograniczenie DISALLOW_ADD_USER jest ustawiane automatycznie. Uniemożliwia to użytkownikom tworzenie niezarządzanych użytkowników dodatkowych. Dodatkowo metody CreateUser() i createAndInitializeUser() zostały wycofane i zastąpione nową metodą DevicePolicyManager.createAndManageUser().
  • Właściciele urządzeń mają dostęp do identyfikatorów urządzeń. Właściciel urządzenia może uzyskać dostęp do adresu MAC sieci Wi-Fi urządzenia za pomocą metody DevicePolicyManager.getWifiMacAddress(). Jeśli Wi-Fi nigdy nie było włączone na urządzeniu, ta metoda zwraca wartość null.
  • Ustawienie Tryb służbowy kontroluje dostęp do aplikacji służbowych. Gdy tryb służbowy jest wyłączony, program uruchamiający system oznacza aplikacje służbowe jako niedostępne, wyszarzając je. Ponowne włączenie trybu pracy przywraca normalne działanie.
  • Podczas instalowania pliku PKCS #12 zawierającego łańcuch certyfikatów klienta i odpowiadający mu klucz prywatny z interfejsu ustawień certyfikat CA w łańcuchu nie jest już instalowany w magazynie zaufanych danych logowania. Nie ma to wpływu na wynik KeyChain.getCertificateChain(), gdy aplikacje próbują później pobrać łańcuch certyfikatów klienta. W razie potrzeby certyfikat CA należy zainstalować w magazynie zaufanych danych logowania, korzystając z osobnego interfejsu ustawień, w formacie DER z rozszerzeniem .crt lub .cer.
  • Począwszy od Androida 7.0, rejestracja i przechowywanie odcisków palców są zarządzane na poziomie użytkownika. Jeśli aplikacja Device Policy Client (DPC) właściciela profilu jest przeznaczona na interfejs API na poziomie 23 (lub niższym) na urządzeniu z Androidem 7.0 (interfejs API na poziomie 24), użytkownik nadal może skonfigurować odcisk palca na urządzeniu, ale aplikacje służbowe nie mają dostępu do odcisku palca na urządzeniu. Jeśli kontroler zasad urządzeń jest przeznaczony na interfejs API na poziomie 24 lub wyższym, użytkownik może ustawić odcisk palca specjalnie dla profilu służbowego, wybierając Ustawienia > Bezpieczeństwo > Bezpieczeństwo profilu służbowego.
  • DevicePolicyManager.getStorageEncryptionStatus() zwraca nowy stan szyfrowania ENCRYPTION_STATUS_ACTIVE_PER_USER, który wskazuje, że szyfrowanie jest aktywne, a klucz szyfrowania jest powiązany z użytkownikiem. Nowy stan jest zwracany tylko wtedy, gdy DPC jest kierowany na interfejs API na poziomie 24 lub wyższym. W przypadku aplikacji kierowanych na wcześniejsze poziomy interfejsu API zwracana jest wartość ENCRYPTION_STATUS_ACTIVE, nawet jeśli klucz szyfrowania jest powiązany z użytkownikiem lub profilem.
  • W Androidzie 7.0 kilka metod, które zwykle wpływają na całe urządzenie, działa inaczej, jeśli na urządzeniu jest zainstalowany profil służbowy z osobnym wyzwaniem służbowym. Te metody nie mają wpływu na całe urządzenie, ale tylko na profil służbowy. (Pełną listę takich metod znajdziesz w dokumentacji DevicePolicyManager.getParentProfileInstance()). Na przykład DevicePolicyManager.lockNow() blokuje tylko profil służbowy, a nie całe urządzenie. W przypadku każdej z tych metod możesz uzyskać stare zachowanie, wywołując metodę w instancji nadrzędnej DevicePolicyManager. Możesz uzyskać tę instancję nadrzędną, wywołując DevicePolicyManager.getParentProfileInstance(). Jeśli na przykład wywołasz metodę lockNow() instancji nadrzędnej, całe urządzenie zostanie zablokowane.

Przechowywanie adnotacji

W Androidzie 7.0 naprawiliśmy błąd, który powodował ignorowanie widoczności adnotacji. Ten problem umożliwiał środowisku wykonawczemu dostęp do adnotacji, do których nie powinno mieć dostępu. Te adnotacje obejmowały:

  • VISIBILITY_BUILD: ma być widoczny tylko podczas kompilacji.
  • VISIBILITY_SYSTEM: ma być widoczny w czasie działania, ale tylko dla systemu bazowego.

Jeśli Twoja aplikacja korzystała z tego zachowania, dodaj zasadę przechowywania do adnotacji, które muszą być dostępne w czasie działania. Możesz to zrobić za pomocą @Retention(RetentionPolicy.RUNTIME).

Zmiany w domyślnej konfiguracji TLS/SSL

Android 7.0 wprowadza te zmiany w domyślnej konfiguracji TLS/SSL używanej przez aplikacje do obsługi ruchu HTTPS i innego ruchu TLS/SSL:

  • Zestawy szyfrów RC4 są teraz wyłączone.
  • Zestawy szyfrów CHACHA20-POLY1305 są teraz włączone.

Domyślne wyłączenie RC4 może prowadzić do przerw w połączeniach HTTPS lub TLS/SSL, gdy serwer nie negocjuje nowoczesnych zestawów szyfrów. Zalecanym rozwiązaniem jest poprawienie konfiguracji serwera, aby umożliwić korzystanie z silniejszych i nowocześniejszych zestawów szyfrów i protokołów. Najlepiej, aby protokół TLSv1.2 i algorytm AES-GCM były włączone, a zestawy szyfrów utajnienia przekazywania (ECDHE) były włączone i preferowane.

Możesz też zmodyfikować aplikację, aby używała niestandardowego SSLSocketFactory do komunikacji z serwerem. Fabryka powinna być zaprojektowana tak, aby tworzyć instancje SSLSocket, które oprócz domyślnych zestawów szyfrów mają włączone niektóre zestawy szyfrów wymagane przez serwer.

Uwaga: te zmiany nie dotyczą WebView.

Aplikacje kierowane na Androida 7.0

Te zmiany w działaniu dotyczą wyłącznie aplikacji kierowanych na Androida 7.0 (poziom interfejsu API 24) lub nowszego. Aplikacje, które są kompilowane na Androida 7.0 lub mają ustawioną wartość targetSdkVersion na Androida 7.0 lub nowszego, muszą zostać zmodyfikowane, aby prawidłowo obsługiwały te działania, jeśli dotyczy to aplikacji.

Zmiany dotyczące serializacji

W Androidzie 7.0 (poziom interfejsu API 24) naprawiliśmy błąd w obliczaniu domyślnej wartości serialVersionUID, która nie była zgodna ze specyfikacją.

Klasy, które implementują Serializable i nie określają jawnego pola serialVersionUID, mogą zauważyć zmianę domyślnego identyfikatora serialVersionUID, co spowoduje wyjątek podczas próby deserializacji instancji klasy, które zostały zserializowane we wcześniejszej wersji lub przez aplikację kierowaną na wcześniejszą wersję. Komunikat o błędzie będzie wyglądać mniej więcej tak:

local class incompatible: stream classdesc serialVersionUID = 1234, local class serialVersionUID = 4567

Aby rozwiązać te problemy, musisz dodać pole serialVersionUID do każdej klasy, której dotyczy problem, z wartością stream classdesc serialVersionUID z komunikatu o błędzie, np. 1234 w tym przypadku. Ta zmiana jest zgodna ze wszystkimi zalecanymi sprawdzonymi metodami pisania kodu serializacji i będzie działać we wszystkich wersjach Androida.

Naprawiony błąd był związany z obecnością metod inicjatora statycznego, czyli <clinit>. Zgodnie ze specyfikacją obecność lub brak metody inicjatora statycznego w klasie wpływa na domyślny identyfikator serialVersionUID obliczony dla tej klasy. Przed poprawieniem błędu obliczenia sprawdzały też, czy klasa nadrzędna ma inicjator statyczny, jeśli klasa go nie miała.

Dla jasności: ta zmiana nie ma wpływu na aplikacje kierowane na interfejs API na poziomie 23 lub niższym, klasy z polem serialVersionUID ani klasy z metodą inicjatora statycznego.

Inne istotne zagadnienia

  • Gdy aplikacja działa na Androidzie 7.0, ale jest kierowana na niższy poziom interfejsu API, a użytkownik zmienia rozmiar wyświetlacza, proces aplikacji zostaje zatrzymany. Aplikacja musi być w stanie prawidłowo obsłużyć ten scenariusz. W przeciwnym razie ulegnie awarii, gdy użytkownik przywróci ją z ostatnich aplikacji.

    Przetestuj aplikację, aby upewnić się, że nie występuje w niej ten problem. Możesz to zrobić, wywołując identyczną awarię podczas ręcznego zamykania aplikacji za pomocą DDMS.

    Aplikacje kierowane na Androida 7.0 (poziom interfejsu API 24) i nowsze wersje nie są automatycznie wyłączane po zmianie gęstości, ale mogą nie działać prawidłowo po zmianie konfiguracji.

  • Aplikacje na Androidzie 7.0 powinny prawidłowo obsługiwać zmiany konfiguracji i nie powinny ulegać awarii przy kolejnych uruchomieniach. Możesz sprawdzić zachowanie aplikacji, zmieniając rozmiar czcionki (Ustawienia > Wyświetlacz > Rozmiar czcionki), a następnie przywracając aplikację z ostatnich.
  • Z powodu błędu w poprzednich wersjach Androida system nie oznaczał zapisu do gniazda TCP w głównym wątku jako naruszenia trybu ścisłego. Android 7.0 rozwiązuje ten problem. Aplikacje, które wykazują takie zachowanie, teraz zgłaszają błąd android.os.NetworkOnMainThreadException. Zasadniczo wykonywanie operacji sieciowych w głównym wątku nie jest dobrym pomysłem, ponieważ te operacje zwykle mają duże opóźnienie, które powoduje błędy ANR i zacinanie się.
  • Metody z rodziny Debug.startMethodTracing() domyślnie zapisują teraz dane wyjściowe w katalogu pakietu w pamięci współdzielonej, a nie na najwyższym poziomie karty SD. Oznacza to, że aplikacje nie muszą już prosić o uprawnienie WRITE_EXTERNAL_STORAGE, aby korzystać z tych interfejsów API.
  • Wiele interfejsów API platformy zaczęło teraz sprawdzać, czy w transakcjach Binder są wysyłane duże ładunki, a system ponownie zgłasza TransactionTooLargeExceptions jako RuntimeExceptions, zamiast po cichu je rejestrować lub pomijać. Jednym z typowych przykładów jest przechowywanie zbyt dużej ilości danych w Activity.onSaveInstanceState(), co powoduje, że ActivityThread.StopInfo zgłasza błąd RuntimeException, gdy aplikacja jest kierowana na Androida 7.0.
  • Jeśli aplikacja publikuje zadania Runnable w View, a View nie jest dołączony do okna, system umieszcza zadanie Runnable w kolejce z View. Zadanie Runnable nie jest wykonywane, dopóki View nie zostanie dołączony do okna. To zachowanie rozwiązuje te błędy:
    • Jeśli aplikacja opublikowała post w View z wątku innego niż wątek UI docelowego okna, w rezultacie Runnable może zostać uruchomiony w niewłaściwym wątku.
    • Jeśli zadanie Runnable zostało opublikowane z wątku innego niż wątek pętli, aplikacja może ujawnić zadanie Runnable.
  • Jeśli aplikacja na Androidzie 7.0 z uprawnieniem DELETE_PACKAGES próbuje usunąć pakiet, który został zainstalowany przez inną aplikację, system wymaga potwierdzenia przez użytkownika. W takim przypadku aplikacje powinny oczekiwać stanu zwrotu STATUS_PENDING_USER_ACTION po wywołaniu PackageInstaller.uninstall().
  • Dostawca JCA o nazwie Crypto jest wycofany, ponieważ jego jedyny algorytm, SHA1PRNG, jest słaby pod względem kryptograficznym. Aplikacje nie mogą już używać SHA1PRNG do (niebezpiecznego) generowania kluczy, ponieważ ten dostawca nie jest już dostępny. Więcej informacji znajdziesz w poście na blogu Security „Crypto” provider deprecated in Android N (Dostawca zabezpieczeń „Crypto” wycofany w Androidzie N).