Ограничения на интерфейсы, отличные от SDK

Начиная с Android 9 (уровень API 28), платформа ограничивает использование вашим приложением интерфейсов, не относящихся к SDK. Эти ограничения применяются всякий раз, когда приложение ссылается на интерфейс, не относящийся к SDK, или пытается получить его дескриптор с помощью рефлексии или JNI. Эти ограничения были введены для улучшения взаимодействия с пользователями и разработчиками, а также для снижения риска сбоев для пользователей и экстренных развёртываний для разработчиков. Подробнее об этом решении см. в статье «Повышение стабильности за счёт сокращения использования интерфейсов, не относящихся к SDK» .

Различия между интерфейсами SDK и не-SDK

Как правило, публичные интерфейсы SDK — это те, которые описаны в индексе пакетов Android. Обработка интерфейсов, не относящихся к SDK, — это деталь реализации, которую API абстрагирует, поэтому эти интерфейсы могут быть изменены без предварительного уведомления.

Во избежание сбоев и непредвиденного поведения приложения должны использовать только официально документированные части классов в SDK. Это также означает, что при взаимодействии с классом с помощью таких механизмов, как рефлексия, не следует обращаться к методам или полям, не перечисленным в SDK.

Списки API, не входящих в SDK

С каждым релизом Android ограничивается использование дополнительных интерфейсов, не входящих в SDK. Мы знаем, что эти ограничения могут повлиять на ваш рабочий процесс выпуска, и хотим убедиться, что у вас есть инструменты для обнаружения использования интерфейсов, не входящих в SDK, возможность оставить отзыв и время для планирования и адаптации к новым политикам.

Чтобы минимизировать влияние ограничений, не связанных с SDK, на процесс разработки, интерфейсы, не связанные с SDK, разделены на списки, определяющие степень ограничения их использования в зависимости от целевого уровня API. В следующей таблице описан каждый из этих списков:

Список Теги кода Описание
Черный список
  • blocked
  • Устаревшее: blacklist
Интерфейсы, не входящие в SDK, которые нельзя использовать независимо от целевого уровня API вашего приложения. Если ваше приложение попытается получить доступ к одному из этих интерфейсов, система выдаст ошибку .
Условно заблокирован
  • max-target-x
  • Устаревшее: greylist-max-x

Начиная с Android 9 (уровень API 28), каждый уровень API имеет интерфейсы, не относящиеся к SDK, которые ограничиваются, когда приложение нацелено на этот уровень API.

Эти списки помечены максимальным уровнем API ( max-target-x ), на который приложение может ориентироваться, прежде чем оно потеряет доступ к интерфейсам, не относящимся к SDK, из этого списка. Например, интерфейс, не относящийся к SDK, который не был заблокирован в Android Pie, но теперь заблокирован в Android 10, входит в список max-target-p ( greylist-max-p ), где «p» означает Pie или Android 9 (уровень API 28).

Если ваше приложение пытается получить доступ к интерфейсу, который ограничен для вашего целевого уровня API, система ведет себя так, как будто API входит в черный список .

Не поддерживается
  • unsupported
  • Устаревшее: greylist
Интерфейсы, не входящие в SDK, которые не имеют ограничений и могут использоваться вашим приложением. Обратите внимание, что эти интерфейсы не поддерживаются и могут быть изменены без предварительного уведомления. Ожидается, что в будущих версиях Android эти интерфейсы будут условно заблокированы в списке max-target-x .
SDK
  • И public-api , и sdk
  • Устаревшие: как public-api , так и whitelist
Интерфейсы, которые можно свободно использовать и которые теперь поддерживаются как часть официально документированного индекса пакетов Android.
Тестовые API
  • test-api
Интерфейсы, используемые для внутреннего тестирования системы, например, API, упрощающие тестирование с помощью Compatibility Test Suite (CTS). Тестовые API не входят в состав SDK. Начиная с Android 11 (уровень API 30) , тестовые API включены в черный список, поэтому приложениям запрещено использовать их независимо от целевого уровня API. Все тестовые API не поддерживаются и могут быть изменены без предварительного уведомления, независимо от уровня API платформы.

