Android系统 应用存储路径与权限


Android系统 文件访问权限笔记
Android系统 理解/sys/目录权限和UID和GID?
Android系统 应用存储路径与权限
Android系统 自定义系统和应用权限
Android系统 AppOps默认授予应用相应的权限
Android系统 权限组管理和兼容性


数据和文件存储概览 | Android 开发者 | Android Developers..

Android应用的存储路径分为内部和外部存储。内部存储固定且小,外部存储如SD卡容量大但可能不稳定。应用在这两种存储中都有私有目录,仅该应用可访问且随应用卸载而删除。外部存储的公共目录可被其他应用访问,且不随应用卸载而删除。

存储类型特点是否私有是否随应用卸载删除是否可被其他应用访问
内部存储固定且容量小
外部存储(专属目录)容量大,可能不稳定
外部存储(公共目录)容量大,可能不稳定

Android应用的文件访问能力基于其请求的权限。与存储相关的权限有READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE和MANAGE_EXTERNAL_STORAGE。Android 10及以上版本引入了分区存储,限制应用只能访问其专属目录和特定媒体文件。

权限名称功能描述Android 10及以上版本的特点
READ_EXTERNAL_STORAGE读取外部存储中的文件只能访问专属目录和特定媒体文件
WRITE_EXTERNAL_STORAGE写入外部存储中的文件只能访问专属目录和特定媒体文件
MANAGE_EXTERNAL_STORAGE管理外部存储的文件可以访问和管理所有文件

Android文件系统和目录结构

Android有特殊类型的应用,根据其存储路径和权限不同,分为系统预装应用、特权系统应用、用户安装应用和平台签名应用。它们的存储位置和权限级别各不相同。
这些特殊类型的应用包括:

应用类型存储路径权限级别是否可被用户卸载特点
系统预装应用/system/app系统预装
特权系统应用/system/priv-app最高系统预装、且具有特权签名
用户安装应用/data/app普通通过商店或手动安装
平台签名应用/system/app/system/priv-app高至最高取决于存储位置使用与系统相同的签名密钥
Android文件系统概述

Android文件系统是一种基于Linux的文件系统,它用于管理设备上的文件和目录。Android文件系统可以分为两个主要部分:系统分区和数据分区。系统分区是指存储设备上的一块固定大小的空间,它用于存储Android系统的核心组件,如内核,引导加载器,恢复模式,系统应用等。数据分区是指存储设备上的剩余空间,它用于存储用户数据,如应用,照片,音乐,文档等。

Android目录结构和主要目录的作用

Android文件系统包含多个主要目录,如根目录、系统分区、数据分区、外部存储、缓存和设备文件目录。每个目录都有其特定的作用和访问权限。

目录名称描述访问权限主要用途
/根目录取决于子目录所有其他目录的父目录
/system系统分区根目录通常只读 (除非有root权限 umount)存储Android系统核心组件和配置
/data数据分区根目录可读写 (需要权限)存储用户数据和应用数据
/sdcard外部存储根目录可读写 (需要权限)存储用户在外部存储的文件
/cache临时缓存目录可读写存储临时文件,如更新包
/dev设备文件目录通常只读 (需要特殊权限)表示设备上的硬件

此外,还有其他目录如/proc/sys/mnt等,用于特定的系统任务和功能。

/system/app目录的作用和特性

/system/app目录存储系统预装或通过刷机安装的应用。这些应用具有高权限,不可被用户卸载,且在设备启动时自动加载。它们通常使用系统签名,不需申请运行时权限,并可通过sharedUserId共享数据。安装应用到此目录可以通过adb命令或刷机包。

特性/操作描述
目录作用与特性
访问权限通常只读,需要root/remount权限进行修改
加载时机设备启动时自动加载
权限与API可访问系统保护的权限和API
文件访问可访问所有文件和目录
应用特点
签名通常使用与系统相同的签名
权限请求使用AndroidManifest.xml声明,无需运行时权限
数据共享使用sharedUserId共享UID和进程空间
安装方法
使用adb使用adb命令复制应用到目录,修改权限和所有者
预置系统打包固件的时候预置进系统

