Zmiany w działaniu Androida 7.0

Oprócz nowych funkcji i możliwości Android 7.0 wprowadza różne zmiany w działaniu systemu i interfejsu API. W tym dokumencie omawiamy niektóre kluczowe zmiany, które należy wziąć pod uwagę w swoich aplikacjach.

Jeśli opublikowałeś(-aś) już aplikację na Androida, pamiętaj, że te zmiany w systemie mogą na nią wpłynąć.

Bateria i pamięć

Android 7.0 zawiera zmiany zachowania systemu, które mają na celu wydłużenie czasu pracy baterii urządzenia i zmniejszenie wykorzystania pamięci RAM. Te zmiany mogą wpłynąć na dostęp aplikacji do zasobów systemowych oraz na sposób jej interakcji z innymi aplikacjami za pośrednictwem określonych intencji niejawnych.

Uśpienie

Wprowadzona w Androidzie 6.0 (poziom interfejsu API 23) funkcja Doze wydłuża czas pracy na baterii poprzez odkładanie na później działań procesora i działalności sieci, gdy urządzenie jest odłączone od zasilania, nieruchome i ma wyłączony ekran. Android 7.0 wprowadza dalsze udoskonalenia funkcji Doze, stosując podzbiór ograniczeń procesora i sieci, gdy urządzenie jest odłączone od zasilania, ma wyłączony ekran, ale niekoniecznie jest nieruchome, np. gdy telefon jest w kieszeni użytkownika.

Ilustracja pokazująca, jak Doze stosuje pierwsze ograniczenie aktywności systemu w celu wydłużenia czasu pracy na baterii

Rysunek 1. Ilustracja pokazująca, jak Doze stosuje pierwsze ograniczenie aktywności systemu w celu wydłużenia czasu pracy na baterii

Gdy urządzenie jest zasilane z baterii, a jego ekran był przez pewien czas wyłączony, urządzenie przejdzie w tryb uśpienia i zastosuje pierwszy podzbiór ograniczeń: wyłącza dostęp aplikacji do sieci oraz opóźnia zadania i synchronizacje. Jeśli po wejściu w tryb Doze urządzenie przez pewien czas pozostaje nieruchome, system stosuje pozostałe ograniczenia Doze do PowerManager.WakeLock, AlarmManager alarmów, GPS-a i skanowania sieci Wi-Fi. Niezależnie od tego, czy stosowane są niektóre czy wszystkie ograniczenia uśpienia, system wybudza urządzenie na krótkie okresy konserwacji, podczas których aplikacje mają dostęp do sieci i mogą wykonywać wszelkie odroczone zadania/synchronizacje.

Ilustracja przedstawiająca, jak uśpienie stosuje drugi poziom ograniczeń aktywności systemu po tym, jak urządzenie przez określony czas jest w strefie

Rysunek 2. Ilustracja pokazująca, jak Doze stosuje drugi poziom ograniczeń aktywności systemu po określonym czasie bezruchu urządzenia

Pamiętaj, że aktywowanie ekranu lub podłączenie urządzenia powoduje wyjście z Doze i zniesienie tych ograniczeń przetwarzania. Dodatkowe zachowanie nie ma wpływu na rekomendacje i najlepsze rozwiązania dotyczące dostosowywania aplikacji do wcześniejszej wersji Doze, która została wprowadzona w Androidzie 6.0 (poziom interfejsu API 23). Więcej informacji znajdziesz w artykule Optymalizacja pod kątem Doze i trybu wstrzymania aplikacji. Nadal musisz przestrzegać tych zaleceń, na przykład używać Komunikacji w chmurze Firebase (FCM) do wysyłania i odbierania wiadomości, a także zacząć planować aktualizacje, aby uwzględnić dodatkowe zachowanie Doze.

Projekt Svelte: optymalizacje w tle

Android 7.0 usuwa 3 domyślne transmisje, aby zoptymalizować wykorzystanie pamięci i zużycie energii. Ta zmiana jest konieczna, ponieważ transmisje niejawne często uruchamiają aplikacje, które zarejestrowały się jako odbiorcy w tle. Usunięcie tych transmisji może znacznie poprawić wydajność urządzenia i wygodę użytkowników.