Хотя вы можете использовать некоторые интерфейсы, не относящиеся к SDK (в зависимости от целевого уровня API вашего приложения), использование любого метода или поля, не относящегося к SDK, всегда сопряжено с высоким риском выхода приложения из строя. Если ваше приложение использует интерфейсы, не относящиеся к SDK, вам следует начать планировать миграцию на интерфейсы SDK или другие альтернативы. Если вы не можете найти альтернативу использованию интерфейса, не относящегося к SDK, для какой-либо функции вашего приложения, вам следует запросить новый публичный API .

Определить, к какому списку принадлежит интерфейс

Списки интерфейсов, не входящих в SDK, формируются как часть платформы. Информация о каждой версии Android представлена ​​в следующих разделах.

Андроид 16

Для Android 16 (уровень API 36) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: 9102af02fe6ab68b92464bdff5e5b09f3bd62c65d1130aaf85d3296f17d38074

Дополнительную информацию об изменениях в списке API, не входящих в SDK, в Android 16 см. в разделе Обновления ограничений интерфейсов, не входящих в SDK, в Android 16 .

Андроид 15

Для Android 15 (уровень API 35) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: 40134e205e58922a708c453726b279a296e6a1f34a988abd90cec0f3432ea5a9

Дополнительную информацию об изменениях в списке API, не входящих в SDK, в Android 15 см. в разделе Обновления ограничений интерфейсов, не входящих в SDK, в Android 15 .

Андроид 14

Для Android 14 (уровень API 34) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: 7e00db074cbe51c51ff4b411f7b48e98692951395c5c17d069c822cc1d0eae0f

Дополнительную информацию об изменениях в списке API, не входящих в SDK, в Android 14 см. в разделе Обновления ограничений интерфейсов, не входящих в SDK, в Android 14 .

Андроид 13

Для Android 13 (уровень API 33) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: 233a277aa8ac475b6df61bffd95665d86aac6eb2ad187b90bf42a98f5f2a11a3

Дополнительную информацию об изменениях в списке API, не входящих в SDK, в Android 13, включая предлагаемые публичные альтернативы API для API, которые условно заблокированы в Android 13, см . в разделе Обновления ограничений интерфейсов, не входящих в SDK, в Android 13 .

Андроид 12

Для Android 12 (уровень API 31) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: 40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761

Дополнительную информацию об изменениях в списке API, не относящихся к SDK, в Android 12, включая предлагаемые публичные альтернативы API для API, которые условно заблокированы в Android 12, см. в разделе Изменения в списке для Android 12 .

Андроид 11

Для Android 11 (уровень API 30) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: a19d839f4f61dc9c94960ae977b2e0f3eb30f880ba1ffe5108e790010b477a56

Дополнительную информацию об изменениях в списке API, не относящихся к SDK, в Android 11, включая предлагаемые публичные альтернативы API для API, которые условно заблокированы в Android 11, см. в разделе Изменения в списке для Android 11 .

Андроид 10

Для Android 10 (уровень API 29) вы можете загрузить следующий файл, в котором описываются все интерфейсы, не входящие в SDK, и соответствующие им списки:

Файл: hiddenapi-flags.csv

Контрольная сумма SHA-256: f22a59c215e752777a114bd9b07b0b6b4aedfc8e49e6efca0f99681771c5bfeb

Дополнительную информацию об изменениях в списке API, не относящихся к SDK, в Android 10, включая предлагаемые публичные альтернативы API для API, которые условно заблокированы в Android 10, см. в разделе Изменения в списке для Android 10 .

Андроид 9

Для Android 9 (уровень API 28) следующий текстовый файл содержит список API, не входящих в SDK, которые не ограничены (занесены в серый список): hiddenapi-light-greylist.txt .

Список заблокированных ( blacklist ) и список условно заблокированных API (темно-серый список) формируются во время сборки.

Генерация списков из AOSP

При работе с AOSP вы можете создать файл hiddenapi-flags.csv , содержащий все интерфейсы, не входящие в SDK, и их соответствующие списки. Для этого скачайте исходный код AOSP и выполните следующую команду:

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

Затем вы сможете найти файл в следующем месте:

