Демистификация внутренней и внешней памяти в современном Android
7 минут чтения
16 января
Обновлено 6 февраля 2023 г.
Разработчики Android имеют возможность выбора внутреннего или внешнего хранилища при сохранении файлов. Хотя для этого есть историческая причина, разница в наши дни немного сбивает с толку.
Давайте отправимся в путешествие, чтобы понять, почему существуют эти варианты, какой вариант вам следует выбрать и какие есть лучшие альтернативы.
Раньше Android был простым, но безумно небезопасным
В старые времена у внутреннего и внешнего выбора были разные цели:
- Внутреннее хранилище означало внутреннюю память устройства. Файлы, хранящиеся здесь, были заблокированы для вашего приложения, а это означает, что другие приложения не могли получить к ним доступ независимо от их разрешений.
- Внешнее хранилище означало все, что не было внутренней памятью устройства, например вставленную SD-карту. Это использовалось как общедоступное место, к которому могло получить доступ любое приложение, если у этого приложения были правильные разрешения.
Хотя это было ясно, у него была особая проблема: устройства того времени имели очень мало внутренней памяти и полагались на то, что пользователи подключали SD-карты. SD-карты по определению были внешним хранилищем.
Поэтому, если вы хотели хранить большой объем данных — скажем, вы писали приложение для фотографий — у вас действительно был выбор только во внешнем хранилище. Поэтому приложения часто запрашивали разрешение на доступ к внешнему хранилищу (через разрешения READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE).
Но это было крайне небезопасно. Эти разрешения на внешнее хранилище позволят приложению читать/записывать файлы в любом месте на SD-карте. Таким образом, все ваши фотографии стали доступны любому приложению, желающему записать свои данные во внешнее хранилище. А поскольку разрешения на внешнее хранилище так часто запрашивались приложениями, пользователи предоставляли их без какого-либо реального рассмотрения. Отслеживайте вредоносные приложения, которые крадут ваши данные без вашего ведома.
Android KitKat: упрощенные разрешения повысили безопасность (!!)
Вопрос : Как можно решить проблему безопасности, ослабив разрешения, необходимые для каких-либо действий?
Ответ : Психология человека. Ослабляя разрешения, необходимые для выполнения неопасных вещей, вы заставляете людей сидеть и обращать внимание, когда запрашивается разрешение .
Это то, что сделал Android 4.4 (KitKat). Впервые он позволил приложениям получать доступ к своим собственным уникальным местам во внешнем хранилище без разрешения. Теперь, когда приложение вызывает getExternalFilesDir(), оно создает свой собственный каталог, из которого оно может свободно читать и писать.
Разрешения READ_EXTERNAL_STORAGE и WRITE_EXTERNAL_STORAGE по-прежнему необходимы для чтения/записи где-либо еще во внешнем хранилище, но дело в том, что большинству приложений это никогда не понадобится.
И поэтому ранее вездесущий диалог разрешений на хранение может начать исчезать из повседневной жизни Android. Со временем это означало, что пользователи были гораздо более осторожными, когда бы они ни видели это. И правильно — теперь не было невинной причины просить об этом.
Эмулированное внешнее хранилище: когда внутреннее хранилище становится внешним
Почему телефоны Android перестали предлагать слоты для SD-карт? Оптимисты сказали бы, что это было сделано для повышения безопасности, поскольку SD-карты можно было легко извлечь из телефона и прочитать в другом месте. Циники сказали бы, что производители телефонов выиграли от того, что не позволили потребителям добавлять свои собственные дешевые хранилища, поскольку они могли продавать внутреннее пространство для хранения с высокой прибылью. Оба пункта, конечно, верны.
И телефоны постепенно перестали предлагать внешнее хранилище. Это вызвало проблему со старыми приложениями, которые ожидали, что только внешнее хранилище будет достаточно большим для их нужд, и слепо использовали getExternalFilesDir() .
Команда разработчиков Android решила эту проблему с помощью Эмулированного внешнего хранилища , которое присутствует в ОС начиная с Android 3. Когда приложение запрашивает внешнее хранилище, вместо этого оно фактически получает часть внутреннего хранилища, и это ничуть не мудрее. К этому фрагменту внутреннего хранилища применяются все небезопасные правила внешнего хранилища.
Начиная с API 21, приложения могут использовать Environment.isExternalStorageEmulated() , чтобы определить, имеет ли устройство физическое или эмулированное внешнее хранилище. Для подавляющего большинства современных Android-устройств он будет эмулироваться.
Приемлемое внешнее хранилище: когда внешнее хранилище становится внутренним
В Android 6 добавлена возможность для телефона или планшета форматировать и шифровать внешнее запоминающее устройство и адаптировать его, заставляя его вести себя как внутреннее хранилище. Принятое хранилище привязывается шифрованием к устройству, которое его создало. Ключ шифрования находится во внутреннем хранилище, поэтому принятое хранилище по существу так же безопасно, как и внутреннее.
Положительные моменты : это позволяет устройствам с низкими характеристиками безопасно увеличивать внутреннюю память.
Плохие моменты : принятая SD-карта, скажем, неразрывно связана с этим телефоном. Удалите его, и ваш телефон станет странным : вы, по сути, удалили случайный фрагмент его приложений и данных. (Случайно, потому что ОС, а не пользователь выбирает, будет ли что-то установлено или сохранено во внутренней или принятой памяти.) Я не могу представить, чтобы какая-либо ОС могла справиться с этим очень хорошо.
Scoped Storage в Android 10 полностью изменил внешнее хранилище
Android 10 представил Scoped Storage для внешнего хранилища. По сути, это сделало безопасность внешнего хранилища очень похожей на внутреннюю память. Приложения получат свой собственный каталог, к которому они смогут обращаться (чтение/запись) без разрешения, и ни одно другое приложение не сможет этого сделать (кроме см. ниже).
Проблема с Scoped Storage заключалась в том, что в нем не учитывались некоторые важные варианты использования, которые ранее требовали бесплатного доступа к общему хранилищу. Например, как насчет доступа к фотогалерее пользователя? Эти варианты использования рассматривались в индивидуальном порядке. Они следующие:
Разрешение пользователю выбирать из галереи фотографий
Используйте средство выбора фотографий , никаких разрешений не требуется. (См. мою статью об использовании Photo Picker с Kotlin + Compose ).
Обратите внимание, что это доступно только на Android 11+.
Запись фотографий в библиотеку пользователя
Используйте API-интерфейсы MediaStore . Для записи новых фотографий не требуется никаких разрешений.
Чтение фотографий из библиотеки пользователя
Также API MediaStore. Никаких разрешений не требуется, если вы получаете доступ только к файлам, созданным вашим собственным приложением. Если вы хотите получить доступ ко всей библиотеке, вам потребуются следующие разрешения:
<!-- Требуется, только если вашему приложению требуется доступ к изображениям или фотографиям
, созданным другими приложениями. -->
< uses-permission android:name = "android.permission.READ_MEDIA_IMAGES" />
<!-- Требуется, только если вашему приложению требуется доступ к видео
, созданным другими приложениями. -->
< uses-permission android:name = "android.permission.READ_MEDIA_VIDEO" />
<!-- Требуется, только если вашему приложению требуется доступ к аудиофайлам
, созданным другими приложениями. -->
< использует-разрешение android:name = "android.permission.READ_MEDIA_AUDIO" />
<!-- Если вашему приложению не требуется доступ к медиафайлам, созданным другими приложениями,
вместо этого установите для атрибута "maxSdkVersion" значение "28". -->
< использование-разрешение android:name = "android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion = "32" />
< использование-разрешение android:name = "android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion = "29" / >
Создание, чтение и запись общих документов
Например, если вы хотите сохранить файл PDF в месте, где другие файлы могут получить к нему доступ, или прочитать данные геотрекинга, которые были предоставлены другим приложением.
Для этого вы можете использовать Documents Provider . Никаких разрешений не требуется, так как пользователь все равно вынужден участвовать в процессе выбора файла.
Доступ к большим наборам данных, кэшированным другим приложением
В ситуации, когда вы работаете с большими общими наборами данных, которые необходимо загрузить, вы можете избежать повторной загрузки, если это уже сделало другое приложение.
Этого можно добиться с помощью BlobStoreManager .
Полный доступ ко всему во внешнем хранилище
По-прежнему существует разрешение, которое позволяет пользователям получать доступ ко всему во внешнем хранилище, но сейчас его труднее получить. Это подходит только в очень ограниченных случаях, например, в приложениях для управления файлами, системах резервного копирования или антивирусных сканерах. Play Store не разрешает отправлять приложения с использованием этого разрешения без подходящего объяснения.
Разрешение есть MANAGE_EXTERNAL_STORAGE
. Приложения должны не только объявлять это разрешение, но и указывать пользователям включать его вручную. Активируйте ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
намерение сделать это, что приводит пользователя сюда:
Отказ от ограниченного хранилища
Хотя Scoped Storage был представлен в Android 10, это было настолько значительное изменение, что оно не применялось до Android 11. Даже тогда приложения, ориентированные на API 29, могли отказаться от него, поместив его в файл манифеста <application android:requestLegacyExternalStorage="true" />
. Обратите внимание, что приложения, ориентированные на API 29, не принимались в Play Store уже много лет, поэтому он, по сути, больше не поддерживается.
Итак, это вводит нас в курс дела. Текущая версия Android не претерпела существенных изменений в правах доступа к хранилищу после этого масштабного изменения в Android 10.
В заключение: если вы разрабатываете современное приложение, в большинстве случаев используйте внутреннюю память. Но если вы находитесь в одном из конкретных случаев использования, указанных выше (фотографии, документы или большие кэшированные наборы данных), вместо этого используйте соответствующие API.
Том Колвин — технический директор Conseal Security , экспертов по тестированию безопасности мобильных приложений; и Apptaura , специалисты по разработке приложений. Свяжитесь с нами , если я могу помочь с любыми проектами по безопасности мобильных устройств или разработками!
Автор Том Колвин
Андроид и безопасность. Технический директор Apptaura, специалисты по разработке приложений, и Conseal, эксперты по безопасности. Доступен в качестве внештатного консультанта/разработчика. Южная Англия.