Urządzenia mobilne często zmieniają połączenia, na przykład przełączając się z Wi-Fi na mobilną transmisję danych. Obecnie aplikacje mogą monitorować zmiany w łączności, rejestrując w pliku manifestu odbiornik niejawną transmisję CONNECTIVITY_ACTION. Wiele aplikacji rejestruje się, by odbierać tę transmisję, dlatego jeden przełącznik sieci może wywołać je wszystkie jednocześnie.

Podobnie w poprzednich wersjach Androida aplikacje mogły rejestrować się do odbioru niejawnych transmisji ACTION_NEW_PICTUREACTION_NEW_VIDEO z innych aplikacji, takich jak Aparat. Gdy użytkownik zrobi zdjęcie za pomocą aplikacji Aparat, te aplikacje zostaną uruchomione, aby przetworzyć transmisję.

Aby rozwiązać te problemy, Android 7.0 wprowadza następujące optymalizacje:

Jeśli Twoja aplikacja korzysta z któregokolwiek z tych intencjonalnych, jak najszybciej usuń ich zależności, aby móc prawidłowo kierować ją na urządzenia z Androidem 7.0. Platforma Android oferuje kilka rozwiązań, które ograniczają potrzebę korzystania z tych domyślnych transmisji. Na przykład interfejs API JobScheduler zapewnia solidny mechanizm do planowania operacji sieciowych, gdy spełnione są określone warunki, takie jak połączenie z nielimitowaną siecią. Możesz nawet używać JobScheduler, aby reagować na zmiany w dostawcach treści.

Więcej informacji o optymalizacji w tle w Androidzie 7.0 (poziom interfejsu API 24) i o tym, jak dostosować aplikację, znajdziesz w artykule Optymalizacja działania 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, katalog prywatny aplikacji kierowanych na Androida 7.0 lub nowszego ma dostęp ograniczony (0700). To ustawienie zapobiega wyciekowi metadanych plików prywatnych, takich jak ich rozmiar lub istnienie. Ta zmiana uprawnień ma kilka efektów ubocznych:

  • Właściciel pliku nie powinien już zmniejszać uprawnień dotyczących plików prywatnych, a próba dodania ich za pomocą MODE_WORLD_READABLE lub MODE_WORLD_WRITEABLE spowoduje wywołanie SecurityException.

    Uwaga: to ograniczenie nie jest jeszcze w pełni egzekwowane. Aplikacje mogą nadal modyfikować uprawnienia do katalogu prywatnego przy użyciu natywnych interfejsów API lub interfejsu API File. Zdecydowanie odradzamy jednak zniesienie uprawnień do katalogu prywatnego.

  • Przekazywanie identyfikatorów URI file:// poza domenę pakietu może spowodować, że odbiorca otrzyma ścieżkę, do której nie będzie miał dostępu. W związku z tym próby przekazania aktywatora identyfikatora URI file:// dla aktywatora FileUriExposedException. Zalecane jest udostępnianie treści pliku prywatnego za pomocą funkcji FileProvider.
  • Użytkownicy DownloadManager nie mogą już udostępniać prywatnie plików przechowywanych na dysku współdzielonym według nazwy pliku. Starsze aplikacje mogą mieć niedostępną ścieżkę podczas próby uzyskania dostępu do COLUMN_LOCAL_FILENAME. Aplikacje kierowane na Androida 7.0 lub nowszego wywołują SecurityException, gdy próbują uzyskać dostęp do COLUMN_LOCAL_FILENAME. Starsze aplikacje, które ustawiają lokalizację pobierania na publiczną za pomocą DownloadManager.Request.setDestinationInExternalFilesDir() lub DownloadManager.Request.setDestinationInExternalPublicDir() mogą nadal uzyskiwać dostęp do ścieżki w COLUMN_LOCAL_FILENAME. Nie zalecamy jednak używania tej metody. Preferowanym sposobem uzyskiwania dostępu do pliku udostępnianego przez DownloadManager jest użycie ContentResolver.openFileDescriptor().

Udostępnianie plików między aplikacjami

