[RK3568 Android13]系统根目录的文件夹下创建文件夹或文件

Android 13系统特定目录创建及SELinux权限处理

平台:RK3568

系统:Android 13

1、需求描述

为了实现系统内置的APP在系统中某些用户无法看到的目录下创建文件夹或文件,需要系统创建文件夹,内置的系统APP具有读写权限,以及系统源码也可以读写该目录或文件。

比如:我们需要在系统根目录data或mnt文件夹下创建一个文件夹mcuhot,需要按照如下操作。

1)在init.rc文件中实现创建目录指令

2)在系统代码中实现某些读写逻辑

3)SELlinux限制添加所需的权限

2、功能实现

1)在init.rc文件中实现创建目录指令

在init.rc添加如下指令实现在目录data下创建文件夹mcuhot.

添加:

mkdir /data/mcuhot
chown system system /data/mcuhot
chmod 0777 /data/mcuhot

文件路径:system/core/rootdir/init.rc

on property:sys.boot_completed=1
    bootchart stop
    # Setup per_boot directory so other .rc could start to use it on boot_completed
    exec - system system -- /bin/rm -rf /data/per_boot
    mkdir /data/per_boot 0700 system system encryption=Require key=per_boot_ref
    
    mkdir /data/sdady
    chown system system /data/sdady
    chmod 0777 /data/sdady

# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
    exec -- /system/bin/extra_free_kbytes.sh ${sys.sysctl.extra_free_kbytes}

2)在系统代码中实现某些读写逻辑

系统代码实现逻辑功能代码此处忽略。主要介绍编写完成后编译,下载更新系统后,并没有实现预期功能,抓取日志进行分析。

从日志分析来看,创建的mcuhot,系统APP没有打开权限,也就是我们frameworks实现的逻辑代码,没有打开目录权限,从后续的日志分析来看,也没有读取权限,因此我们这里需要简单了解SELinux安全模块。

安全增强型linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。SELinux 主要由美国国家安全局开发。2.6 及以上版本的 Linux 内核都已经集成了 SELinux 模块。SELinux 的结构及配置非常复杂,而且有大量概念性的东西,要学精难度较大。很多 Linux 系统管理员嫌麻烦都把 SELinux 关闭了。

关于SELinux我们不过多介绍,网络上有详细介绍和使用。目前只解决如何处理我们的问题。刚才提到我们系统APP没有打开和读取权限,由于SELinux限制了在对根目录下的文件夹及文件的打开,读取,写入等各种操作。

如何添加权限呢?从日志分析可知,mcuhot没有读取被限制,后续日志发现也没有打开权限,日志关键部分如下:

---------------------------------------------------------------------------------------------------------------------------------

auditd  : type=1400 audit(0.0:562): avc: denied { read } for comm="DefaultDispatch" name="mcuhot" dev="dm-8" ino=1391 scontext=u:r:system_app:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=1

... ...

DefaultDispatch: type=1400 audit(0.0:563): avc: denied { open } for path="/data/sdady" dev="dm-8" ino=1391 scontext=u:r:system_app:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=1

---------------------------------------------------------------------------------------------------------------------------------

SELinux添加权限格式:

allow 源类型 目标类型:访问类型 操作权限

实现代码:

allow system_app system_data_file:dir { read open };

3)SELlinux限制添加所需的权限

在system_app.te添加权限打开和读取权限,各平台芯片system_app.te文件,所处目录各不相同。在文件最后添加如下代码:

allow system_app system_data_file:dir { read open };
 

路径:device/rockchip/common/sepolicy/vendor/system_app.te

dontaudit system_app mnt_vendor_file:dir search;
#for gpu
allow system_app sysfs_usb:file rw_file_perms;
#for ota
allow system_app selinuxfs:file { read open };
allow system_app mnt_media_rw_file:dir { getattr };
#for hdmi
allow system_app sysfs_hdmi:file rw_file_perms;
allow system_app sysfs_zram:dir r_dir_perms;
allow system_app sysfs_zram:file rw_file_perms;
allow system_app proc_stat:file { read open getattr };
#for samba
allow system_app metadata_file:dir {getattr};
allow system_app block_device:dir {search};
#for devicetest
#allow system_app system_app_data_file:file { execute execute_no_trans };
allow system_app system_data_file:file { read };
allow system_app { sysfs_leds metadata_file }:dir { search };

#TODO removed for Q
#allow system_app vendor_file:file { read open };
allow system_app unlabeled:filesystem { getattr };
allow system_app unlabeled:file { getattr open read write unlink rename };
allow system_app unlabeled:dir { open search read getattr write remove_name add_name };
allow system_app cache_file:lnk_file { read };
allow system_app cache_recovery_file:dir {search create read write open add_name getattr remove_name};
allow system_app cache_recovery_file:file {rw_file_perms create unlink setattr};

#TODO removed for Q
#allow system_app vendor_file:file { getattr };
allow system_app cache_file:dir search;
#set_prop(system_app,exported_system_prop)
set_prop(system_app,powerctl_prop)

