Ograniczenia dotyczące interfejsów spoza SDK

Począwszy od Androida 9 (poziom interfejsu API 28) platforma ogranicza dostępność interfejsów innych niż SDK w aplikacji. Ograniczenia te obowiązują zawsze, gdy aplikacja odwołuje się do interfejsu innego niż SDK lub próbuje uzyskać nick za pomocą interfejsu Reflektion lub JNI. Wprowadziliśmy te ograniczenia, aby zwiększyć wygodę użytkowników i programistów oraz zmniejszyć ryzyko awarii u użytkowników i awaryjne wdrażanie awaryjne. Więcej informacji o tej decyzji znajdziesz w artykule Poprawa stabilności przez ograniczenie korzystania z interfejsów innych niż SDK.

Różnice między interfejsami SDK i innymi niż SDK

Ogólnie rzecz biorąc, publiczne interfejsy SDK to te, które są wymienione na platformie Android Package Index. Obsługa interfejsów innych niż SDK to szczegóły implementacji, które są pomijane przez interfejs API, dlatego mogą one ulec zmianie bez powiadomienia.

Aby uniknąć awarii i nieoczekiwanego działania, aplikacje powinny korzystać tylko z oficjalnie udokumentowanych części klas z pakietu SDK. Oznacza to też, że podczas interakcji z klasą za pomocą mechanizmów takich jak odbicie nie należy korzystać z metod ani pól, których nie ma w pakiecie SDK.

Listy interfejsów API spoza pakietu SDK

W każdej wersji Androida dodatkowe interfejsy inne niż SDK są ograniczone. Wiemy, że te ograniczenia mogą wpływać na przepływ pracy przy tworzeniu, dlatego chcemy zapewnić Ci narzędzia do wykrywania użycia interfejsów innych niż SDK, możliwość przekazania nam opinii oraz czas na zaplanowanie nowych zasad i dostosowanie się do nich.

Aby zminimalizować wpływ ograniczeń niezwiązanych z pakietem SDK na przepływ pracy w programie, interfejsy inne niż SDK są podzielone na listy, które definiują ścisłe ograniczenia ich wykorzystania w zależności od docelowego poziomu interfejsu API. Każdą z tych list znajdziesz w poniższej tabeli:

Lista Tagi kodu Opis
Lista zablokowanych
  • blocked
  • Wycofane: blacklist
Interfejsy inne niż SDK, których nie można używać niezależnie od docelowego poziomu interfejsu API aplikacji. Jeśli aplikacja spróbuje uzyskać dostęp do jednego z tych interfejsów, system zgłosi błąd.
Zablokowane warunkowo
  • max-target-x
  • Wycofane: greylist-max-x

Począwszy od Androida 9 (poziom interfejsu API 28) każdy poziom interfejsu API ma interfejsy inne niż SDK, które są ograniczone, gdy aplikacja jest kierowana na ten poziom API.

Listy te są oznaczone maksymalnym poziomem interfejsu API (max-target-x), na który aplikacja może kierować reklamy, zanim aplikacja utraci dostęp do interfejsów innych niż SDK znajdujących się na tej liście. Na przykład interfejs inny niż SDK, który nie został zablokowany w Androidzie Pie, ale jest teraz zablokowany w Androidzie 10, jest częścią listy max-target-p (greylist-max-p), gdzie „p” oznacza Pie lub Android 9 (poziom interfejsu API 28).

Jeśli aplikacja próbuje uzyskać dostęp do interfejsu, który jest ograniczony do docelowego poziomu interfejsu API, system zachowuje się tak, jakby ten interfejs API był częścią listy zablokowanych.

Nieobsługiwane
  • unsupported
  • Wycofane: greylist
Interfejsy inne niż SDK, które nie mają ograniczeń i mogą być używane przez Twoją aplikację. Pamiętaj jednak, że te interfejsy nie są obsługiwane i mogą ulec zmianie bez powiadomienia. W przyszłych wersjach Androida te interfejsy będą warunkowo blokowane na liście max-target-x.
Pakiet SDK
  • Zarówno public-api, jak i sdk
  • Wycofane: zarówno public-api, jak i whitelist