W przypadku aplikacji kierowanych na Androida 7.0 platforma Androida egzekwuje zasady interfejsu API StrictMode, które zabraniają ujawniania identyfikatorów URI file:// poza aplikacją. Jeśli intencje zawierająca identyfikator URI pliku opuszcza aplikację, aplikacja nie działa 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. Najprostszym 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 mające na celu poprawę użyteczności platformy dla użytkowników ze słabym lub osłabionym wzrokiem. Zmiany te nie powinny wymagać wprowadzenia zmian w kodzie aplikacji, ale warto sprawdzić te funkcje i przetestować je w aplikacji, aby ocenić ich wpływ na wrażenia użytkowników.

Powiększenie ekranu

Android 7.0 umożliwia użytkownikom ustawianie rozmiaru wyświetlacza, który powiększa lub pomniejsza wszystkie elementy na ekranie, zwiększając w ten sposób ułatwienia dostępu dla osób niedowidzących. Użytkownicy nie mogą powiększać ekranu o minimalną szerokość sw320dp, czyli szerokość tabletu Nexus 4, typowej średniej wielkości telefonu.

Ekran pokazujący niezoomowany rozmiar wyświetlacza urządzenia z obrazem systemu Android 7.0
Ekran pokazujący efekt zwiększenia rozmiaru wyświetlacza urządzenia 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 następujące sposoby:

  • 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 tej aplikacji na ekran Ustawienia i zmieni ustawienie Rozmiar wyświetlacza, system zamknie aplikację w taki sam sposób, jak w sytuacji niskiej ilości pamięci. Jeśli aplikacja ma jakieś procesy na pierwszym planie, system powiadamia je o zmianie konfiguracji w sposób opisany w artykule Obsługa zmian w czasie wykonywania, 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 sekcji Obsługa zmian w środowisku wykonawczym.

Większość aplikacji nie musi wprowadzać żadnych zmian, aby obsługiwać tę funkcję, o ile są zgodne ze sprawdzonymi metodami dotyczącymi Androida. Sprawdź te elementy:

  • Przetestuj aplikację na urządzeniu o szerokości ekranu sw320dp, aby upewnić się, że działa wystarczająco dobrze.
  • Gdy konfiguracja urządzenia ulegnie zmianie, zaktualizuj wszystkie informacje w pamięci podręcznej zależne od gęstości, takie jak zapisane w pamięci podręcznej bitmapy lub zasoby wczytane z sieci. Sprawdź, czy konfiguracja uległa zmianie, gdy aplikacja wznowi działanie po przerwie.

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

  • Unikaj podawania wymiarów w pikselach, ponieważ nie skalują się one do gęstości ekranu. Zamiast tego podaj wymiary w pikselach niezależnych od gęstości (dp).

Ustawienia dla niedowidzących w Kreatorze konfiguracji

Android 7.0 zawiera ustawienia dotyczące wzroku na ekranie powitalnym, na którym użytkownicy mogą skonfigurować te ustawienia ułatwień dostępu na nowym urządzeniu: gestyk powiększania, rozmiar czcionki, rozmiar wyświetlaczaTalkBack. Ta zmiana zwiększa widoczność błędów związanych z różnymi ustawieniami ekranu. Aby ocenić wpływ tej funkcji, przetestuj swoje aplikacje z włączonymi tymi ustawieniami. Odpowiednie ustawienia znajdziesz w sekcji Ustawienia > Ułatwienia dostępu.

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

Począwszy 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ójnego korzystania z aplikacji na różnych platformach i urządzeniach. Nawet jeśli Twój kod nie łączy się z bibliotekami prywatnymi, możliwe, że to zewnętrzna biblioteka statyczna w Twojej aplikacji. Dlatego wszyscy deweloperzy powinni się upewnić, że ich aplikacje nie ulegają awarii na urządzeniach z Androidem 7.0. Jeśli Twoja aplikacja używa kodu natywnego, powinna korzystać tylko z publicznych interfejsów NDK.

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

  • Twoja aplikacja ma bezpośredni dostęp do prywatnych bibliotek platformy. Zaktualizuj aplikację, aby zawierała własną kopię tych bibliotek, lub użyj publicznych interfejsów API NDK.
  • Twoja aplikacja korzysta z biblioteki innej firmy, która uzyskuje dostęp do prywatnych bibliotek platformy. Nawet jeśli masz pewność, że Twoja aplikacja nie ma bezpośredniego dostępu do bibliotek prywatnych, nadal musisz ją przetestować w tym scenariuszu.
  • Aplikacja odwołuje się do biblioteki, która nie jest zawarta w pliku APK. Może się tak zdarzyć, jeśli spróbujesz użyć własnej kopii OpenSSL, ale zapomnisz ją umieścić w pliku APK aplikacji. Aplikacja może działać normalnie na platformach Androida obejmujących libcrypto.so. Może się jednak zdarzyć, że aplikacja ulegnie awarii w nowszych wersjach Androida, które nie zawierają tej biblioteki (na przykład na Androidzie 6.0 i nowszych). Aby to naprawić, upewnij się, że wszystkie biblioteki inne niż NDK są pogrupowane w pliku APK.