out/soong/hiddenapi/hiddenapi-flags.csv

Ожидаемое поведение при доступе к ограниченным интерфейсам, не входящим в SDK

В следующей таблице описывается поведение, которого можно ожидать, если ваше приложение попытается получить доступ к интерфейсу, не являющемуся SDK, но входящему в черный список.

Средства доступа Результат
Инструкция Dalvik, ссылающаяся на поле Выдана ошибка NoSuchFieldError
Инструкция Dalvik, ссылающаяся на метод Выдана ошибка NoSuchMethodError
Отражение с использованием Class.getDeclaredField() или Class.getField() Выдано исключение NoSuchFieldException
Рефлексия с использованием Class.getDeclaredMethod() , Class.getMethod() Выдано исключение NoSuchMethodException
Отражение с использованием Class.getDeclaredFields() , Class.getFields() Не-члены SDK не включены в результаты
Рефлексия с использованием Class.getDeclaredMethods() , Class.getMethods() Не-члены SDK не включены в результаты
JNI с использованием env->GetFieldID() Возвращено NULL , выдано NoSuchFieldError
JNI с использованием env->GetMethodID() Возвращен NULL , выдан NoSuchMethodError

Протестируйте свое приложение на наличие интерфейсов, не относящихся к SDK

Существует несколько методов, которые можно использовать для тестирования интерфейсов, не относящихся к SDK, в вашем приложении.

Тестирование с использованием отлаживаемого приложения

Вы можете протестировать интерфейсы, не относящиеся к SDK, создав и запустив отлаживаемое приложение на устройстве или эмуляторе под управлением Android 9 (уровень API 28) или выше. Убедитесь, что используемое устройство или эмулятор соответствует целевому уровню API вашего приложения.

При выполнении тестов вашего приложения система выводит сообщение журнала, если приложение обращается к определённым интерфейсам, не относящимся к SDK. Вы можете просмотреть сообщения журнала приложения, чтобы найти следующую информацию:

  • Объявляющий класс, имя и тип (в формате, используемом средой выполнения Android).
  • Способы доступа: либо связывание, либо использование отражения, либо использование JNI.
  • К какому списку принадлежит не-SDK-интерфейс.

Вы можете использовать adb logcat для доступа к этим сообщениям журнала, которые отображаются под идентификатором процесса (PID) запущенного приложения. Например, запись в журнале может выглядеть следующим образом:

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

Тестирование с использованием StrictMode API

Вы также можете протестировать интерфейсы, не относящиеся к SDK, используя API StrictMode . Для этого используйте метод detectNonSdkApiUsage . После включения API StrictMode вы можете получать обратный вызов для каждого использования интерфейса, не относящегося к SDK, используя метод penaltyListener , в котором можно реализовать собственную обработку. Объект Violation , предоставляемый в обратном вызове, наследуется от Throwable , а приложенная трассировка стека предоставляет контекст использования.

Тест с использованием инструмента Veridex

Вы также можете запустить статический анализ вашего APK-файла Veridex. Инструмент Veridex сканирует всю кодовую базу APK-файла, включая все сторонние библиотеки, и сообщает о любых найденных случаях использования интерфейсов, не входящих в SDK.

Ограничения инструмента veridex включают следующее:

  • Он не может обнаружить вызовы через JNI.
  • Он может обнаружить только подмножество вызовов посредством отражения.
  • Анализ неактивных путей кода ограничивается проверками на уровне API.
  • Его можно запустить только на машинах, поддерживающих инструкции SSE4.2 и POPCNT.

Окна

Встроенные исполняемые файлы для Windows не предоставляются, но вы можете запустить инструмент Veridex в Windows, запустив исполняемые файлы Linux с помощью подсистемы Windows для Linux (WSL). Перед выполнением инструкций, описанных в этом разделе, установите WSL и выберите Ubuntu в качестве дистрибутива Linux.

После установки Ubuntu запустите терминал Ubuntu и выполните следующие действия:

  1. Загрузите инструмент veridex из репозитория готовых сборок среды выполнения Android.
  2. Извлеките содержимое файла appcompat.tar.gz .
  3. В извлеченной папке найдите файл veridex-linux.zip и распакуйте его.
  4. Перейдите в распакованную папку и выполните следующую команду, где your-app.apk — это APK-файл, который вы хотите протестировать:

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