/system/priv-app目录的作用和特性

/system/priv-app目录存储具有特权签名的系统预装或刷机安装应用。这些应用具有最高权限,不可被用户卸载。它们在设备启动时加载,可访问所有权限/API,并通常使用系统签名。

/data/app目录的作用和特性

特性/操作描述
目录作用与特性
访问权限通常只读,需要root或刷机操作进行修改
加载时机设备启动时自动加载
权限与API可访问所有权限和API,包括特权权限
文件访问可访问所有文件和目录
应用特点
签名必须使用与系统相同的签名,并声明android:sharedUserId="android.uid.system"
权限请求可直接使用任何权限,无需声明
数据共享使用sharedUserId共享UID和进程空间
安装方法
使用adb使用adb命令复制应用到目录,修改权限和所有者
预置系统打包固件的时候预置进系统

/data/app目录存储用户通过商店或其他渠道安装的应用。这些应用具有普通权限,可被用户卸载。它们在安装或更新时加载,可访问普通权限/API,但需申请运行时权限。

特性/操作描述
目录作用与特性
访问权限可读写,需root或adb shell权限
加载时机用户安装或更新时加载
权限与API可访问普通权限/API,不可访问系统保护权限
文件访问可访问专属目录/特定媒体,需特权或SAF访问其他
应用特点
签名使用自己的签名密钥
权限请求需声明和申请运行时权限
数据共享通常不使用sharedUserId共享UID/进程空间
安装方法
商店/其他渠道使用Google Play等商店安装应用
使用adb使用adb命令复制应用到目录,修改权限和所有者
预置系统打包固件的时候预置进系统

平台签名的app使用与系统相同的签名密钥,允许它们访问特权权限和API。这些应用通常位于/system/app/system/priv-app。它们可以直接使用任何权限,不需申请运行时权限,并可能使用sharedUserId共享数据。

平台签名的app的权限特性

特性/操作描述
权限特性
权限与API可访问所有权限和API,包括特权权限
权限请求不需使用AndroidManifest.xml声明或申请运行时权限
数据共享使用sharedUserId共享UID和进程空间
请求与使用方法
使用AndroidManifest.xml声明所需权限,无需用户授权
使用代码直接调用API,无需权限检查

普通app的权限特性

普通app是指使用自己的签名密钥签名的应用,它们没有任何特殊的存储路径或者权限特性。这些应用可以存储在任何目录中,但是通常存储在/data/app中。例如,一些自己开发或者下载的应用,都是普通app。

普通app的权限特性有以下几点:

  • 普通app可以访问一些普通的权限和API,例如访问网络,读取位置,拍照等。但是它们不能访问一些系统保护的权限和API,例如修改系统设置,访问电话状态,读取联系人等。
  • 普通app需要使用AndroidManifest.xml文件中声明的权限和运行时权限来请求和使用权限。运行时权限是指一些敏感的权限,它们需要在应用运行时向用户申请授权才能使用。例如,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE等。
  • 普通app通常不使用AndroidManifest.xml文件中声明的sharedUserId属性来共享UID和进程空间的,因为这样会增加安全风险和兼容性问题。

普通app如何请求和使用权限呢?有以下几种方法:

  • 使用AndroidManifest.xml文件:需要在AndroidManifest.xml文件中声明想要使用的权限,并且根据不同版本的Android系统来申请运行时权限。例如,如果想要使用READ_EXTERNAL_STORAGE权限,需要在AndroidManifest.xml文件中添加以下代码:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  • 使用代码:需要在代码中检查并申请运行时权限,并且处理用户的授权结果。例如,如果想要读取外部存储空间中的文件,需要在代码中使用以下代码:
// 定义一个常量作为请求码
private static final int REQUEST_CODE_READ_EXTERNAL_STORAGE = 1;

// 检查是否已经有READ_EXTERNAL_STORAGE权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    // 如果已经有了,直接读取文件
    readFileFromExternalStorage();
} else {
    // 如果没有,向用户申请
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE_READ_EXTERNAL_STORAGE);
}