Aplikacje nie powinny używać bibliotek natywnych, które nie są zawarte w NDK, ponieważ mogą się zmieniać lub być usuwane w różnych wersjach Androida. Przykładem takiej zmiany jest przejście z OpenSSL na BoringSSL. Poza tym ze względu na to, że nie ma wymagań dotyczących zgodności dla bibliotek platformy nieuwzględnionych w NDK, różne urządzenia mogą oferować różne poziomy zgodności.

Aby ograniczyć wpływ tego ograniczenia na już opublikowane aplikacje, zestaw bibliotek, które są często używane, takich jak libandroid_runtime.so, libcutils.so, libcrypto.solibssl.so, jest tymczasowo dostępny w Androidzie 7.0 (poziom API 24) w przypadku aplikacji kierowanych na poziom API 23 lub niższy. 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 Android mogą całkowicie ograniczyć korzystanie z bibliotek prywatnych i spowodować awarię aplikacji.

Wszystkie aplikacje generują błąd czasu wykonywania, gdy wywołują interfejs API, który nie jest publiczny ani tymczasowo dostępny. Skutkiem jest to, że System.loadLibrary i dlopen(3) zwracają NULL, co może spowodować awarię aplikacji. Sprawdź kod aplikacji, aby usunąć odwołania do prywatnych interfejsów API platformy, i gruntownie przetestuj aplikacje na urządzeniu lub w 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 opisujemy, jakie zachowanie aplikacji możesz zaobserwować w zależności od wykorzystania w niej prywatnych bibliotek natywnych i docelowego poziomu interfejsu API (android:targetSdkVersion).

Biblioteki Docelowy poziom interfejsu API Dostęp w czasie wykonywania za pomocą linkera dynamicznego Działanie Androida 7.0 (poziom interfejsu API 24) Przyszłe zachowanie platformy Android
NDK Public Dowolny 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 pojawia się ostrzeżenie w logcat. Błąd środowiska wykonawczego
Prywatne (tymczasowo dostępne prywatne biblioteki) 24 lub więcej Z ograniczonym dostępem Błąd środowiska wykonawczego Błąd środowiska wykonawczego
Prywatny (inne) Dowolny Z ograniczonym dostępem Błąd środowiska wykonawczego Błąd środowiska wykonawczego

Sprawdź, czy Twoja aplikacja korzysta z bibliotek prywatnych

Aby ułatwić wykrywanie problemów z wczytywaniem bibliotek prywatnych, logcat może wygenerować ostrzeżenie lub błąd środowiska wykonawczego. Jeśli na przykład Twoja aplikacja jest kierowana na poziom interfejsu API 23 lub niższego i próbuje uzyskać dostęp do prywatnej biblioteki na urządzeniu z Androidem 7.0, może wyświetlić 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 interfejsu API prywatnej platformy, ale nie spowoduje awarii aplikacji. Jeśli aplikacja jest kierowana na interfejs API na poziomie 24 lub wyższym, logcat generuje ten błąd czasu wykonywania, a 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)

Możesz też zobaczyć te dane wyjściowe logcat, jeśli Twoja aplikacja korzysta z bibliotek innych firm, które dynamicznie łączą się z prywatnymi interfejsami API platformy. Narzędzie readelf w Androidzie 7.0DK umożliwia wygenerowanie listy wszystkich dynamicznie powiązanych bibliotek współdzielonych danego pliku .so. Aby to zrobić, uruchom to polecenie:

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

Zaktualizuj aplikację