macOS

Чтобы запустить инструмент veridex на macOS, выполните следующие действия:

  1. Загрузите инструмент veridex из репозитория готовых сборок среды выполнения Android.
  2. Извлеките содержимое файла appcompat.tar.gz .
  3. В извлеченной папке найдите файл veridex-mac.zip и извлеките его.
  4. Перейдите в распакованную папку и выполните следующую команду, где /path-from-root/your-app.apk — это путь к APK-файлу, который вы хотите протестировать, начиная с корневого каталога вашей системы:

    ./appcompat.sh --dex-file=/path-from-root/your-app.apk
    

Линукс

Чтобы запустить инструмент veridex в Linux, выполните следующие действия:

  1. Загрузите инструмент veridex из репозитория готовых сборок среды выполнения Android.
  2. Извлеките содержимое файла appcompat.tar.gz .
  3. В извлеченной папке найдите файл veridex-linux.zip и распакуйте его.
  4. Перейдите в распакованную папку и выполните следующую команду, где your-app.apk — это APK-файл, который вы хотите протестировать:

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

Тестирование с помощью инструмента Android Studio lint

При каждой сборке приложения в Android Studio инструмент lint проверяет ваш код на наличие потенциальных проблем. Если ваше приложение использует интерфейсы, не относящиеся к SDK, вы можете увидеть ошибки сборки или предупреждения в зависимости от того, к какому списку относятся эти интерфейсы.

Вы также можете запустить инструмент lint из командной строки или вручную запустить проверку определенного проекта, папки или файла.

Тест с использованием Play Console

При загрузке приложения в тестовую версию Play Console оно автоматически тестируется на наличие потенциальных проблем, и формируется отчёт о предзапуске. Если ваше приложение использует интерфейсы, не относящиеся к SDK, в отчёте о предзапуске отображается ошибка или предупреждение в зависимости от того, к какому списку относятся эти интерфейсы.

Дополнительную информацию см. в разделе «Совместимость с Android» статьи Использование отчетов о предварительных запусках для выявления проблем .

Запросить новый публичный API

Если вы не можете найти альтернативу использованию интерфейса, отличного от SDK, для функции вашего приложения, вы можете запросить новый публичный API, создав запрос на функцию в нашей системе отслеживания ошибок.

При создании запроса на функцию предоставьте следующую информацию:

  • Какой неподдерживаемый API вы используете, включая полный дескриптор, указанный в сообщении Accessing hidden ... logcat.
  • Почему вам нужно использовать эти API, включая сведения о высокоуровневых функциях, для которых необходим API, а не только низкоуровневые детали.
  • Почему любые связанные публичные API SDK недостаточны для ваших целей.
  • Пробовали ли вы другие альтернативы и почему они не сработали?

Предоставляя эти данные в запросе на функцию, вы увеличиваете вероятность предоставления нового публичного API.

Другие вопросы

В этом разделе приведены ответы на некоторые вопросы, которые часто задают разработчики:

Общие вопросы

Как Google может быть уверена, что сможет отслеживать потребности всех приложений с помощью IssueTracker?

Первоначальные списки для Android 9 (уровень API 28) были созданы путем статического анализа приложений, который был дополнен с использованием следующих методов:

  • ручное тестирование лучших приложений Play и не Play
  • внутренние отчеты
  • автоматический сбор данных от внутренних пользователей
  • предварительные отчеты для разработчиков
  • дополнительный статический анализ, который был разработан для консервативного включения большего количества ложноположительных результатов

При оценке списков для каждого нового выпуска мы учитываем использование API, а также отзывы разработчиков через систему отслеживания ошибок.

Как включить доступ к интерфейсам, не относящимся к SDK?

Вы можете включить доступ к интерфейсам, не относящимся к SDK, на устройствах разработки, используя команды adb для изменения политики принудительного использования API. Набор используемых команд зависит от уровня API. Для этих команд не требуется устройство с правами root.

Android 10 (уровень API 29) или выше

Чтобы включить доступ, используйте следующую команду adb