Interfejsy, z których można swobodnie korzystać i które są teraz obsługiwane w ramach oficjalnie udokumentowanej platformy Androida Package Index.
Testuj interfejsy API
  • test-api
Interfejsy używane do wewnętrznego testowania systemu, takie jak interfejsy API umożliwiające testowanie w pakiecie CTS (Compatibility Test Suite). Testowe interfejsy API nie należą do pakietu SDK. Począwszy od Androida 11 (poziom interfejsu API 30) testowe interfejsy API są uwzględniane na liście zablokowanych, 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 korzystać z niektórych interfejsów spoza pakietu SDK (w zależności od docelowego poziomu interfejsu API aplikacji), użycie dowolnej metody lub pola spoza pakietu SDK zawsze wiąże się z dużym ryzykiem uszkodzenia aplikacji. Jeśli Twoja aplikacja korzysta z interfejsów innych niż SDK, warto zacząć planować migrację do interfejsów SDK lub innych rozwiązań. Jeśli nie możesz znaleźć w swojej aplikacji alternatywy dla interfejsu innego niż SDK, możesz poprosić o nowy publiczny interfejs API.

Określ, do której listy należy interfejs

Listy interfejsów innych niż SDK są tworzone w ramach platformy. W kolejnych sekcjach znajdziesz informacje o każdej wersji Androida.

Android 15

W przypadku Androida 15 (poziom interfejsu API 35) możesz pobrać ten plik opisujący wszystkie interfejsy inne niż SDK oraz odpowiadające im listy:

Plik: hiddenapi-flags.csv

Suma kontrolna SHA-256: 40134e205e58922a708c453726b279a296e6a1f34a988abd90cec0f3432ea5a9

Aby dowiedzieć się więcej o zmianach dotyczących list interfejsów API niezwiązanych z pakietem SDK w Androidzie 15, przeczytaj artykuł Aktualizacje ograniczeń interfejsu spoza SDK w Androidzie 15.

Android 14

W przypadku Androida 14 (poziom interfejsu API 34) możesz pobrać ten plik opisujący wszystkie interfejsy inne niż SDK oraz odpowiadające im listy:

Plik: hiddenapi-flags.csv

Suma kontrolna SHA-256: 7e00db074cbe51c51ff4b411f7b48e98692951395c5c17d069c822cc1d0eae0f

Więcej informacji o zmianach dotyczących list interfejsów API niezwiązanych z pakietem SDK w Androidzie 14 znajdziesz w artykule Aktualizacje ograniczeń interfejsu spoza SDK w Androidzie 14.

Android 13

W przypadku Androida 13 (poziom interfejsu API 33) możesz pobrać ten plik opisujący wszystkie interfejsy inne niż SDK oraz odpowiadające im listy:

Plik: hiddenapi-flags.csv

Suma kontrolna SHA-256: 233a277aa8ac475b6df61bffd95665d86aac6eb2ad187b90bf42a98f5f2a11a3

Więcej informacji o zmianach na liście interfejsów API innych niż SDK w Androidzie 13, w tym o sugerowanych publicznych alternatywach dla interfejsów API, które są warunkowo blokowane w Androidzie 13, znajdziesz w artykule Aktualizacje ograniczeń interfejsu innego niż SDK w Androidzie 13.

Android 12

W przypadku Androida 12 (poziom interfejsu API 31) możesz pobrać ten plik opisujący wszystkie interfejsy inne niż SDK oraz odpowiadające im listy:

Plik: hiddenapi-flags.csv

Suma kontrolna SHA-256: 40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761

Więcej informacji o zmianach na liście interfejsów API innych niż SDK w Androidzie 12, w tym o sugerowanych alternatywnych alternatywnych interfejsach API dla interfejsów API, które są warunkowo blokowane w Androidzie 12, znajdziesz w artykule Lista zmian na Androidzie 12.

Android 11