Oto kilka czynności, które możesz wykonać, aby naprawić tego typu błędy i upewnić się, że aplikacja nie ulegnie awarii podczas przyszłych aktualizacji platformy:

  • Jeśli Twoja aplikacja korzysta z prywatnych bibliotek platformy, zaktualizuj ją, aby zawierała własną kopię tych bibliotek, lub użyj publicznych interfejsów NDK API.
  • Jeśli Twoja aplikacja korzysta z biblioteki innej firmy, która ma dostęp do symboli prywatnych, skontaktuj się z jej autorem, aby ją zaktualizować.
  • Upewnij się, że wszystkie biblioteki inne niż NDK są spakowane w pliku APK.
  • Użyj 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>.
    
  • Zamiast prywatnego symbolu property_getlibcutils.so użyj symbolu __system_property_get. Aby to zrobić, użyj właściwości __system_property_get z tymi elementami:
    #include <sys/system_properties.h>

    Uwaga: dostępność i zawartość właściwości systemowych nie są testowane w CTS. Lepszym rozwiązaniem jest całkowite unikanie stosowania tych właściwości.

  • Użyj lokalnej wersji symbolu SSL_ctrl z poziomu libcrypto.so. Na przykład w pliku .so musisz utworzyć statyczny link do biblioteki libcyrpto.a lub dołączyć dynamicznie połączoną wersję biblioteki libcrypto.so z BoringSSL/OpenSSL i zapakować ją w pliku APK.

Android for Work

Android 7.0 zawiera zmiany w aplikacji na Androida dla firm, w tym zmiany w instalacji certyfikatów, resetowaniu hasła, zarządzaniu dodatkowym użytkownikiem i dostępie do identyfikatorów urządzenia. Jeśli tworzysz aplikacje dla środowisk Android for Work, sprawdź te zmiany i odpowiednio zmodyfikuj aplikację.

  • Musisz zainstalować delegowany instalator certyfikatów, zanim DPC będzie mógł go ustawić. W przypadku aplikacji do zarządzania profilem i aplikacji właściciela urządzenia kierowanych na Androida 7.0 (poziom interfejsu API 24) przed wywołaniem przez kontrolera zasad dotyczących urządzeń (DPC) należy zainstalować delegowany instalator certyfikatu.DevicePolicyManager.setCertInstallerPackage() Jeśli instalator nie jest jeszcze zainstalowany, system IllegalArgumentException.
  • Ograniczenia resetowania hasła dla administratorów urządzeń dotyczą teraz również właścicieli profili. Administratorzy urządzeń nie mogą już używać opcji DevicePolicyManager.resetPassword(), aby usunąć hasła lub zmienić te, które są już ustawione. Administratorzy urządzeń nadal mogą ustawić hasło, ale tylko wtedy, gdy na urządzeniu nie ma hasła, kodu PIN ani wzoru.
  • Właściciele urządzeń i profili mogą zarządzać kontami nawet wtedy, gdy są ustawione ograniczenia. Właściciele urządzeń i właściciele profili mogą wywoływać interfejsy Account Management API, nawet jeśli obowiązują ograniczenia dotyczące użytkowników DISALLOW_MODIFY_ACCOUNTS.
  • Właściciele urządzeń mogą łatwiej zarządzać dodatkowymi użytkownikami. Gdy urządzenie działa w trybie właściciela urządzenia, ograniczenie DISALLOW_ADD_USER jest automatycznie ustawiane. Zapobiega to tworzeniu przez użytkowników niezarządzanych kont dodatkowych. Ponadto metody CreateUser() i createAndInitializeUser() są wycofane; zastępuje je nowa metoda DevicePolicyManager.createAndManageUser().
  • Właściciele urządzeń mają dostęp do ich identyfikatorów. Właściciel urządzenia może uzyskać dostęp do adresu MAC karty Wi-Fi urządzenia za pomocą DevicePolicyManager.getWifiMacAddress(). Jeśli sieć Wi-Fi nie została nigdy włączona na urządzeniu, ta metoda zwraca wartość null.
  • Ustawienie Tryb pracy kontroluje dostęp do aplikacji służbowych. Gdy tryb pracy jest wyłączony, program uruchamiający system sygnalizuje, że aplikacje służbowe są niedostępne, wyświetlając je w szarym kolorze. Ponowne włączenie trybu pracy przywróci normalne działanie.
  • Podczas instalowania pliku PKCS #12 zawierającego łańcuch certyfikatów klienta i odpowiadający mu klucz prywatny z poziomu interfejsu ustawień certyfikat CA w łańcuchu nie jest już instalowany w magazynie z zaufanymi poświadczeniami. Nie ma to wpływu na wynik funkcji 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 za pomocą interfejsu ustawień, oddzielnie, w formacie DER z rozszerzeniem pliku .crt lub .cer.
  • Od Androida 7.0 rejestracja i przechowywanie odcisków palców są zarządzane na poziomie użytkownika. Jeśli klient zasad urządzenia (DPC) właściciela profilu jest przeznaczony dla poziomu interfejsu API 23 (lub niższego) na urządzeniu z Androidem 7.0 (poziom interfejsu API 24), użytkownik nadal może ustawić odcisk palca na urządzeniu, ale aplikacje służbowe nie będą mieć dostępu do odcisku palca. Jeśli DPC jest kierowany na poziom interfejsu API 24 lub nowszy, użytkownik może ustawić odcisk palca specjalnie dla profilu służbowego, klikając Ustawienia > Bezpieczeństwo > Bezpieczeństwo profilu służbowego.
  • Nowy stan szyfrowania ENCRYPTION_STATUS_ACTIVE_PER_USER jest zwracany przez DevicePolicyManager.getStorageEncryptionStatus(), aby wskazać, ż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 starsze poziomy interfejsu API zwracany jest klucz ENCRYPTION_STATUS_ACTIVE, nawet jeśli klucz szyfrowania jest specyficzny dla użytkownika lub profilu.
  • W Androidzie 7.0 kilka metod, które normalnie wpływają na całe urządzenie, działa inaczej, gdy na urządzeniu jest zainstalowany profil służbowy z osobnym testem zabezpieczającym. Te metody dotyczą tylko profilu służbowego, a nie całego urządzenia. (Pełna lista takich metod znajduje się w dokumentacji DevicePolicyManager.getParentProfileInstance()). Na przykład: DevicePolicyManager.lockNow() blokuje tylko profil służbowy, zamiast blokować całe urządzenie. W przypadku każdej z tych metod możesz uzyskać stare zachowanie, wywołując metodę w nadrzędnim wystąpieniu klasy DevicePolicyManager; możesz uzyskać ten nadrzędny element, wywołując metodę DevicePolicyManager.getParentProfileInstance(). Jeśli na przykład wywołasz metodę lockNow() instancji nadrzędnej, całe urządzenie zostaje zablokowane.