команда:

adb shell settings put global hidden_api_policy  1

Чтобы сбросить политику принудительного использования API до настроек по умолчанию, используйте следующую команду:

adb shell settings delete global hidden_api_policy
Android 9 (уровень API 28)

Чтобы включить доступ, используйте следующие команды adb:

adb shell settings put global hidden_api_policy_pre_p_apps  1
adb shell settings put global hidden_api_policy_p_apps 1

Чтобы сбросить политику принудительного использования API до настроек по умолчанию, используйте следующие команды:

adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps

В политике принудительного использования API можно задать целое число на одно из следующих значений:

  • 0: отключить обнаружение всех интерфейсов, не относящихся к SDK. Использование этого параметра отключает все сообщения журнала об использовании интерфейсов, не относящихся к SDK, и запрещает тестирование приложения с использованием StrictMode API . Использовать этот параметр не рекомендуется.
  • 1: Разрешить доступ ко всем интерфейсам, не относящимся к SDK, но выводить сообщения журнала с предупреждениями при использовании любого интерфейса, не относящегося к SDK. Этот параметр также позволяет тестировать приложение с использованием StrictMode API .
  • 2: Запретить использование интерфейсов, не относящихся к SDK, которые входят в черный список или условно заблокированы для вашего целевого уровня API .

Вопросы о списках интерфейсов, не входящих в SDK

Где я могу найти списки API, не входящих в SDK, в образе системы?

Они закодированы в битах флагов доступа к полям и методам в dex-файлах платформы. В образе системы нет отдельного файла, содержащего эти списки.

Одинаковы ли списки API, не входящих в SDK, на разных OEM-устройствах с одинаковыми версиями Android?

OEM-производители могут добавлять собственные интерфейсы в чёрный список (чёрный список), но не могут удалять интерфейсы из списков API AOSP, не входящих в SDK. CDD предотвращает такие изменения, а тесты CTS гарантируют, что среда выполнения Android Runtime соблюдает требования списка.

Существуют ли какие-либо ограничения на использование не-NDK-интерфейсов в нативном коде?

Android SDK включает интерфейсы Java. Платформа начала ограничивать доступ к интерфейсам, не входящим в NDK, для нативного кода C/C++ в Android 7 (уровень API 26). Подробнее см. в статье «Улучшение стабильности с помощью ограничений на использование частных символов C/C++ в Android N» .

Планируется ли ограничить манипуляции с файлами dex2oat или DEX?

Мы не планируем ограничивать доступ к исполняемому файлу dex2oat, но не планируем делать формат файла DEX стабильным или предоставлять общедоступный интерфейс за пределами частей, публично указанных в формате исполняемого файла Dalvik . Мы оставляем за собой право изменять или удалять dex2oat и неуказанные части формата DEX в любое время. Также обратите внимание, что производные файлы, создаваемые dex2oat, такие как ODEX (также известный как OAT), VDEX и CDEX, имеют неуказанные форматы.

Что делать, если критически важный сторонний SDK (например, обфускатор) не может избежать использования интерфейсов, не входящих в SDK, но обязуется поддерживать совместимость с будущими версиями Android? Может ли Android отказаться от своих требований совместимости в этом случае?

Мы не планируем отказываться от требований совместимости для каждого SDK. Если разработчик SDK может поддерживать совместимость только с помощью интерфейсов из неподдерживаемых (ранее серых) списков, ему следует начать планировать миграцию на интерфейсы SDK или другие альтернативы, а также запрашивать новый публичный API всякий раз, когда он не может найти альтернативу использованию интерфейса, не входящего в SDK.

Распространяются ли ограничения интерфейса, не относящегося к SDK, на все приложения, включая системные и сторонние приложения, а не только на сторонние приложения?

Да, однако мы не распространяется на приложения, подписанные ключом платформы, и некоторые приложения из образа системы. Обратите внимание, что эти исключения применяются только к приложениям, входящим в состав образа системы (или к приложениям из обновлённого образа системы). Список предназначен только для приложений, разработанных с использованием API частных платформ, а не API SDK (где LOCAL_PRIVATE_PLATFORM_APIS := true ).