Od Androida 9 (poziom interfejsu API 28) platforma ogranicza interfejsy spoza pakietu SDK, których może używać aplikacja. Te ograniczenia obowiązują, gdy aplikacja odwołuje się do interfejsu innego niż SDK lub próbuje uzyskać jego uchwyt za pomocą odbicia lustrzanego lub JNI. Te ograniczenia zostały wprowadzone, aby poprawić wrażenia użytkowników i deweloperów oraz zmniejszyć ryzyko awarii dla użytkowników i awaryjnych wdrożeń dla deweloperów. Więcej informacji o tej decyzji znajdziesz w artykule Zwiększanie stabilności przez ograniczanie korzystania z interfejsów innych niż SDK.
Różnice między interfejsami SDK i nie-SDK
Ogólnie rzecz biorąc, publiczne interfejsy pakietu SDK to te, które są opisane w indeksie pakietów platformy Android. Obsługa interfejsów innych niż SDK to szczegół implementacji, który jest abstrakcją interfejsu API, więc te interfejsy mogą ulec zmianie bez powiadomienia.
Aby uniknąć awarii i nieoczekiwanego zachowania, aplikacje powinny korzystać tylko z oficjalnie udokumentowanych części klas w pakiecie SDK. Oznacza to też, że nie możesz uzyskiwać dostępu do metod ani pól, które nie są wymienione w pakiecie SDK, gdy wchodzisz w interakcję z klasą za pomocą mechanizmów takich jak odbicie lustrzane.
Listy interfejsów API spoza pakietu SDK
W każdej nowej wersji Androida ograniczamy dostęp do kolejnych interfejsów innych niż SDK. Wiemy, że te ograniczenia mogą mieć wpływ na Twój proces publikowania. Chcemy jednak zapewnić Ci narzędzia do wykrywania korzystania z interfejsów innych niż SDK, przekazać nam opinię oraz czas na zaplanowanie i dostosowanie się do nowych zasad.
Aby zminimalizować wpływ ograniczeń dotyczących interfejsów spoza pakietu SDK na proces programowania, interfejsy spoza pakietu SDK zostały podzielone na listy, które określają, na ile ich użycie jest ograniczone w zależności od poziomu interfejsu API. W tabeli poniżej opisano te listy:
Lista | Tagi kodu | Opis |
---|---|---|
Lista zablokowanych |
|
Interfejsy spoza pakietu SDK, których nie można używać niezależnie od docelowego poziomu interfejsu API aplikacji. Jeśli aplikacja próbuje uzyskać dostęp do jednego z tych interfejsów, system wyrzuca błąd. |
Warunkowo zablokowany |
|
Począwszy od Androida 9 (poziom API 28) każdy poziom interfejsu API ma interfejsy spoza pakietu SDK, które są ograniczone, gdy aplikacja jest kierowana na ten poziom. Te listy są opisane maksymalnym poziomem interfejsu API ( Jeśli aplikacja próbuje uzyskać dostęp do interfejsu, który jest ograniczony dla docelowego poziomu interfejsu API, system zachowuje się tak, jakby interfejs API był częścią listy blokowania. |
Nieobsługiwane |
|
interfejsy inne niż SDK, które nie są ograniczone i których może używać Twoja aplikacja. Pamiętaj, że te interfejsy nie są obsługiwane i mogą ulec zmianie bez powiadomienia. Spodziewaj się, że te interfejsy zostaną zablokowane warunkowo w kolejnych wersjach Androida na liście max-target-x . |
Pakiet SDK |
|
Interfejsy, których można używać swobodnie i które są teraz obsługiwane w ramach oficjalnie udokumentowanego frameworka Androida Package Index. |
Testowanie interfejsów API |
|
interfejsy używane do testowania wewnętrznego systemu, takie jak interfejsy API ułatwiające testowanie za pomocą pakietu Compatibility Test Suite (CTS); Interfejsy API testowe nie są częścią pakietu SDK. Od Androida 11 (poziom interfejsu API 30) interfejsy API testowe są uwzględniane na liście blokowania, więc aplikacje nie mogą z nich korzystać niezależnie od docelowego poziomu interfejsu API. Wszystkie testowe interfejsy API nie są obsługiwane i mogą ulec zmianie bez powiadomienia, niezależnie od poziomu interfejsu API platformy. |
Chociaż możesz używać niektórych interfejsów spoza pakietu SDK (w zależności od docelowego poziomu interfejsu API aplikacji), korzystanie z metod lub pól spoza pakietu SDK zawsze wiąże się z wysokim ryzykiem awarii aplikacji. Jeśli Twoja aplikacja korzysta z interfejsów spoza pakietu SDK, zacznij planować migrację na interfejsy SDK lub inne alternatywy. Jeśli nie możesz znaleźć alternatywy dla interfejsu spoza pakietu SDK, który jest używany w funkcji Twojej aplikacji, poproś o nowy publiczny interfejs API.
Sprawdzanie, do której listy należy interfejs
Listy interfejsów innych niż SDK są tworzone jako część platformy. Informacje o poszczególnych wersjach Androida znajdziesz w następnych sekcjach.
Android 16 (wersja dla programistów)
W przypadku Androida 16 możesz pobrać plik opisujący wszystkie interfejsy spoza pakietu SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
a22d5c2fa9c24ec0b864f0680208e9794222d1921114abe3245979143ce6d1c6
Więcej informacji o zmianach w liście interfejsów API spoza pakietu SDK w Androidzie 16 znajdziesz w artykule Zmiany w ograniczeniach interfejsów API spoza pakietu SDK w Androidzie 16.
Android 15
W przypadku Androida 15 (poziom API 35) możesz pobrać plik, który opisuje wszystkie interfejsy inne niż interfejsy SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
40134e205e58922a708c453726b279a296e6a1f34a988abd90cec0f3432ea5a9
Więcej informacji o zmianach w liście interfejsów API spoza pakietu SDK w Androidzie 15 znajdziesz w artykule Zmiany ograniczeń interfejsów API spoza pakietu SDK w Androidzie 15.
Android 14
W przypadku Androida 14 (poziom API 34) możesz pobrać plik, który opisuje wszystkie interfejsy spoza pakietu SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
7e00db074cbe51c51ff4b411f7b48e98692951395c5c17d069c822cc1d0eae0f
Więcej informacji o zmianach w liście interfejsów API spoza pakietu SDK w Androidzie 14 znajdziesz w artykule Zmiany w ograniczeniach interfejsów API spoza pakietu SDK w Androidzie 14.
Android 13
W przypadku Androida 13 (poziom API 33) możesz pobrać plik, który opisuje wszystkie interfejsy inne niż SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
233a277aa8ac475b6df61bffd95665d86aac6eb2ad187b90bf42a98f5f2a11a3
Więcej informacji o zmianach w liście interfejsów API spoza pakietu SDK w Androidzie 13, w tym o zalecanych alternatywnych interfejsach API dla interfejsów API, które są blokowane warunkowo w Androidzie 13, znajdziesz w artykule Zmiany w ograniczeniach interfejsów API spoza pakietu SDK w Androidzie 13.
Android 12
W przypadku Androida 12 (poziom API 31) możesz pobrać plik, który opisuje wszystkie interfejsy spoza pakietu SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761
Więcej informacji o zmianach w liście interfejsów API innych niż SDK w Androidzie 12, w tym o sugerowanych alternatywnych interfejsach API dla interfejsów blokowanych warunkowo w Androidzie 12, znajdziesz w artykule Zmiany w liście interfejsów API w Androidzie 12.
Android 11
W przypadku Androida 11 (poziom API 30) możesz pobrać plik, który opisuje wszystkie interfejsy inne niż SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
a19d839f4f61dc9c94960ae977b2e0f3eb30f880ba1ffe5108e790010b477a56
Aby dowiedzieć się więcej o zmianach w liście interfejsów API innych niż SDK w Androidzie 11, w tym o sugerowanych alternatywnych interfejsach API dla interfejsów, które są warunkowo zablokowane w Androidzie 11, przeczytaj artykuł Zmiany w liście interfejsów API w Androidzie 11.
Android 10
W przypadku Androida 10 (poziom API 29) możesz pobrać plik, który opisuje wszystkie interfejsy inne niż SDK i odpowiednie listy:
Plik: hiddenapi-flags.csv
Suma kontrolna SHA-256:
f22a59c215e752777a114bd9b07b0b6b4aedfc8e49e6efca0f99681771c5bfeb
Aby dowiedzieć się więcej o zmianach w liście interfejsów API innych niż SDK w Androidzie 10, w tym o sugerowanych publicznych alternatywach dla interfejsów API, które są warunkowo blokowane w Androidzie 10, zapoznaj się z artykułem Zmiany w liście interfejsów API w Androidzie 10.
Android 9
W przypadku Androida 9 (poziom interfejsu API 28) ten plik tekstowy zawiera listę interfejsów API spoza pakietu SDK, które nie są ograniczone (znajdują się na liście szarej):hiddenapi-light-greylist.txt
.
Lista zablokowanych adresów (blacklist
) i lista interfejsów API zablokowanych warunkowo (ciemnoszara lista) są tworzone w czasie kompilacji.
Generowanie list z AOSP
Podczas pracy z AOSP możesz wygenerować plik hiddenapi-flags.csv
, który zawiera wszystkie interfejsy inne niż SDK i odpowiednie listy. Aby to zrobić, pobierz kod źródłowy AOSP, a potem uruchom to polecenie:
m out/soong/hiddenapi/hiddenapi-flags.csv
Plik znajdziesz w tym miejscu:
out/soong/hiddenapi/hiddenapi-flags.csv
Zakładane działanie podczas uzyskiwania dostępu do ograniczonych interfejsów innych niż SDK
Z tabeli poniżej dowiesz się, czego możesz się spodziewać, gdy Twoja aplikacja próbuje uzyskać dostęp do interfejsu innego niż SDK, który znajduje się na liście zablokowanych.
Sposób dostępu | Wynik |
---|---|
Instrukcja Dalvik odwołująca się do pola | NoSuchFieldError rzucono |
Instrukcja Dalvik odwołująca się do metody | NoSuchMethodError rzucono |
Odbicie za pomocą Class.getDeclaredField() lub Class.getField() |
NoSuchFieldException rzucono |
Odbicie przy użyciu Class.getDeclaredMethod() , Class.getMethod() |
NoSuchMethodException rzucono |
Odbicie przy użyciu Class.getDeclaredFields() , Class.getFields() |
Użytkownicy spoza pakietu SDK nie są uwzględniani w wynikach |
Odbicie przy użyciu Class.getDeclaredMethods() , Class.getMethods() |
Użytkownicy spoza pakietu SDK nie są uwzględniani w wynikach |
JNI używa env->GetFieldID() |
NULL zwrócone, NoSuchFieldError wyrzucone |
JNI używa env->GetMethodID() |
NULL zwrócone, NoSuchMethodError wyrzucone |
Testowanie aplikacji pod kątem interfejsów innych niż SDK
Aby sprawdzić, czy w aplikacji są używane interfejsy inne niż SDK, możesz użyć kilku metod.
Testowanie za pomocą aplikacji do debugowania
Interfejsy spoza pakietu SDK możesz testować, kompilując i uruchamiając aplikację z możliwością debugowania na urządzeniu lub emulatorze z Androidem 9 (poziom API 28) lub nowszym. Upewnij się, że używane urządzenie lub emulator odpowiada docelowemu poziomowi interfejsu API aplikacji.
Podczas testowania aplikacji system wypisuje komunikat logowania, jeśli aplikacja uzyskuje dostęp do określonych interfejsów innych niż SDK. W wiadomościach z dziennika aplikacji możesz znaleźć te informacje:
- Klasa deklarująca, nazwa i typ (w formacie używanym przez środowisko wykonawcze Androida).
- Sposób dostępu: linkowanie, korzystanie z odzwierciedlenia lub JNI.
- Do której listy należy interfejs inny niż SDK.
Aby uzyskać dostęp do tych komunikatów, możesz użyć adb logcat
. Pojawiają się one w sekcji PID uruchomionej aplikacji. Na przykład wpis w logu może wyglądać tak:
Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)
Testowanie za pomocą interfejsu StrictMode API
Interfejsy inne niż SDK możesz też testować za pomocą interfejsu API StrictMode
. Aby to zrobić, użyj metody detectNonSdkApiUsage
. Po włączeniu interfejsu API StrictMode
możesz otrzymywać wywołania zwrotne dla każdego użycia interfejsu spoza pakietu SDK, korzystając z interfejsu penaltyListener
, w którym możesz zaimplementować niestandardowe przetwarzanie. Obiekt Violation
podany w wywołaniu zwrotnym pochodzi z poziomu Throwable
, a załączony ślad stosu zawiera kontekst użycia.
Testowanie za pomocą narzędzia Veridex
Możesz też uruchomić na pliku APK narzędzie do analizy statycznej veridex. Narzędzie veridex skanuje cały kod źródłowy pliku APK, w tym wszystkie biblioteki innych firm, i zgłasza znalezione interfejsy spoza pakietu SDK.
Ograniczenia narzędzia veridex:
- Nie może wykrywać wywołań za pomocą JNI.
- Może wykryć tylko podzbiór wywołań za pomocą odbicia.
- Analiza nieaktywnych ścieżek kodu jest ograniczona do kontroli na poziomie interfejsu API.
- Może być uruchamiana tylko na maszynach obsługujących instrukcje SSE4.2 i POPCNT.
Windows
Natywne pliki binarne systemu Windows nie są dostarczane, ale możesz uruchomić narzędzie veridex w systemie Windows, wykonując pliki binarne systemu Linux za pomocą podsystemu Windows dla systemu Linux (WSL). Zanim wykonasz czynności opisane w tej sekcji, zainstaluj WSL i wybierz Ubuntu jako dystrybucję Linuksa.
Po zainstalowaniu Ubuntu uruchom terminal Ubuntu i wykonaj te czynności:
- Pobierz narzędzie veridex z repozytorium gotowych pakietów środowiska uruchomieniowego Androida.
- Wyodrębnij zawartość pliku
appcompat.tar.gz
. - W wyodrębnionym folderze odszukaj plik
veridex-linux.zip
i go wyodrębnij. Przejdź do rozpakowanego folderu, a potem uruchom to polecenie, gdzie
your-app.apk
to plik APK, który chcesz przetestować:./appcompat.sh --dex-file=your-app.apk
macOS,
Aby uruchomić narzędzie veridex w systemie macOS:
- Pobierz narzędzie veridex z repozytorium gotowych pakietów środowiska uruchomieniowego Androida.
- Wyodrębnij zawartość pliku
appcompat.tar.gz
. - W wyodrębnionym folderze odszukaj plik
veridex-mac.zip
i go wyodrębnij. Przejdź do rozpakowanego folderu, a potem uruchom podane niżej polecenie, w którym
/path-from-root/your-app.apk
to ścieżka do pliku APK, który chcesz przetestować, zaczynając od katalogu głównego systemu:./appcompat.sh --dex-file=/path-from-root/your-app.apk
Linux
Aby uruchomić narzędzie veridex w systemie Linux:
- Pobierz narzędzie veridex z repozytorium gotowych pakietów środowiska uruchomieniowego Androida.
- Wyodrębnij zawartość pliku
appcompat.tar.gz
. - W wyodrębnionym folderze odszukaj plik
veridex-linux.zip
i go wyodrębnij. Przejdź do rozpakowanego folderu, a potem uruchom to polecenie, gdzie
your-app.apk
to plik APK, który chcesz przetestować:./appcompat.sh --dex-file=your-app.apk
Testowanie za pomocą narzędzia lint w Android Studio
Za każdym razem, gdy kompilujesz aplikację w Android Studio, narzędzie lint sprawdza kod pod kątem potencjalnych problemów. Jeśli Twoja aplikacja korzysta z interfejsów innych niż SDK, mogą pojawić się błędy kompilacji lub ostrzeżenia, w zależności od tego, do której listy należą te interfejsy.
Możesz też uruchamiać narzędzie lint z poziomu wiersza poleceń lub ręcznie przeprowadzać inspekcje w określonym projekcie, folderze lub pliku.
Testowanie w Konsoli Play
Gdy prześlesz aplikację na ścieżkę testów w Konsoli Play, zostanie ona automatycznie przetestowana pod kątem potencjalnych problemów, a następnie wygenerowany zostanie raport przed opublikowaniem. Jeśli Twoja aplikacja korzysta z interfejsów spoza pakietu SDK, w raporcie przed opublikowaniem pojawi się błąd lub ostrzeżenie, w zależności od listy, na której znajdują się te interfejsy.
Więcej informacji znajdziesz w sekcji „Zgodność z Androidem” w artykule Używanie raportów przed opublikowaniem do identyfikowania problemów.
Prośba o nowy publiczny interfejs API
Jeśli nie możesz znaleźć alternatywy dla interfejsu spoza pakietu SDK, który jest używany w Twojej aplikacji, możesz poprosić o nowy publiczny interfejs API, tworząc prośbę o dodanie funkcji w naszym systemie śledzenia problemów.
Podczas tworzenia prośby o dodanie funkcji podaj te informacje:
- Nieobsługiwany interfejs API, którego używasz, w tym pełny opis widoczny w wiadomości logcat
Accessing hidden ...
. - Dlaczego musisz używać tych interfejsów API, w tym szczegóły dotyczące funkcji wysokiego poziomu, do której są one potrzebne, a nie tylko szczegóły niskiego poziomu.
- Dlaczego żadne powiązane publiczne interfejsy API pakietu SDK nie są wystarczające do Twoich celów.
- wszelkie inne wypróbowane przez Ciebie alternatywy i uzasadnienie, dlaczego nie zadziałały.
Podając te informacje w prośbie o funkcję, zwiększasz prawdopodobieństwo udostępnienia nowego publicznego interfejsu API.
Inne pytania
Ta sekcja zawiera odpowiedzi na inne pytania, które często zadają deweloperzy:
Pytania ogólne
Jak Google może mieć pewność, że uwzględnia potrzeby wszystkich aplikacji za pomocą Issue Tracker?
Początkowe listy dla Androida 9 (poziom interfejsu API 28) zostały utworzone na podstawie statycznej analizy aplikacji, którą uzupełniono za pomocą tych metod:
- ręczne testowanie najlepszych aplikacji z Google Play i aplikacji spoza Google Play.
- raporty wewnętrzne
- automatyczne zbieranie danych od użytkowników wewnętrznych;
- raporty podglądu dla deweloperów,
- dodatkowa analiza statyczna, która została zaprojektowana tak, aby konserwatywnie uwzględniać więcej wyników fałszywie dodatnich.
Podczas oceny list w przypadku każdej nowej wersji bierzemy pod uwagę użycie interfejsu API oraz opinie deweloperów podawane w systemie śledzenia problemów.
Jak mogę włączyć dostęp do interfejsów innych niż SDK?
Na urządzeniach deweloperskich możesz włączyć dostęp do interfejsów spoza pakietu SDK, używając poleceń adb do zmiany zasad egzekwowania interfejsów API. Polecenia, których używasz, różnią się w zależności od poziomu interfejsu API. Te polecenia nie wymagają urządzenia z dostępem do roota.
- Android 10 (poziom 29 interfejsu API) lub nowszy
Aby włączyć dostęp, użyj tego polecenia adb
polecenie:
adb shell settings put global hidden_api_policy 1
Aby zresetować zasady egzekwowania interfejsu API do ustawień domyślnych, użyj tego polecenia:
adb shell settings delete global hidden_api_policy
- Android 9 (poziom 28 interfejsu API)
Aby włączyć dostęp, użyj tych poleceń adb:
adb shell settings put global hidden_api_policy_pre_p_apps 1
adb shell settings put global hidden_api_policy_p_apps 1
Aby zresetować zasady egzekwowania interfejsu API do ustawień domyślnych, użyj tych poleceń:
adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps
Całkę w zasadach egzekwowania interfejsu API możesz ustawić na jedną z tych wartości:
- 0: wyłącza wykrywanie wszystkich interfejsów innych niż SDK. To ustawienie wyłącza wszystkie komunikaty logowania dotyczące użycia interfejsu spoza pakietu SDK i uniemożliwi testowanie aplikacji za pomocą interfejsu API
StrictMode
. Nie zalecamy tego ustawienia. - 1: włącz dostęp do wszystkich interfejsów innych niż SDK, ale wypisuj komunikaty logowania z ostrzeżeniami dotyczącymi użycia interfejsu innego niż SDK; Dzięki temu ustawieniu możesz też przetestować swoją aplikację za pomocą interfejsu API
StrictMode
. - 2. Zakaz użycia interfejsów spoza pakietu SDK, które znajdują się na liście zablokowanych lub są bezwarunkowo zablokowane na docelowym poziomie interfejsu API.
Pytania dotyczące list interfejsów innych niż SDK
Gdzie w pliku obrazu systemu znajdę listy interfejsów API innych niż SDK?
Są one zakodowane w bitach flagi dostępu do pola i metody w plikach dex platformy. W pliku obrazu systemu nie ma osobnego pliku z tymi listami.
Czy listy interfejsów API innych niż SDK są takie same na różnych urządzeniach OEM z tymi samymi wersjami Androida?
Producenci OEM mogą dodawać własne interfejsy do listy blokowania (czarnej listy), ale nie mogą usuwać interfejsów z list interfejsów AOSP innych niż interfejsy SDK. CDD zapobiega takim zmianom, a testy CTS zapewniają, że środowisko uruchomieniowe Androida egzekwuje tę listę.
Pytania dotyczące zgodności powiązanych aplikacji
Czy w kodzie natywnym są jakieś ograniczenia dotyczące interfejsów innych niż NDK?
Pakiet SDK Androida zawiera interfejsy Java. W Androidzie 7 (poziom API 26) platforma zaczęła ograniczać dostęp do interfejsów spoza NDK w przypadku natywnego kodu C/C++. Więcej informacji znajdziesz w artykule Poprawa stabilności dzięki ograniczeniom symboli prywatnych C/C++ w Androidzie N.
Czy planujecie ograniczyć manipulowanie plikami dex2oat lub DEX?
Nie mamy obecnie planów, aby ograniczać dostęp do binarnego pliku dex2oat, ale nie zamierzamy też, aby format pliku DEX był stabilny lub interfejsem publicznym poza częściami, które są publicznie określone w formacie wykonywalnym Dalvik. Zastrzegamy sobie prawo do zmiany lub usunięcia dex2oat i nieokreślonych części formatu DEX w dowolnym momencie. Pamiętaj też, że pliki pochodne utworzone przez dex2oat, takie jak ODEX (znany też jako OAT), VDEX i CDEX, są formatami nieokreślonymi.
Co zrobić, jeśli kluczowy pakiet SDK innej firmy (np. narzędzie do zaciemniania) nie może używać interfejsów spoza pakietu SDK, ale zobowiązuje się do zachowania zgodności z przyszłymi wersjami Androida? Czy w tym przypadku Android może zrezygnować z wymagań dotyczących zgodności?
Nie planujemy rezygnacji z wymagań dotyczących zgodności w przypadku poszczególnych pakietów SDK. Jeśli deweloper pakietu SDK może zachować zgodność tylko dzięki interfejsom z listy nieobsługiwanych (dawniej szarych), powinien zacząć planować migrację do interfejsów SDK lub innych alternatyw i poprosić o nowy publiczny interfejs API, gdy nie może znaleźć alternatywy dla interfejsu innego niż SDK.
Czy ograniczenia interfejsu niebędącego pakietem SDK dotyczą wszystkich aplikacji, w tym aplikacji systemowych i własnych, a nie tylko aplikacji innych firm?
Tak, ale nie dotyczy to aplikacji podpisanych kluczem platformy i niektórych aplikacji z obrazem systemu. Pamiętaj, że te wyjątki dotyczą tylko aplikacji, które są częścią obrazu systemu (lub zaktualizowanych aplikacji obrazu systemu). Lista jest przeznaczona tylko do aplikacji, które korzystają z interfejsów API prywatnej platformy, a nie z interfejsów API pakietu SDK (gdzie LOCAL_PRIVATE_PLATFORM_APIS := true
).