Как узнать, какой уровень API используется моим устройством?
Версия прошивки 1.6. Означает ли это, что он использует API Level 4?
Вы можете получить уровень API программно с помощью постоянной системы (Build.VERSION.SDK_INT). Например, вы можете запустить часть кода, для которой требуется более новый API, следующим образом (он будет выполняться, если уровень API текущего устройства составляет не менее 4):
Для получения видимой пользователем версии Android используйте:
Для уровня API> = 4 вы можете использовать Build.VERSION.SDK_INT
Применение
Чтобы получить текущее API вашего устройства:
В первых версиях был использован Build.VERSION.SDK
Но теперь не рекомендуется !.
SDK Это поле было устарело в уровне API 4. Используйте SDK_INT, чтобы легко получить это как целое число.
Теперь вы должны использовать: SDK_INT Добавлен в уровень API 4:
SDK_INT Видимая пользователем SDK-версия фреймворка; Его возможные значения определены в Build.VERSION_CODES.
Вы можете получить информацию о устройстве, как показано ниже.
И может получить историю версий кода Android из ОС.
Поэтому, объедините эти и официальные версии .
Это говорит о том, что код версии API25 является N_MR1.
В некоторых случаях требуется узнать версию Android API непосредственно во время работы программы.
Пример подобной ситуации мы уже рассматривали ранее, когда речь шла о работе с событием onScrollChange для элементов управления ScrollView и HorizontalScrollView (напомним, что оно, доступно только начиная с API 23 (Android 6.0 или Marshmallow)).
В вышеупомянутом примере мы обращались к свойству SDK_INT, класса VERSION, которое возвращает номер версии API.
Номер версии API возвращается в виде целого числа. Поэтому с ним можно работать непосредственно:
Либо сравнивать его с один из значений перечисления VERSION_CODES (как в первом примере). Нижеприведены значения перечисления VERSION_CODES в соответствии с номерами версий API и Android.
Версия API | Значение перечисления VERSION_CODES | Версия Android |
1 | BASE | 1.0 |
2 | BASE_1_1 | 1.1 |
3 | CUPCAKE | 1.5 |
4 | DONUT | 2.0 |
5 | ECLAIR | 2.0. |
6 | ECLAIR_0_1 | 2.0.1 |
7 | ECLAIR_0_1 | 2.1 |
8 | FROYO | 2.2 |
9 | GINGERBREAD | 2.3 |
10 | GINGERBREAD_MR1 | 2.3.3 |
11 | HONEYCOMB | 3.0 |
12 | HONEYCOMB_MR1 | 3.1 |
13 | HONEYCOMB_MR1 | 3.2 |
14 | ICE_CREAM_SANDWICH | 4.0 |
15 | ICE_CREAM_SANDWICH_MR1 | 4.0.3 |
16 | JELLY_BEAN | 4.1 |
17 | JELLY_BEAN_MR1 | 4.2 |
18 | JELLY_BEAN_MR2 | 4.3 |
19 | KITKAT | 4.4 |
20 | KITKAT_WATCH | 4.4W |
21 | L | 5.0 |
21 | LOLLIPOP | 5.0 |
22 | LOLLIPOP_MR1 | 5.1 |
23 | M | 6.0 |
24 | N | 7.0 |
25 | N_MR1 | 7.1 |
26 | O | 8.0 |
27 | O_MR1 | 8.1 |
28 | P | 9.0 |
29 | Q | 10.0 |
Это позволяет оперировать с номером версии API даже зная только версию Android.
Примечание
По просьбе одного из читателей 29.02.2020 таблица в статье была дополнена до Android 10.
Содержание статьи
Любой, кто писал более или менее серьезный софт для разных мобильных ОС, знает, что Android — самая открытая для разработчика ОС. Доступный для сторонних приложений API здесь гораздо шире, сама система гибче, а правила размещения приложений в маркете очень либеральные. Однако и в Android есть ряд системных API, скрытых от сторонних приложений и доступных только стоковому софту. В этой статье мы попробуем разобраться, как получить доступ к этим API и какие возможности они открывают.
Немного теории
Как мы все знаем, в Android есть такое понятие — полномочия приложений (permissions, разрешения). Полномочия прописываются в файл Manifest.xml каждого приложения и определяют то, к каким функциям API сможет получить доступ приложение. Хочешь работать с камерой — добавь в Manifest.xml строку . Нужен доступ к карте памяти — android.permission.READ_EXTERNAL_STORAGE . Все просто и логично, к тому же все доступные приложениям полномочия хорошо документированы.
Есть, однако, в этой стройной схеме одна очень важная деталь, которую сами создатели Android называют уровень доступа (protection level). Чтобы понять, что это такое, попробуй добавить в Manifest.xml любого своего приложения следующую строку:
По идее, данное полномочие должно открыть доступ к API, позволяющему переводить смартфон в режим полета, включать/выключать GPS и делать другие полезные вещи. Но IDE так не считает и поэтому сразу подчеркивает строку как ошибку с формулировкой «Permission is only granted to system apps». Это и есть предупреждение о нарушении того самого уровня доступа. IDE как бы говорит нам: да, ты можешь попробовать дать своему приложению полномочие WRITE_SECURE_SETTINGS , но Android все равно не разрешит тебе использовать закрепленный за ним API до тех пор, пока ты не сделаешь свое приложение системным. А что значит «системным» в данном случае? Это значит: подпишешь его тем же цифровым ключом, каким подписана сама прошивка (иди попробуй раздобыть такой ключ у какой-нибудь Samsung или LG!).
Xakep #250. Погружение в AD
Официально в Android существует четыре уровня доступа:
- normal — «обычные» полномочия, дающие приложению доступ к безобидным функциям, которые не получится зловредно использовать (примеры: SET_ALARM, ACCESS_NETWORK_STATE, VIBRATE). Система даже не скажет тебе, что приложение вообще их использует;
- dangerous — «опасные» полномочия, юзер будет информирован о них при установке приложения либо увидит окошко с предупреждением в Android 6.0 (примеры: READ_SMS, SEND_SMS, CALL_PHONE, READ_CALL_LOG);
- signature — доступны только приложениям, подписанным ключом прошивки (примеры: GET_TASKS, MANAGE_USERS, WRITE_SETTINGS, MOUNT_UNMOUNT_FILESYSTEMS);
- privileged — доступны приложениям, располагающимся в каталоге /system/priv-app .
В большинстве случаев уровни доступа signature и privileged равноценны. Например, чтобы получить полномочие MANAGE_USERS, приложение должно быть либо подписано ключом прошивки, либо размещено в каталоге /system/priv-app . Но есть и исключения: например, полномочие MANAGE_DEVICE_ADMIN имеет уровень доступа signature, то есть единственный способ его получить — подписать приложение ключом прошивки.
Есть также набор внутренних уровней доступа, введенных в Android для решения определенных проблем: installer, development, preinstalled, appop, pre23. По сути, это костыли, и на данном этапе ты можешь о них не думать, однако к уровню доступа development мы еще вернемся, и он нам очень сильно пригодится. А пока поговорим о том, как получить нужные нам уровни доступа и что они дают.
Уровень доступа privileged
Privileged не самый высокий уровень доступа и позволяет использовать далеко не весь API Android. Однако в большинстве случаев он оказывается вполне достаточным, так как позволяет устанавливать и удалять приложения и пользователей (INSTALL_PACKAGES, DELETE_PACKAGES, MANAGE_USERS), управлять статусной строкой (STATUS_BAR), управлять некоторыми настройками питания (WRITE_SECURE_SETTINGS), читать и изменять настройки Wi-Fi (READ_WIFI_CREDENTIAL, OVERRIDE_WIFI_CONFIG), отключать приложения и их компоненты (CHANGE_COMPONENT_ENABLED_STATE) и многое другое.
Чтобы приложение получило уровень доступа privileged, оно должно быть установлено в каталог /system/priv-app , а это значит — поставляться предустановленным в составе прошивки. Однако, имея root, мы можем поместить свое приложение в данный каталог с помощью двух функций:
Функцию runCommandWait я описывать не буду, она просто выполняет shell-команду и ждет ее завершения (подробнее читай в моей статье про написание приложений с правами root). Функция makeAppSystem, в свою очередь, принимает полное имя приложения (это то самое com.example.app, которое ты указываешь при создании нового проекта в Android Studio) и переносит его в /system/priv-app или /system/app , в зависимости от используемой версии Android. Код может показаться тебе несколько странным, на самом деле он абсолютно корректен и учитывает два фактора:
- до Android 4.4 (API Level: 20) каталога /system/priv-app не существовало и все системные приложения размещались в /system/app ;
- начиная с Android 5.0 (API Level: 21) пакеты с приложениями не просто складируются в /data/app и /system/priv-app , а размещаются внутри своих обособленных подкаталогов.
Как использовать этот код? Очень просто: ты определяешь в Manifest.xml своего приложения все privileged-полномочия, которые ему нужны, не обращая внимания на ошибки IDE. Затем в самое начало кода приложения вставляешь вызов makeAppSystem с именем самого приложения в качестве аргумента, компилируешь и запускаешь. После запуска приложение перемещает само себя в /system/priv-app , перезагружает смартфон, и ему открываются все privileged API.
Список privileged-полномочий можно посмотреть в исходниках Android. Просто ищи по слову privileged. О том, как их использовать, — чуть позже.
Уровень доступа signature
Подпись ключом прошивки позволяет получить самый высокий уровень доступа к API — signature. Имеющее такой доступ приложение может делать практически все что угодно: манипулировать любыми настройками Android (WRITE_SETTINGS, WRITE_SECURE_SETTINGS), наделять приложения правами администратора (MANAGE_DEVICE_ADMINS), программно нажимать кнопки и вводить данные в любое окно (INJECT_EVENTS) и многое другое.
Получить такой уровень доступа на стоковой прошивке почти невозможно. Ни один производитель смартфонов не предоставит тебе ключ для подписи своих прошивок. Но если речь идет о кастомной прошивке, то все становится немного проще. Например, ночные сборки того же CyanogenMod (а я напомню, что пользователей у нее больше, чем юзеров всех версий Windows Phone, вместе взятых) подписываются тестовым ключом, а его особенность в том, что он есть в открытом доступе.
Но это еще не все, в CyanogenMod есть механизм безопасности, который, в отличие от чистого Android, позволяет получать уровень доступа signature не абсолютно всем приложениям, подписанным ключом прошивки, а только тем, что размещены в /system/priv-app . Поэтому, чтобы получить уровень доступа signature в CyanogenMod (не в Cyanogen OS, я подчеркиваю), необходимо:
- Добавить в Manifest.xml приложения необходимые полномочия.
- Добавить в приложение вызов функции makeAppSystem(), описанной в предыдущем разделе.
- Подписать релизную версию приложения ключом platform из репозитория CyanogenMod.
Уровень доступа development
В Android есть специальный уровень доступа development, отличие которого заключается в том, что приложения получают его не по факту размещения в /system/priv-app или использования цифровой подписи прошивки, а динамически. То есть система может дать такой уровень доступа любому приложению, а может и отозвать обратно. Но самое важное, что, имея права root, приложение может наделить себя таким уровнем доступа самостоятельно.
Чтобы это сделать, достаточно использовать примерно такой код:
В данном случае приложение appName получит полномочие WRITE_SECURE_SETTINGS вне зависимости от того, где оно размещено и каким ключом подписано. Круто? Вне сомнения, однако WRITE_SECURE_SETTINGS — фактически единственное полезное полномочие с уровнем доступа development. Остальные четырнадцать — это полномочия для отладки и тестирования (чтение логов, дампы памяти и так далее).
Полномочия development в исходниках Android
Как использовать системный API?
Основная проблема, с которой ты столкнешься при работе с системным API, — это полное (за небольшими исключениями) отсутствие документации. Ни в официальных руководствах, ни в неофициальных ты не найдешь почти никаких упоминаний об этом. Информацию придется собирать по крупицам, прошаривая сотни страниц форумов и читая тысячи страниц исходников Android. Однако хоть и небольшую, но отправную точку в виде парочки полезных примеров мы тебе дадим.
WRITE_SECURE_SETTINGS
Полномочие WRITE_SECURE_SETTINGS появилось в Android 4.2 для защиты некоторых критически важных настроек Android. Среди таких настроек: включение/выключение режима полета, управление настройками местоположения и передачи данных. Оно защищено сразу тремя уровнями доступа: signature, privileged и development. То есть ты можешь использовать любой из перечисленных выше способов получения уровня доступа, чтобы наделить свое приложение полномочием WRITE_SECURE_SETTINGS.
Как использовать открывшиеся возможности? Например, так:
Это очень простой код, который тупо переключает смартфон в режим полета или наоборот в зависимости от текущего состояния. Все просто и лаконично.
INSTALL_PACKAGES
Как ясно из названия, полномочие INSTALL_PACKAGES позволяет «втихую» устанавливать в систему APK-пакеты. Использовать эту возможность могут либо подписанные ключом прошивки приложения (signature), либо установленные в /system/priv-app . При этом даже не обязательно использовать Java API, достаточно вызвать консолью команду pm (Package Manager) с нужными параметрами:
После отработки команды пакет apkPath будет установлен в систему. Ты можешь возразить, что то же самое можно сделать и с правами root, и будешь прав: в данном случае достаточно изменить последний аргумент функции runCommandWait() на true. Однако стоит иметь в виду, что приложения с правами root, во-первых, приводят к появлению окна запроса соответствующих полномочий у юзера, а во-вторых, логируются тем же SuperSU. А так достаточно один раз прописать свою софтину в /system/priv-app , и она сможет устанавливать сколько угодно софта без всяких вопросов.
Вместо выводов
Вот и все. Доступ к закрытому API в Android не так уж и сложно получить. С другой стороны, с легитимным софтом использовать его в большинстве случаев не имеет смысла, проще получить права root и вызывать соответствующие консольные команды: settings для изменения настроек, pm для установки/удаления приложений, setprop для изменения низкоуровневых настроек и так далее. Однако если речь идет о не совсем обычном программном обеспечении.
Евгений Зобнин
Редактор рубрики X-Mobile. По совместительству сисадмин. Большой фанат Linux, Plan 9, гаджетов и древних видеоигр.