Начиная с 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 , выдано 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 и выполните следующие действия:
- Загрузите инструмент 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: Запретить использование интерфейсов, не относящихся к 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
).