// 重写onRequestPermissionsResult方法来处理用户的授权结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    // 判断请求码是否匹配
    if (requestCode == REQUEST_CODE_READ_EXTERNAL_STORAGE) {
        // 判断授权结果是否成功
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 如果成功,读取文件
            readFileFromExternalStorage();
        } else {
            // 如果失败,提示用户
            Toast.makeText(this, "You need to grant READ_EXTERNAL_STORAGE permission to read files", Toast.LENGTH_SHORT).show();
        }
    }
}

// 定义一个方法来读取外部存储空间中的文件
private void readFileFromExternalStorage() {
    // 获取外部存储空间的根目录
    File externalStorageDirectory = Environment.getExternalStorageDirectory();
    // 创建一个文件对象表示要读取的文件
    File file = new File(externalStorageDirectory, "test.txt");
    // 创建一个输入流对象来读取文件内容
    try (FileInputStream fis = new FileInputStream(file)) {
        // 创建一个字节数组来存储文件内容
        byte[] buffer = new byte[fis.available()];
        // 将文件内容读取到字节数组中
        fis.read(buffer);
        // 将字节数组转换为字符串
        String content = new String(buffer);
        // 显示文件内容
        Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
        // 处理异常情况
        e.printStackTrace();
    }
}

不同类型应用的存储路径和权限区别

不同的应用存储路径如/system/app, /system/priv-app, 和 /data/app具有不同的存储和权限特性。系统和特权应用通常存储在系统分区,具有更高的权限,而普通应用存储在数据分区,权限较低。选择应用的安装位置和权限应基于应用的类型、需求和安全性。

表格:

特性/操作/system/app & /system/priv-app/data/app
存储特性
存储位置系统分区数据分区
存储方式刷机/adb命令商店/其他渠道
用户操作需要root/刷机操作用户自由安装/卸载
权限特性
权限级别高级权限 & API普通权限 & API
权限申请不需运行时权限需要运行时权限
数据共享可使用sharedUserId通常不使用sharedUserId
建议
权限最小化
使用普通权限
使用运行时权限
  1. 普通应用使用了系统平台签名 但不使用android:sharedUserId=“android.uid.system”:

    • 这种应用使用了与系统相同的签名密钥,因此它可以被视为一个平台签名的app。但由于它没有使用android:sharedUserId="android.uid.system",它不会具有与系统应用相同的UID,所以它不是特权应用。
  2. 普通应用使用了系统平台签名 使用android:sharedUserId=“android.uid.system”:

    • 这种应用使用了与系统相同的签名密钥并且使用了android:sharedUserId="android.uid.system",因此它可以被视为一个特权应用
  3. 普通应用如果Android源码预置到/system/app & /system/priv-app:

    • 如果预置在/system/app,它仍然是一个系统应用,但可能没有特权应用的所有权限。
    • 如果预置在/system/priv-app,它是一个特权应用,因为这个目录是为具有特权签名的应用预留的。
  4. 查看 /system/app, /system/priv-app 和 /data/app 中的应用:

    • 首先,确保你的设备已经连接到电脑并且 ADB 正在运行。
    • 打开命令行或终端。
    • 输入以下命令:
      adb shell
      
    • 然后,你可以使用 ls 命令来查看各个目录中的内容:
      ls /system/app
      ls /system/priv-app
      ls /data/app
      
  5. 区分 shareid 和签名:

    • Android 的应用可以使用相同的 sharedUserId 来共享数据和代码。这通常在 AndroidManifest.xml 文件中定义。要查看应用的 sharedUserId,你可以使用以下命令:
      dumpsys package <package_name> | grep Share
      

    在这里插入图片描述

     其中 `<package_name>` 是你想要查询的应用的包名。
    
    • 对于签名,你可以使用以下命令来获取应用的签名信息:
      dumpsys package <package_name> | grep Sign
      

    注意:这些命令可能会返回大量的信息,所以你可能需要仔细查看或使用更多的 grep 命令来过滤结果。