W przypadku Androida 11 (poziom interfejsu API 30) możesz pobrać ten plik opisujący wszystkie interfejsy inne niż SDK oraz odpowiadające im listy:

Plik: hiddenapi-flags.csv

Suma kontrolna SHA-256: a19d839f4f61dc9c94960ae977b2e0f3eb30f880ba1ffe5108e790010b477a56

Więcej informacji o zmianach dotyczących list interfejsów API niezwiązanych z pakietem SDK w Androidzie 11, w tym o sugerowanych publicznych alternatywach dla interfejsów API, które są warunkowo blokowane w Androidzie 11, znajdziesz w artykule Lista zmian na Androidzie 11.

Android 10

W przypadku Androida 10 (poziom interfejsu API 29) możesz pobrać ten plik opisujący wszystkie interfejsy inne niż SDK oraz odpowiadające im listy:

Plik: hiddenapi-flags.csv

Suma kontrolna SHA-256: f22a59c215e752777a114bd9b07b0b6b4aedfc8e49e6efca0f99681771c5bfeb

Więcej informacji o zmianach na liście interfejsów API spoza pakietu SDK w Androidzie 10, w tym o sugerowanych alternatywnych alternatywnych interfejsach API dla interfejsów API, które są warunkowo blokowane w Androidzie 10, znajdziesz w artykule Lista zmian w Androidzie 10.

Android 9

W przypadku Androida 9 (poziom interfejsu API 28) poniższy plik tekstowy zawiera listę interfejsów API innych niż SDK, które nie są objęte ograniczeniami (szara lista): hiddenapi-light-greylist.txt.

Lista zablokowanych (blacklist) i lista warunkowo zablokowanych interfejsów API (ciemnoszara lista) są ustalane w czasie kompilacji.

Generuj listy z AOSP

Podczas pracy z AOSP możesz wygenerować plik hiddenapi-flags.csv zawierający wszystkie interfejsy inne niż SDK oraz odpowiadające im listy. W tym celu pobierz źródło AOSP i uruchom to polecenie:

m out/soong/hiddenapi/hiddenapi-flags.csv

Znajdziesz go w tej lokalizacji:

out/soong/hiddenapi/hiddenapi-flags.csv

Oczekiwane działanie przy dostępie do ograniczonych interfejsów spoza pakietu SDK

W tabeli poniżej opisano zachowanie, którego możesz się spodziewać, jeśli aplikacja próbuje uzyskać dostęp do interfejsu innego niż SDK, który znajduje się na liście zablokowanych.

Metody dostępu Wynik
Instrukcja Dalvik odnosząca się do pola NoSuchFieldError rzucony
Instrukcja Dalvik odnosząca się do metody NoSuchMethodError rzucony
Odbicie za pomocą Class.getDeclaredField() lub Class.getField() NoSuchFieldException rzucony
Odbicie z użyciem elementów Class.getDeclaredMethod(), Class.getMethod() NoSuchMethodException rzucony
Odbicie z użyciem elementów Class.getDeclaredFields(), Class.getFields() Użytkownicy, którzy nie korzystają z pakietu SDK, nie pojawiają się w wynikach
Odbicie z użyciem elementów Class.getDeclaredMethods(), Class.getMethods() Użytkownicy, którzy nie korzystają z pakietu SDK, nie pojawiają się w wynikach
JNI z env->GetFieldID() NULL zwrócone, NoSuchFieldError rzuca
JNI z env->GetMethodID() NULL zwrócone, NoSuchMethodError rzuca

Testowanie aplikacji pod kątem interfejsów innych niż SDK

Jest kilka metod, które możesz wykorzystać do przetestowania interfejsów innych niż SDK w swojej aplikacji.

Testowanie za pomocą aplikacji z możliwością debugowania

Aby przetestować interfejsy inne niż SDK, utwórz i uruchom aplikację z możliwością debugowania na urządzeniu lub w emulatorze z Androidem 9 (poziom interfejsu API 28) lub nowszym. Upewnij się, że używane urządzenie lub emulator jest zgodne z docelowym poziomem interfejsu API aplikacji.