Przechowywanie adnotacji

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

  • VISIBILITY_BUILD: ma być widoczny tylko w czasie kompilacji.
  • VISIBILITY_SYSTEM: ma być widoczny w czasie wykonywania, ale tylko dla systemu podstawowego.

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

Zmiany domyślnej konfiguracji TLS/SSL

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

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

Wyłączenie domyślnie mechanizmu szyfrowania RC4 może powodować przerwy w połączeniach HTTPS lub TLS/SSL, gdy serwer nie negocjuje nowoczesnych zestawów szyfrów. Preferowaną rozwiązaniem jest ulepszenie konfiguracji serwera, aby uzyskać dostęp do silniejszych i bardziej nowoczesnych zestawów szyfrów i protokołów. W idealnej sytuacji należy włączyć TLS 1.2 i AES-GCM oraz preferować i włączać zestawy szyfrów oparte na szyfrowaniu z zachowaniem tajemnicy (ECDHE).

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

Uwaga: te zmiany nie dotyczą usługi WebView.

Aplikacje kierowane na Androida 7.0

Te zmiany zachowania dotyczą wyłącznie aplikacji kierowanych na Androida 7.0 (poziom interfejsu API 24) lub nowszego. Aplikacje skompilowane pod kątem Androida 7.0 lub z ustawieniami targetSdkVersion Androida 7.0 lub nowszego muszą zostać zmodyfikowane, aby prawidłowo obsługiwać te zachowania (w odpowiednich przypadkach).

Zmiany w serializacji

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

Klasy, które implementują interfejs Serializable i nie określają wyraźnego pola serialVersionUID, mogą mieć zmieniony domyślny identyfikator serialVersionUID, co spowoduje wyjątek podczas próby deserializacji instancji klasy, które zostały zaserializowane w wcześniejszej wersji lub za pomocą aplikacji kierowanej 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

