Начиная с Android 9 (уровень API 28), платформа ограничивает использование вашим приложением интерфейсов, не относящихся к SDK. Эти ограничения применяются всякий раз, когда приложение ссылается на интерфейс, не относящийся к SDK, или пытается получить его дескриптор с помощью рефлексии или JNI. Эти ограничения были введены для улучшения взаимодействия с пользователями и разработчиками, а также для снижения риска сбоев для пользователей и экстренных развёртываний для разработчиков. Подробнее об этом решении см. в статье «Повышение стабильности за счёт сокращения использования интерфейсов, не относящихся к SDK» .
Различия между интерфейсами SDK и не-SDK
Как правило, публичные интерфейсы SDK — это те, которые описаны в индексе пакетов Android. Обработка интерфейсов, не относящихся к SDK, — это деталь реализации, которую API абстрагирует, поэтому эти интерфейсы могут быть изменены без предварительного уведомления.
Во избежание сбоев и непредвиденного поведения приложения должны использовать только официально документированные части классов в SDK. Это также означает, что при взаимодействии с классом с помощью таких механизмов, как рефлексия, не следует обращаться к методам или полям, не перечисленным в SDK.
Списки API, не входящих в SDK
С каждым релизом Android ограничивается использование дополнительных интерфейсов, не входящих в SDK. Мы знаем, что эти ограничения могут повлиять на ваш рабочий процесс выпуска, и хотим убедиться, что у вас есть инструменты для обнаружения использования интерфейсов, не входящих в SDK, возможность оставить отзыв и время для планирования и адаптации к новым политикам.
Чтобы минимизировать влияние ограничений, не связанных с SDK, на процесс разработки, интерфейсы, не связанные с SDK, разделены на списки, определяющие степень ограничения их использования в зависимости от целевого уровня API. В следующей таблице описан каждый из этих списков:
Список | Теги кода | Описание |
---|---|---|
Черный список |
| Интерфейсы, не входящие в SDK, которые нельзя использовать независимо от целевого уровня API вашего приложения. Если ваше приложение попытается получить доступ к одному из этих интерфейсов, система выдаст ошибку . |
Условно заблокирован |
| Начиная с Android 9 (уровень API 28), каждый уровень API имеет интерфейсы, не относящиеся к SDK, которые ограничиваются, когда приложение нацелено на этот уровень API. Эти списки помечены максимальным уровнем API ( Если ваше приложение пытается получить доступ к интерфейсу, который ограничен для вашего целевого уровня API, система ведет себя так, как будто API входит в черный список . |
Не поддерживается |
| Интерфейсы, не входящие в SDK, которые не имеют ограничений и могут использоваться вашим приложением. Обратите внимание, что эти интерфейсы не поддерживаются и могут быть изменены без предварительного уведомления. Ожидается, что в будущих версиях Android эти интерфейсы будут условно заблокированы в списке max-target-x . |
SDK |
| Интерфейсы, которые можно свободно использовать и которые теперь поддерживаются как часть официально документированного индекса пакетов Android. |
Тестовые 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 returned, NoSuchFieldError thrown |
JNI с использованием env->GetMethodID() | Возвращен NULL , выдан NoSuchMethodError |
Протестируйте свое приложение на наличие интерфейсов, не относящихся к SDK
Существует несколько методов, которые можно использовать для тестирования интерфейсов, не относящихся к SDK, в вашем приложении.
Тестирование с использованием отлаживаемого приложения
You can test for non-SDK interfaces by building and running a debuggable app on a device or emulator running Android 9 (API level 28) or higher. Make sure that the device or emulator that you are using matches the target API level of your app.
При выполнении тестов вашего приложения система выводит сообщение журнала, если приложение обращается к определённым интерфейсам, не относящимся к 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 и выполните следующие действия:
- Загрузите инструмент veridex из репозитория готовых сборок среды выполнения Android.
- Извлеките содержимое файла
appcompat.tar.gz
. - В извлеченной папке найдите файл
veridex-linux.zip
и распакуйте его. Перейдите в распакованную папку и выполните следующую команду, где
your-app.apk
— это APK-файл, который вы хотите протестировать:./appcompat.sh --dex-file=your-app.apk
macOS
Чтобы запустить инструмент veridex на macOS, выполните следующие действия:
- Загрузите инструмент veridex из репозитория готовых сборок среды выполнения Android.
- Извлеките содержимое файла
appcompat.tar.gz
. - В извлеченной папке найдите файл
veridex-mac.zip
и извлеките его. Перейдите в распакованную папку и выполните следующую команду, где
/path-from-root/your-app.apk
— это путь к APK-файлу, который вы хотите протестировать, начиная с корневого каталога вашей системы:./appcompat.sh --dex-file=/path-from-root/your-app.apk
Линукс
Чтобы запустить инструмент veridex в Linux, выполните следующие действия:
- Загрузите инструмент veridex из репозитория готовых сборок среды выполнения Android.
- Извлеките содержимое файла
appcompat.tar.gz
. - В извлеченной папке найдите файл
veridex-linux.zip
и распакуйте его. Перейдите в распакованную папку и выполните следующую команду, где
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: Disallow usage of non-SDK interfaces that belong to the blocklist or are conditionally blocked for your target API level .
Вопросы о списках интерфейсов, не входящих в 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
).