Podczas testów aplikacji system wyświetla komunikat logu, jeśli uzyskuje ona dostęp do określonych interfejsów spoza pakietu SDK. Aby znaleźć te informacje, możesz przejrzeć komunikaty logu aplikacji:

  • Klasa, nazwa i typ deklarowania (w formacie używanym przez środowisko wykonawcze Androida).
  • Środki dostępu: połączenie, za pomocą refleksji lub JNI.
  • Do której listy należy interfejs inny niż SDK.

Aby uzyskać dostęp do tych komunikatów logu, które pojawiają się pod identyfikatorem PID uruchomionej aplikacji, możesz użyć polecenia adb logcat. Wpis w dzienniku może na przykład wyglądać tak:

Accessing hidden field Landroid/os/Message;->flags:I (light greylist, JNI)

Testowanie za pomocą interfejsu StrictMode API

Możesz też przeprowadzać testy w interfejsach innych niż SDK za pomocą interfejsu API StrictMode. Aby włączyć tę funkcję, użyj metody detectNonSdkApiUsage. Po włączeniu interfejsu API StrictMode możesz otrzymywać wywołania zwrotne dla każdego użycia interfejsu innego niż SDK za pomocą interfejsu penaltyListener, który umożliwia implementację niestandardowej obsługi. Obiekt Violation podany w wywołaniu zwrotnym pochodzi z Throwable, a załączony zrzut stosu przedstawia kontekst użycia.

Przetestuj za pomocą narzędzia Veridex

Możesz też uruchomić narzędzie do analizy statycznej Veridex. Narzędzie Veridex skanuje całą bazę kodu pliku APK, w tym biblioteki zewnętrzne, i zgłasza wszystkie przypadki użycia interfejsów innych niż SDK.

Ograniczenia narzędzia Weridex są następujące:

  • Nie udało się wykryć 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żna go uruchomić tylko na komputerach obsługujących instrukcje SSE4.2 i POPCNT.

Windows

Natywne pliki binarne systemu Windows nie są dostępne, ale narzędzie Veridex można uruchomić w systemie Windows, uruchamiając pliki binarne Linuksa przy użyciu podsystemu Windows (WSL). Zanim wykonasz czynności opisane w tej sekcji, zainstaluj WSL i wybierz Ubuntu jako dystrybucję Linuksa.

Po zainstalowaniu systemu Ubuntu uruchom terminal Ubuntu, a następnie wykonaj te czynności:

  1. Pobierz narzędzie Veridex z repozytorium gotowych komponentów środowiska wykonawczego Androida.
  2. Wyodrębnij zawartość pliku appcompat.tar.gz.
  3. W rozpakowanym folderze znajdź plik veridex-linux.zip i rozpakuj go.
  4. Przejdź do rozpakowanego folderu i uruchom to polecenie, w którym 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, wykonaj te czynności:

  1. Pobierz narzędzie Veridex z repozytorium gotowych komponentów środowiska wykonawczego Androida.
  2. Wyodrębnij zawartość pliku appcompat.tar.gz.
  3. W rozpakowanym folderze znajdź plik veridex-mac.zip i rozpakuj go.
  4. Przejdź do rozpakowanego folderu i uruchom to 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, wykonaj następujące czynności:

  1. Pobierz narzędzie Veridex z repozytorium gotowych komponentów środowiska wykonawczego Androida.
  2. Wyodrębnij zawartość pliku appcompat.tar.gz.
  3. W rozpakowanym folderze znajdź plik veridex-linux.zip i rozpakuj go.
  4. Przejdź do rozpakowanego folderu i uruchom to polecenie, w którym your-app.apk to plik APK, który chcesz przetestować:

    ./appcompat.sh --dex-file=your-app.apk
    

Testowanie za pomocą narzędzia Android Studio Linter