Rozwiązanie tych problemów wymaga dodania pola serialVersionUID do każdej klasy, której dotyczy problem, z wartością stream classdesc serialVersionUID z komunikatu o błędzie (w tym przypadku 1234). Ta zmiana jest zgodna ze wszystkimi zaleceniami dotyczącymi tworzenia kodu serializacji i działa we wszystkich wersjach Androida.

Naprawiony błąd dotyczył obecności statycznych metod inicjalizujących, np. <clinit>. Zgodnie ze specyfikacją obecność lub brak metody stałego inicjalizowania w klasie wpłynie na domyślną wartość serialVersionUID obliczoną dla tej klasy. Przed naprawieniem błędu obliczenia sprawdzały też, czy superklasa zawiera statyczny inicjalizator, jeśli klasa nie miała takiego.

Zmiana ta nie ma wpływu na aplikacje kierowane na interfejs API na poziomie 23 lub niższym, klasach zawierających pole serialVersionUID ani klas zawierających metodę inicjowania statycznego.

Inne ważne informacje

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

    Przetestuj aplikację, aby upewnić się, że nie będzie ona tak działać. Możesz to zrobić, wywołując identyczne awarie, gdy ręcznie zabijasz aplikację za pomocą DDMS.

    Aplikacje kierowane na Androida 7.0 (poziom interfejsu API 24) lub nowszego nie są automatycznie usuwane po zmianie gęstości, ale nadal mogą słabo reagować na zmiany w konfiguracji.

  • Aplikacje na Androidzie 7.0 powinny płynnie obsługiwać zmiany konfiguracji i nie powinny ulegać awarii przy kolejnych uruchomieniach. Aby sprawdzić działanie aplikacji, zmień rozmiar czcionki (Ustawienia > Wyświetlacz > Rozmiar czcionki), a następnie przywróć aplikację z Ostatnich.
  • Z powodu błędu w poprzednich wersjach Androida system nie oznaczał zapisu do gniazda TCP na wątku głównym jako naruszenia trybu rygorystycznego. Ten błąd został naprawiony w Androidzie 7.0. Aplikacje, które wykazują takie zachowanie, android.os.NetworkOnMainThreadException. Ogólnie wykonywanie operacji sieciowych w wątku głównym nie jest dobrym pomysłem, ponieważ wiąże się to z dużym opóźnieniem, które powoduje błędy ANR i zacinanie.
  • Rodzina metod Debug.startMethodTracing() domyślnie przechowuje dane wyjściowe w katalogu pakietu w wspólnej pamięci masowej, 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 platform zaczęło sprawdzać, czy w ramach transakcji Binder nie są wysyłane duże ładunki. System zamiast milcząco rejestrować te ładunki lub pomijać je, zwraca teraz błąd TransactionTooLargeExceptions jako RuntimeExceptions. Typowym przykładem jest przechowywanie zbyt wielu 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 usługach View, a usługa View nie jest przypisana do okna, system umieszcza zadanie Runnable w kolejce z zadaniem View. Zadanie Runnable nie jest wykonywane, dopóki usługa View nie zostanie przypisana do okna. Dzięki temu rozwiązano te błędy:
    • Jeśli aplikacja opublikowała View z wątku innego niż przeznaczony wątek interfejsu okna, Runnable może się uruchomić 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 udostępnić zadanie Runnable.
  • Jeśli aplikacja na Androidzie 7.0 z uprawnieniami DELETE_PACKAGESpróbuje usunąć pakiet, ale został on zainstalowany przez inną aplikację, system wymaga potwierdzenia użytkownika. W takim przypadku aplikacje powinny oczekiwać wartości STATUS_PENDING_USER_ACTION jako stanu zwracanego, gdy wywołują funkcję PackageInstaller.uninstall().
  • Dostawca JCA o nazwie Crypto został wycofany, ponieważ jego jedyny algorytm, SHA1PRNG, jest słaby pod względem kryptograficznym. Aplikacje nie mogą już używać funkcji SHA1PRNG do (niebezpiecznego) wyprowadzania kluczy, ponieważ dostawca tej funkcji nie jest już dostępny. Więcej informacji znajdziesz w poście na blogu Usługa bezpieczeństwa „Crypto” nie jest już obsługiwana na Androidzie N.