allow system_app abc_data_file:file { read getattr };
allow system_app abc_data_file:dir { open getattr read search };

set_prop(system_app, debug_prop)

rw_rockchip_graphic_device(system_app)

allow system_app block_device:dir { search read open getattr };
allow system_app mnt_media_rw_file:dir { search read open getattr };
allow system_app asec_apk_file:dir { search read open getattr };

hal_client_domain(system_app, hal_light)
hal_client_domain(system_app, hal_power)
hal_client_domain(system_app, hal_health)
binder_call(system_app, hal_keymint_default)
binder_call(system_app, hal_usb_impl)
binder_call(system_app, update_engine)
allow system_app proc_pagetypeinfo:file r_file_perms;

allow system_app mnt_sdcard_file:lnk_file r_file_perms;
allow system_app mnt_pass_through_file:dir r_file_perms;
allow system_app system_data_file:dir { read open };

<think> 我们正在讨论的是Android 14系统。在Android系统中,特别是从Android 4.4(KitKat)开始,对于外部存储的访问权限逐渐收紧。在Android 10(Q)及以上版本,特别是Android 11(R)引入了作用域存储(Scoped Storage),使得应用不能随意在外部存储的根目录创建文件夹(除非使用特定的存储访问框架者获得特殊权限)。 但是,请注意:用户问题中提到的“根目录”可能有不同的含义: 1. 外部存储的根目录(即通常的/sdcard/storage/emulated/0等)。 2. 系统根目录(即Linux文件系统根目录,如/)。 根据引用[1]和[3]的内容,用户似乎是想在外部存储的根目录(如/sdcard)下创建文件夹。而引用[2]则描述的是在系统根目录(ramdisk)下创建目录,这通常需要系统级权限(比如制作ROM时修改ramdisk)。 由于用户明确提到“Android 14系统根目录”,我们需要区分两种情况: 情况1:用户指的是外部存储的根目录(即用户通常可见的存储根目录,如/sdcard/CAT_IMG) 情况2:用户指的是系统根目录(即/,例如/system, /data等) 从用户描述的需求(创建CAT_IMG文件夹并在列表视图中检索)来看,应该是情况1(外部存储根目录)。但用户的问题明确写了“根目录”,并且引用[4]提到了U盘自动生成根目录文件夹(也是外部存储),而引用[2]提到了系统根目录。 然而,在Android 14中: - 对于外部存储根目录:应用默认只能访问自己专属的外部存储目录(通过Context#getExternalFilesDir())和媒体集合(如图片、视频等)。在外部存储根目录创建文件夹需要特殊权限(如MANAGE_EXTERNAL_STORAGE)者使用系统文件选择器让用户选择位置(Storage Access Framework)。 - 对于系统根目录:普通应用无法在系统根目录(/)下创建文件夹,因为这需要root权限,并且系统分区是只读的。只有系统级应用(有系统签名)者在刷机时修改系统镜像(如ramdisk)才能做到。 鉴于用户需求是在根目录创建CAT_IMG文件夹并能在列表视图中检索,我们假设用户指的是外部存储的根目录(即/sdcard/CAT_IMG),因为这是应用可能实现的需求(尽管有权限限制)。至于系统根目录(/)下的创建,普通应用无法做到,我们在此不讨论。 因此,我们聚焦于在外部存储根目录创建文件夹的方法(针对Android 14): 方法1:使用MANAGE_EXTERNAL_STORAGE权限(不推荐,因为需要用户手动授权,且Google Play审核严格) - 在AndroidManifest.xml中添加权限:<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> - 然后使用Environment.getExternalStorageDirectory()(已废弃)MediaStore API来操作。 - 但是,从Android 11开始,MANAGE_EXTERNAL_STORAGE权限允许应用访问整个外部存储,但需要用户手动在设置中授予权限(通过Intent引导用户到设置页面)。 方法2:使用Storage Access Framework(推荐) - 通过Intent.ACTION_OPEN_DOCUMENT_TREE让用户选择一个目录(包括根目录),然后通过DocumentFile在该目录下创建文件夹文件。 方法3:如果应用是系统应用(预装在系统分区),则可以使用系统签名,那么就可以直接操作外部存储根目录(无需请求MANAGE_EXTERNAL_STORAGE权限)。但普通应用不行。 另外,在Android 10及以上,Environment.getExternalStorageDirectory()已被废弃。官方建议使用Context#getExternalFilesDir()来访问应用专属目录,者使用MediaStore API访问共享媒体文件。 针对用户需求(在根目录创建CAT_IMG文件夹),我们给出两种方案: 方案一(使用MANAGE_EXTERNAL_STORAGE): 步骤1:在AndroidManifest.xml中添加: <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> 步骤2:检查是否已经获得权限,如果没有则引导用户设置: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } } 步骤3:获得权限后,创建文件夹: File root = Environment.getExternalStorageDirectory(); // 虽然废弃,但在获得MANAGE_EXTERNAL_STORAGE权限后仍可用 File catImgDir = new File(root, "CAT_IMG"); if (!catImgDir.exists()) { catImgDir.mkdirs(); } 注意:此方法在Android 11及以上需要用户手动授权,且Google Play可能会要求应用必须满足核心功能需要使用此权限,否则可能被拒绝上架。 方案二(使用Storage Access Framework,不需要特殊权限): 步骤1:使用Intent.ACTION_OPEN_DOCUMENT_TREE选择外部存储根目录(用户选择)。 步骤2:在onActivityResult中获取用户选择的目录的Uri,然后使用DocumentFile来创建文件夹。 示例代码: // 请求用户选择外部存储的根目录 Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.putExtra("android.provider.extra.INITIAL_URI", Uri.parse("content://com.android.externalstorage.documents/root/primary")); startActivityForResult(intent, REQUEST_CODE_OPEN_DIRECTORY); // 在onActivityResult中 if (requestCode == REQUEST_CODE_OPEN_DIRECTORY && resultCode == RESULT_OK) { Uri treeUri = data.getData(); // 保存这个Uri(为了以后使用,需要持久化保存并调用takePersistableUriPermission) getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 使用DocumentFile从Uri创建代表根目录的DocumentFile DocumentFile root = DocumentFile.fromTreeUri(this, treeUri); // 创建CAT_IMG文件夹 DocumentFile catImgDir = root.createDirectory("CAT_IMG"); if (catImgDir != null && catImgDir.exists()) { // 创建成功 } } 注意:此方法需要用户交互,用户必须选择根目录(通常显示为“内部存储”)。 方案二虽然不需要特殊权限,但需要用户主动选择,而且创建的位置取决于用户的选择(不一定是根目录,也可以是其他位置)。如果用户没有选择根目录,那么创建的CAT_IMG文件夹就在用户选择的目录下。 总结:对于普通应用,在Android 14上,推荐使用Storage Access Framework(方案二)来让用户选择目录并创建文件夹,这样不需要特殊权限,也符合Google的存储政策。 另外,引用[4]提到的是在插入U盘时创建根目录文件夹,这属于系统级别的操作(MediaProvider内部),普通应用无法直接使用。 因此,针对用户的问题,我们提供两种方法,并说明各自的优缺点。 注意:用户的问题中引用了[1]到[4],但根据上下文,我们主要参考了[1]和[3](外部存储)以及[2](系统根目录,但用户可能不是这个需求)。我们按照用户描述的需求(在根目录创建CAT_IMG文件夹并检索)给出了外部存储根目录创建方法。 如果用户确实是指系统根目录(如/),那么需要root权限系统签名,普通应用无法实现。这种情况下,建议用户使用具有root权限的设备,并通过Runtime.getRuntime().exec("su")执行shell命令(如mkdir)来创建。但root方法不稳定且不安全,且大多数用户设备没有root。 根据问题,我们推断用户的需求是在外部存储根目录创建文件夹,所以重点放在外部存储根目录上。 最后,我们生成相关问题。 </think> 在Android 14系统创建根目录文件夹需区分两种场景,具体实现方法如下: ### 一、外部存储根目录(如/sdcard) 适用于创建用户可见文件夹(如CAT_IMG),需遵循Android存储权限策略: ```java // 在外部存储根目录创建CAT_IMG文件夹 String folderName = "CAT_IMG"; File directory = new File(Environment.getExternalStorageDirectory(), folderName); // 检查权限(Android 10+需作用域存储) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Environment.isExternalStorageManager()) { // 已授权MANAGE_EXTERNAL_STORAGE if (!directory.exists()) directory.mkdirs(); } else { // 引导用户开启权限(Android 11+) Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } } else { // Android 10以下使用传统权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { if (!directory.exists()) directory.mkdirs(); } } ``` **关键配置**: 1. AndroidManifest.xml添加权限: ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <!-- Android 11+ --> ``` 2. 对于Android 11+,需在AndroidManifest.xml添加: ```xml <application ... android:requestLegacyExternalStorage="true"> ``` ### 二、系统根目录(如/system) **仅限系统级应用ROM开发**,需修改ramdisk镜像: 1. 解压boot.img获取ramdisk 2. 在ramdisk根目录创建目录结构: ``` ├── factory │ └── bin # 目标目录 ``` 3.init.rc中添加挂载逻辑: ```shell on early-init mkdir /factory/bin 0755 root root ``` 4. 重新打包ramdisk并刷入设备[^2] ### 注意事项 1. **普通应用无法写入系统根目录**:Android沙盒机制限制应用只能访问`/data/data/包名`目录 2. 外部存储权限变化: - Android 10+:默认禁用访问根目录,需使用MediaStore APIMANAGE_EXTERNAL_STORAGE - Android 14:需在Google Play声明合法用例才能使用MANAGE_EXTERNAL_STORAGE 3. U盘自动挂载:系统级功能由vold服务实现,普通应用需通过StorageManager监听挂载事件[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值