Za każdym razem, gdy tworzysz aplikację w Android Studio, narzędzie Lint pozwala sprawdzić kod pod kątem potencjalnych problemów. Jeśli Twoja aplikacja używa interfejsów innych niż SDK, możesz zobaczyć błędy lub ostrzeżenia o błędzie kompilacji w zależności od listy, do której należą te interfejsy.

Możesz też uruchomić narzędzie Lint z poziomu wiersza poleceń lub przeprowadzić inspekcji ręcznie w określonym projekcie, folderze lub pliku.

Testowanie w Konsoli Play

Gdy prześlesz aplikację na ścieżkę testów w Konsoli Play, jest ona automatycznie testowana pod kątem potencjalnych problemów i generowany jest raport przed opublikowaniem. Jeśli Twoja aplikacja używa interfejsów innych niż SDK, w zależności od listy, do której należą te interfejsy, w raporcie przed opublikowaniem pojawi się błąd lub ostrzeżenie.

Więcej informacji znajdziesz w sekcji Zgodność z Androidem w artykule Używanie raportów przed opublikowaniem do wykrywania problemów.

Poproś o nowy publiczny interfejs API

Jeśli dla danej funkcji nie możesz znaleźć alternatywy dla interfejsu innego niż SDK, możesz poprosić o nowy publiczny interfejs API, tworząc prośbę o dodanie funkcji w naszym narzędziu do śledzenia problemów.

Podczas tworzenia prośby o dodanie funkcji podaj te informacje:

  • Jakiego nieobsługiwanego interfejsu API używasz, w tym pełnego deskryptora widocznego w komunikacie logcat Accessing hidden ....
  • Dlaczego trzeba korzystać z tych interfejsów API, w tym szczegóły dotyczące ogólnej funkcji, do której jest potrzebny interfejs API, a nie tylko szczegółowych informacji.
  • Dlaczego powiązane publiczne interfejsy API pakietu SDK są niewystarczające do realizacji Twoich celów.
  • Wszelkie inne wypróbowane przez Ciebie rozwiązania i przyczyny niepowodzenia.

Podając te informacje w żądaniu funkcji, zwiększasz prawdopodobieństwo uzyskania nowego publicznego interfejsu API.

Inne pytania

W tej sekcji znajdziesz odpowiedzi na inne pytania zadane przez deweloperów:

Pytania ogólne

Jak Google może mieć pewność, że za pomocą narzędzia do śledzenia problemów będzie w stanie uwzględnić potrzeby wszystkich aplikacji?

Utworzyliśmy wstępne listy dla Androida 9 (poziom interfejsu API 28) na podstawie statycznej analizy aplikacji, które zostały uzupełnione następującymi metodami:

  • ręczne testowanie najpopularniejszych aplikacji z Google Play i innych aplikacji
  • raporty wewnętrzne
  • automatyczne zbieranie danych od użytkowników wewnętrznych
  • raporty dotyczące wersji przedpremierowej dla programistów
  • dodatkową analizę statyczną, która miała konserwatywnie uwzględnić więcej wyników fałszywie pozytywnych

Oceniając listy każdej nowej wersji, bierzemy pod uwagę wykorzystanie interfejsu API oraz opinie deweloperów w narzędziu do śledzenia problemów.

Jak mogę włączyć dostęp do interfejsów innych niż SDK?

Możesz włączyć dostęp do interfejsów innych niż SDK na urządzeniach, których używasz do programowania, zmieniając zasadę egzekwowania interfejsu API za pomocą poleceń adb. Używane polecenia 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 interfejsu API 29) lub nowszy

Aby włączyć dostęp, użyj tego narzędzia adb

polecenie:

adb shell settings put global hidden_api_policy  1

Aby zresetować zasadę 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ć zasadę 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