希望这篇文章能对您有所帮助。如果还有其他问题或建议,请留言与私信。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用UE5打包游戏之后,如果需要读取外部文件,可以采用以下两种方式: 1. 通过使用相对路径或绝对路径来读取外部文件。代码中可以使用FFileHelper::LoadFileToArray()或FFileHelper::LoadFileToString()函数来实现读取外部文件的操作。需要注意的是,读取文件的路径应该是相对于游戏运行时的根目录或绝对路径。 2. 将外部文件打包进游戏中一起打包进去。具体步骤为将外部文件拷贝到项目目录下的 Content 文件夹内,然后在 UE5 中将它们导入到项目中。最后编译时在设置中将这些文件都勾选上,它们就会自动被打包到游戏中。在游戏运行时,可以使用FPaths::GameContentDir()函数获得游戏运行时的 Content 目录路径,然后利用FFileHelper::LoadFileToArray()来读取文件。 无论采用哪种方式,都需要注意文件路径的正确性及文件名的拼写正确性。另外,对于需要读取的外部文件类型,如图像、音频文件等,需要有相应的解析模块进行解码,然后才能使用。 ### 回答2: 在UE5中,如果需要在打包后读取外部文件,可以使用“虚拟文件系统(Virtual File System)”这一功能。虚拟文件系统是UE5中的一个新特性,其目的是为了在游戏或应用运行时快速加载和管理不同类型的文件。 首先,在代码中需要使用VirtualFileSystem模块来访问虚拟文件系统。可以使用VirtualFileSystem的API来加载和卸载文件。为了确保能在打包后正常运行,需要将需要读取的外部文件添加到虚拟文件系统载入的目录中。 在将外部文件添加到虚拟文件系统载入目录的时候,需要使用UpdateFileRedirects命令。这个命令可以在项目打包前执行,也可以在运行时执行。添加文件路径后,虚拟文件系统会自动将路径中的文件转换为虚拟文件,这样在运行时就可以正常访问。 例如,在虚拟文件系统中添加D:/Test/目录作为载入目录,而当前项目需要读取D:/Test/test.txt文件。可以通过以下代码来访问: ```c++ // 加载文件 FString TestFilePath = "/Test/test.txt"; const FString& TestFileContent = FVirtualFileSystem::LoadFileToString(TestFilePath); // 卸载文件 FVirtualFileSystem::FlushFiles(TestFilePath); ``` 这样,就可以在虚拟文件系统中成功读取外部的test.txt文件并加载到程序中。 总之,在UE5中读取外部文件需要使用虚拟文件系统这一特性,将需要读取的文件添加到载入目录中,并使用VirtualFileSystem模块的API访问即可。 ### 回答3: 在使用UE5打包游戏的过程中,有时候我们需要将一些外部文件(比如文本、图片等)加载到游戏中去,以丰富游戏内容。这时候,我们需要将这些外部文件与游戏一起打包,然后在运行游戏时,通过代码读取这些文件并将其加载到游戏中。 在UE5中,读取外部文件的方式与UE4类似,可以使用FFileHelper和FArchive等类来实现。具体而言,可以采用以下步骤来读取外部文件: 1. 将需要加载的文件放置在游戏的Content或者其他自定义的文件夹中。 2. 在代码中使用FFileHelper或者FArchive等类的方法来读取文件,比如: FString Path = FPaths::ProjectContentDir() + "xxfile.txt"; FString Result; if (FFileHelper::LoadFileToString(Result, *Path)) { UE_LOG(LogTemp, Warning, TEXT("Read file success! content: %s"), *Result); } else { UE_LOG(LogTemp, Warning, TEXT("Read file failed!")); } 这段代码的作用是读取Content文件夹中的xxfile.txt文件,将其内容读取到Result变量中,并在日志中输出读取结果。 需要注意的是,在使用FArchive读取文件时,需要考虑文件的大小和读取的速度,以及内存的占用等问题,需要选择合适的读取方式来保证游戏的性能和稳定性。 综上所述,通过使用FFileHelper和FArchive等类来读取外部文件,可以很方便地将外部资源加载到游戏中,提高游戏的可玩性和趣味性。同时,需要注意文件的路径、大小和读取方式等问题,以保证游戏的性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值