Android emulated sdcard

本文详细介绍了在Android系统中添加虚拟SD卡(emulatedsdcard)的方法,包括内核配置、文件系统修改以及验证步骤。通过此教程,开发者可以轻松实现虚拟SD卡的集成,提升设备的存储灵活性。

如果要添加 emulated sdcard ,需要一下几个内容修改:

 

1. patch:

 

  1. diff --git a/init.rc b/init.rc  
  2. index bd6c22e..3a55e6a 100755  
  3. --- a/init.rc  
  4. +++ b/init.rc  
  5. @@ -184,11 +184,15 @@ on post-fs-data  
  6.      # create directory for DRM plug-ins  
  7.      mkdir /data/drm 0774 drm drm  
  8.   
  9. +    # we will remap this as /mnt/sdcard with the sdcard fuse tool  
  10. +    mkdir /data/media 0775 media_rw media_rw  
  11. +    chown media_rw media_rw /data/media  
  12. +  
  13.      # If there is no fs-post-data action in the init.<device>.rc file, you  
  14.      # must uncomment this line, otherwise encrypted filesystems  
  15.      # won't work.  
  16.      # Set indication (checked by vold) that we have finished this action  
  17. -    #setprop vold.post_fs_data_done 1  
  18. +    setprop vold.post_fs_data_done 1  
  19.   
  20.      chown system system /sys/class/android_usb/android0/f_mass_storage/lun/file  
  21.      chmod 0660 /sys/class/android_usb/android0/f_mass_storage/lun/file  
  22. @@ -509,3 +513,9 @@ service iprenew_eth0 /system/bin/dhcpcd -n  
  23.      disabled  
  24.      oneshot  
  25.   
  26. +# create virtual SD card at /mnt/sdcard, based on the /data/media directory  
  27. +# daemon will drop to user/group system/media_rw after initializing  
  28. +# underlying files in /data/media will be created with user and group media_rw (1023)  
  29. +#service sdcard /system/bin/sdcard /data/media 1023 1023  
  30. +service sdcard /system/bin/sdcard /data/media /mnt/shell/emulated 1023 1023
  31. +    class late_start  
  32. +  
  33. diff --git a/device.mk b/device.mk  
  34. index bd72276..c836943 100755  
  35. --- a/device.mk  
  36. +++ b/device.mk  
  37. @@ -6,6 +6,8 @@ PRODUCT_PACKAGES := \  
  38.      VisualizationWallpapers \  
  39.      librs_jni  
  40.   
  41. +PRODUCT_CHARACTERISTICS += nosdcard  
  42. +  
  43.  DEVICE_PACKAGE_OVERLAYS := \  
  44.      device/stm/kem/overlay  
  45.   
  46. diff --git a/overlay/frameworks/base/core/res/res/xml/storage_list.xml b/overlay/frameworks/base/core/res/res/xml/storage_list.xml  
  47. new file mode 100644  
  48. index 0000000..043530d  
  49. --- /dev/null  
  50. +++ b/overlay/frameworks/base/core/res/res/xml/storage_list.xml  
  51. @@ -0,0 +1,41 @@  
  52. +<?xml version="1.0" encoding="utf-8"?>  
  53. +<!--  
  54. +**  
  55. +** Copyright 2011, The Android Open Source Project  
  56. +**  
  57. +** Licensed under the Apache License, Version 2.0 (the "License")  
  58. +** you may not use this file except in compliance with the License.  
  59. +** You may obtain a copy of the License at  
  60. +**  
  61. +**     http://www.apache.org/licenses/LICENSE-2.0  
  62. +**  
  63. +** Unless required by applicable law or agreed to in writing, software  
  64. +** distributed under the License is distributed on an "AS IS" BASIS,  
  65. +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  66. +** See the License for the specific language governing permissions and  
  67. +** limitations under the License.  
  68. +*/  
  69. +-->  
  70. +  
  71. +<!-- The <device> element should contain one or more <storage> elements.  
  72. +     Exactly one of these should have the attribute primary="true".  
  73. +     This storage will be the primary external storage and should have path="/mnt/sdcard".  
  74. +     Each storage should have both a path and description attribute set.  
  75. +     The following boolean attributes are optional:  
  76. +  
  77. +        primary:    this storage is the primary external storage  
  78. +        removable:  this is removable storage (for example, a real SD card)  
  79. +        emulated:   the storage is emulated via the FUSE sdcard daemon  
  80. +        mtp-reserve: number of megabytes of storage MTP should reserve for free storage  
  81. +                     (used for emulated storage that is shared with system's data partition)  
  82. +  
  83. +      A storage should not have both emulated and removable set to true  
  84. +-->  
  85. +  
  86. +<StorageList xmlns:android="http://schemas.android.com/apk/res/android">  
  87. +    <storage android:storageDescription="@string/storage_internal"
  88. +             android:emulated="true"  
  89. +             android:mtpReserve="100" />  
  90. +</StorageList>  


2. kernel config

       需要 CONFIG_FUSE_FS=y

 

查看有没有 /mnt/sdcard:

       开机后adb shell进去后df下即可

 

<think>我们正在解决用户的问题:如何获取Android设备中SD卡的存储路径。 根据引用[1][2][3]的内容,我们可以总结如下: 1. Android设备上存在多种存储路径,包括内部存储(内置SD卡)和外部存储(外置SD卡)。 2. 常用的获取内置存储(通常称为SD卡,但实际上是模拟的)路径的方法是使用`Environment.getExternalStorageDirectory()`。 3. 对于外置SD卡(即扩展存储),由于没有官方API直接获取,通常需要通过系统环境变量或者遍历挂载点来获取。 因此,我们将分两部分回答: 一、获取内置存储(内部SD卡)路径 二、获取外置存储(外部SD卡,如TF卡)路径 注意:从Android 4.4(KitKat)开始,应用在访问外部存储的特定目录时不需要请求权限,但访问外部存储的根目录或其他应用的私有目录则需要权限。另外,在Android 10及以上版本,由于分区存储(Scoped Storage)的引入,访问外部存储的方式有所变化,但获取路径的方法仍然可用,只是访问文件可能需要使用MediaStore或Storage Access Framework。 步骤: 一、获取内置存储路径(通常指向/storage/emulated/0或/mnt/sdcard等) 使用Environment类: ```java String internalPath = Environment.getExternalStorageDirectory().getAbsolutePath(); ``` 二、获取外置SD卡路径 由于没有标准API,我们可以尝试以下方法: 1. 通过系统环境变量(可能不可靠,因为不同设备变量名不同): - "SECONDARY_STORAGE" - "EXTERNAL_SDCARD_STORAGE" 2. 遍历挂载点,通过读取/proc/mounts或/mnt目录下的挂载点,找到外置SD卡的路径。 以下是一个获取外置SD卡路径的示例方法(注意:需要根据设备进行测试,因为不同设备挂载点可能不同): ```java public static String getExternalSdCardPath() { String path = null; File[] files = ContextCompat.getExternalFilesDirs(context, null); if (files.length > 1) { // files[0]是内置存储,files[1]是外置存储(如果有的话) File externalFile = files[1]; if (externalFile != null) { path = externalFile.getAbsolutePath(); // 由于返回的是应用在外部存储上的私有目录,我们需要去掉后面的路径部分,得到根目录 int index = path.indexOf("/Android/data/"); if (index != -1) { path = path.substring(0, index); } } } return path; } ``` 或者,我们也可以读取系统环境变量: ```java public static String getExternalSdCardPath() { String secondStorage = System.getenv("SECONDARY_STORAGE"); if (secondStorage != null && !secondStorage.isEmpty()) { // 可能有多个路径,用冒号分隔 String[] paths = secondStorage.split(":"); if (paths.length > 0) { return paths[0]; } } return null; } ``` 但是,更可靠的方法是使用ContextCompat.getExternalFilesDirs(),因为它在大多数设备上都有效。 注意:在Android 4.4及以上,使用ContextCompat.getExternalFilesDirs()可以获取到所有外部存储设备上的应用私有目录,然后我们可以从中提取出外部存储的根路径。 三、权限问题 在AndroidManifest.xml中声明读写权限(对于Android 6.0+需要动态申请): ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ``` 但是,从Android 4.4开始,应用在访问自己的私有目录(即Context.getExternalFilesDir()返回的目录)时不需要权限。因此,如果我们只是获取路径而不访问其他文件,可能不需要权限。但如果要访问外部存储的根目录下的文件,则需要权限。 四、示例代码 以下是一个完整的示例,展示如何获取内置存储和外置存储的路径: ```java import android.content.Context; import android.os.Environment; import androidx.core.content.ContextCompat; public class StorageUtils { // 获取内置存储路径(主外部存储) public static String getInternalStoragePath() { return Environment.getExternalStorageDirectory().getAbsolutePath(); } // 获取外置存储路径(扩展存储,如SD卡) public static String getExternalSdCardPath(Context context) { File[] files = ContextCompat.getExternalFilesDirs(context, null); if (files.length > 1) { File externalFile = files[1]; if (externalFile != null) { String path = externalFile.getAbsolutePath(); // 截取掉私有目录部分 int index = path.indexOf("/Android/data/" + context.getPackageName()); if (index != -1) { return path.substring(0, index); } } } return null; } } ``` 注意:有些设备可能有多个外部存储(比如OTG),所以files数组可能有多个元素,我们可以遍历处理。 五、注意事项 1. 不同设备厂商可能会有不同的实现,因此获取外置SD卡路径的方法可能不适用于所有设备。 2. 在Android 10及以上,如果应用启用了分区存储(Scoped Storage),则无法直接通过文件路径访问外部存储,而需要使用MediaStore或Storage Access Framework。 最后,根据引用[1][2][3]的内容,我们还可以通过Environment类获取其他标准目录,例如: ```java Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); ``` 这将返回内置存储上的公共DCIM目录。 引用说明: 我们参考了引用[1][2][3]中关于SD卡路径获取的方法,特别是通过Environment类获取内置存储路径,以及通过系统环境变量或ContextCompat.getExternalFilesDirs()获取外置存储路径。 因此,在回答中我们会引用这些内容。</think>### 获取 Android 设备 SD 卡存储路径的完整指南 在 Android 开发中获取 SD 卡存储路径,需要注意不同 Android 版本的变化和设备差异。以下是可靠的方法总结: #### 一、获取内置存储(主外部存储)路径 这是最常用且官方推荐的方法,**适用于大多数设备**: ```java // 获取内置存储根路径(如:/storage/emulated/0) String primaryStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); // 获取公共目录路径(如相册目录) File picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); ``` #### 二、获取外置 SD 卡路径(扩展存储) 由于没有官方 API,需通过以下方法兼容不同设备: 1. **通过系统环境变量**(部分设备有效): ```java String secondaryStorage = System.getenv("SECONDARY_STORAGE"); String externalSdCard = System.getenv("EXTERNAL_SDCARD_STORAGE"); ``` 2. **通过挂载点遍历**(更可靠): ```java public static String getExternalSdCardPath() { File[] storagePoints = new File("/storage").listFiles(); for (File device : storagePoints) { if (device.isDirectory() && !device.getName().equals("emulated") && !device.getName().equals("self")) { File sdCard = new File(device, Environment.DIRECTORY_DCIM); if (sdCard.exists()) { return device.getAbsolutePath(); // 如:/storage/XXXX-XXXX } } } return null; } ``` 3. **通过 ContextCompat API**(Android 4.4+ 推荐): ```java File[] externalDirs = ContextCompat.getExternalFilesDirs(context, null); if (externalDirs.length > 1) { String sdCardPath = externalDirs[1].getAbsolutePath(); // 提取根路径:/storage/XXXX-XXXX/Android/data/... → /storage/XXXX-XXXX return sdCardPath.substring(0, sdCardPath.indexOf("/Android")); } ``` #### 三、适配不同 Android 版本 | 方案 | Android 4.4- | Android 5-9 | Android 10+ | |--------------------------|--------------|-------------|-------------| | `Environment.getExternalStorageDirectory()` | ✅ 推荐 | ✅ 推荐 | ⚠️ 需 `requestLegacyExternalStorage` | | 系统环境变量 | ⚠️ 部分可用 | ⚠️ 部分可用 | ❌ 不可用 | | `ContextCompat.getExternalFilesDirs()` | ✅ 推荐 | ✅ 推荐 | ✅ 推荐 | #### 四、完整示例代码 ```java public class StorageUtils { // 获取所有存储路径(包含内置+外置) public static List<String> getAllStoragePaths(Context context) { List<String> paths = new ArrayList<>(); // 1. 添加主存储 paths.add(Environment.getExternalStorageDirectory().getAbsolutePath()); // 2. 通过ContextCompat获取外置SD卡 File[] externals = ContextCompat.getExternalFilesDirs(context, null); for (int i = 1; i < externals.length; i++) { if (externals[i] != null) { String path = externals[i].getAbsolutePath(); int index = path.indexOf("/Android/data"); if (index != -1) paths.add(path.substring(0, index)); } } // 3. 备用方案:挂载点检测 if (paths.size() == 1) { String sdPath = detectViaMountPoints(); if (sdPath != null) paths.add(sdPath); } return paths; } private static String detectViaMountPoints() { // 实现上述挂载点遍历逻辑 } } ``` #### 五、关键注意事项 1. **权限声明**(AndroidManifest.xml): ```xml <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ``` Android 6.0+ 需[动态请求权限](https://developer.android.com/training/permissions/requesting) 2. **Android 10+ 适配**: ```xml <application android:requestLegacyExternalStorage="true"> ``` 或使用 [MediaStore API](https://developer.android.com/training/data-storage/shared/media) 访问公共文件 3. **路径差异说明**: - `/sdcard` → 通常符号链接到主存储 - `/storage/emulated/0` → 主存储的实际路径 - `/storage/XXXX-XXXX` → 外置SD卡的物理路径[^1][^3] > **最佳实践**:优先使用 `ContextCompat.getExternalFilesDirs()`,它自动处理多存储设备,返回应用私有目录路径,避免权限问题[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值