W zasadzie egzekwowania interfejsu API możesz ustawić jedną z tych wartości na liczbę całkowitą:

  • 0. Wyłącz wykrywanie interfejsów innych niż SDK. To ustawienie wyłącza wszystkie komunikaty logu dotyczące korzystania z interfejsu innego niż SDK i uniemożliwia testowanie aplikacji za pomocą interfejsu API StrictMode. To ustawienie nie jest zalecane.
  • 1. Włącz dostęp do wszystkich interfejsów spoza SDK, ale drukuj komunikaty logu z ostrzeżeniami dotyczącymi korzystania z tych interfejsów. To ustawienie umożliwia też testowanie aplikacji za pomocą interfejsu API StrictMode.
  • 2. Nie zezwalaj na korzystanie z interfejsów innych niż SDK, które znajdują się na liście zablokowanych lub są warunkowo zablokowane na docelowym poziomie interfejsu API.

Pytania o listy interfejsów innych niż SDK

Gdzie znajdę w obrazie systemu listy interfejsów API spoza pakietu SDK?

Są one zakodowane w bitach flag dostępu pola i metod w plikach .dex platformy. W obrazie systemu nie ma osobnego pliku, który zawiera te listy.

Czy listy interfejsów API spoza pakietu SDK są takie same na różnych urządzeniach OEM z tą samą wersją Androida?

OEM może dodawać do listy zablokowanych (czarną) własne interfejsy, ale nie może usuwać interfejsów z list interfejsów innych niż SDK AOSP. CDD zapobiega takim zmianom, a testy CTS gwarantują, że środowisko wykonawcze Androida egzekwuje tę listę.

Czy są jakieś ograniczenia dotyczące interfejsów innych niż NDK w kodzie natywnym?

Pakiet Android SDK zawiera interfejsy Java. Platforma zaczęła ograniczać dostęp do interfejsów innych niż NDK w przypadku natywnego kodu C/C++ w Androidzie 7 (poziom API 26). Więcej informacji znajdziesz w artykule Poprawianie stabilności z ograniczeniami dotyczącymi prywatnych symboli C/C++ w Androidzie N.

Czy planujecie ograniczyć manipulowanie plikami dex2oat i DEX?

Nie planujemy ograniczyć dostępu do pliku binarnego dex2oat, ale nie zamierzamy, aby format plików DEX był stabilny ani nie stanowił publicznego interfejsu w postaci części publicznych określonych w formacie pliku wykonywalnego Daalvik. Zastrzegamy sobie prawo do zmodyfikowania lub usunięcia dex2oat i nieokreślonych części formatu DEX w dowolnym momencie. Pamiętaj też, że pliki derywowane generowane przez dex2oat, takie jak ODEX (znane też jako OAT), VDEX i CDEX, to formaty nieokreślone.

Co zrobić, jeśli kluczowy pakiet SDK innej firmy (np. zaciemniający) nie może uniknąć użycia interfejsów innych niż SDK, ale zobowiązuje się zachować zgodność z przyszłymi wersjami Androida? Czy w tym przypadku Android może zrezygnować z wymagań dotyczących zgodności?

Nie planujemy zrezygnować z wymagań dotyczących zgodności z poszczególnymi pakietami SDK. Jeśli deweloper pakietu SDK jest w stanie utrzymać zgodność tylko w zależności od interfejsów na nieobsługiwanych (dawniej szarych) listach, powinien zacząć planować migrację do interfejsów SDK lub innych rozwiązań alternatywnych i wysyłać prośbę o nowy publiczny interfejs API za każdym razem, gdy nie może znaleźć alternatywy dla interfejsu innego niż SDK.

Czy ograniczenia interfejsu innego niż SDK mają zastosowanie do wszystkich aplikacji, w tym aplikacji systemowych i aplikacji własnych, a nie tylko aplikacji innych firm?

Tak, jednak wykluczamy aplikacje podpisane kluczem platformy i niektóre aplikacje obrazu systemu. Te wyłączenia mają zastosowanie tylko do aplikacji będących częścią obrazu systemu (lub zaktualizowanych aplikacji z obrazem systemu). Ta lista jest przeznaczona tylko dla aplikacji, które tworzą interfejsy API platformy prywatnej, a nie interfejsy API pakietu SDK (gdzie LOCAL_PRIVATE_PLATFORM_APIS := true).