《Android加密之全盘加密》
《Android系统之System Server大纲》
Android 的安全性问题一直备受关注,Google 在 Android 系统的安全方面也是一直没有停止过更新,努力做到更加安全的手机移动操作系统。
在 Android 的安全性方面,有很多模块:
其中,加密又分全盘加密(Android 4.4 引入,《Android加密之全盘加密》)和文件级加密(Android 7.0 引入),本文将论述加密中的文件级加密的基本知识。
Android 7.0 及更高版本支持文件级加密 (FBE)。采用文件级加密时,可以使用不同的密钥对不同的文件进行加密,并且可以对这些文件进行单独解密。
借助文件级加密,Android 7.0 中引入了一项称为直接启动的新功能。该功能处于启用状态时,已加密设备在启动后将直接进入锁定屏幕。之前,在使用全盘加密 (FDE) 的已加密设备上,用户在访问任何数据之前都需要先提供凭据,从而导致手机无法执行除最基本操作之外的所有其他操作。例如,闹钟无法运行,无障碍服务不可用,手机无法接电话,而只能进行基本的紧急拨号操作。
引入文件级加密 (FBE) 和新 API 后,便可以将应用设为加密感知型应用,这样一来,它们将能够在受限环境中运行。这些应用将可以在用户提供凭据之前运行,同时系统仍能保护私密用户信息。
在启用了 FBE 的设备上,每位用户均有两个可供应用使用的存储位置:
这种区分能够使工作资料更加安全,因为这样一来,加密不再只基于启动时密码,从而能够同时保护多位用户。
Direct Boot API 允许加密感知型应用访问上述每个区域。应用生命周期会发生一些变化,以便在用户的 CE 存储空间因用户在锁定屏幕上首次输入凭据而解锁时,或者在工作资料提供工作挑战时,通知应用。无论是否实现了 FBE,运行 Android 7.0 的设备都必须要支持这些新的 API 和生命周期。不过,如果没有 FBE,DE 和 CE 存储空间将始终处于解锁状态。
通过将不带参数的 fileencryption 标记添加到 userdata 分区最后一列的 fstab 行中,可以启用 FBE。
为了实现系统应用的快速迁移,新增了两个可在应用级别设置的属性。defaultToDeviceProtectedStorage 属性仅适用于系统应用,directBootAware 属性则适用于所有应用。
android:defaultToDeviceProtectedStorage="true">
应用级别的 directBootAware 属性的含义是将相应应用中的所有组件均标记为加密感知型组件。
defaultToDeviceProtectedStorage 属性用于将默认的应用存储位置重定向到 DE 存储空间(而非 CE 存储空间)。使用此标记的系统应用必须要仔细审核存储在默认位置的所有数据,并将敏感数据的路径更改为使用 CE 存储空间。使用此选项的设备制造商应仔细检查要存储的数据,以确保其中不含任何个人信息。
在这种模式下运行时,以下系统 API 可在需要时用于明确管理由 CE 存储空间支持的 Context(这些 API 与设备保护存储空间适用的同类 API 相对应)。
DE 存储空间支持的 Context
首次创建设备的 userdata 分区时,会由 init 脚本应用基本结构和政策。这些脚本将触发创建首位用户(用户 0)的 CE 密钥和 DE 密钥,并定义要使用这些密钥加密哪些目录。创建其他用户和资料时,会生成必要的其他密钥并将其存储在密钥代码库中;接下来会创建它们的凭据和设备存储位 置,并且加密政策会将这些密钥关联到相应目录。
DE密钥
触发 late-init action
// 开机执行init.cpp,
int main(int argc, char** argv) {
......
// 解析 init.rc file
Parser& parser = Parser::GetInstance();
parser.ParseConfig("/init.rc");
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = property_get("ro.bootmode");
if (bootmode == "charger") {
am.QueueEventTrigger("charger");
} else {
// 触发 late-init action
am.QueueEventTrigger("late-init");
}
......
}
这个方法定义在文件 system/core/init/init.cpp 中。
触发 post-fs-data
on late-init
.....
trigger post-fs
# Now we can mount /data. File encryption requires keymaster to decrypt
# /data, which in turn can only be loaded when system properties are present
trigger post-fs-data
.....
这个 action 定义在文件 system/core/rootdir/init.rc 中。
执行 installkey 命令
on post-fs-data
chown system system /data
chmod 0771 /data
# Make sure we have the device encryption key.
start vold
#执行 installkey 命令
installkey /data
这个 action 定义在文件 system/core/rootdir/init.rc 中。
命令 installkey 实质执行 do_installkey 函数
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits::max();
static const Map builtin_functions = {
.....
{"installkey", {1, 1, do_installkey}},
{"load_persist_props", {0, 0, do_load_persist_props}},
.....
};
return builtin_functions;
这个方法定义在文件 system/core/init/builtins.cpp 中。
do_installkey() 函数定义如下
// 是否是 文件级加密
static bool is_file_crypto() {
// 文件级加密 ro.crypto.type 的值是 file, 全盘加密是 block
std::string value = property_get("ro.crypto.type");
return value == "file";
}
static int do_installkey(const std::vector& args) {
// 检查是否是文件级加密
if (!is_file_crypto()) {
return 0;
}
// 创建密钥
return e4crypt_create_device_key(args[1].c_str(),
do_installkeys_ensure_dir_exists);
}
这个方法定义在文件 system/core/init/builtins.cpp 中。
ro.crypto.type 在函数 do_mount_all() 中设置
static int do_mount_all(const std::vector& args) {
} else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
return -1;
}
property_set("ro.crypto.state", "encrypted");
//文件级加密
property_set("ro.crypto.type", "file");
}
这个方法定义在文件 system/core/init/builtins.cpp 中。
回到 do_installkey() 函数,e4crypt_create_device_key() 定义如下
int e4crypt_create_device_key(const char* dir,
int ensure_dir_exists(const char*))
{
init_logging();
.....
// 执行 vdc, 传入命令 enablefilecrypto, 同时需要注意参数 cryptfs
const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto" };
// 从 init, 到 vdc, 注意参数 argv[]
int rc = android_fork_execvp(4, (char**) argv, NULL, false, true);
LOG(INFO) << "enablefilecrypto result: " << rc;
return rc;
}
这个方法定义在文件 system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中。
android_fork_execvp() 实质是调用函数 android_fork_execvp_ext()
static inline int android_fork_execvp(int argc, char* argv[], int *status,
bool ignore_int_quit, bool logwrap)
{
// 实质是调用函数这个函数
return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
(logwrap ? LOG_ALOG : LOG_NONE), false, NULL,
NULL, 0);
}
这个方法定义在文件 system/core/logwrapper/include/logwrap/logwrap.h 中。
函数 android_fork_execvp_ext() 的实现如下
int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
int log_target, bool abbreviated, char *file_path,
const struct AndroidForkExecvpOption* opts, size_t opts_len) {
// fork 一个新的进程运行 vdc 程序
pid = fork();
if (pid < 0) {
.....
} else if (pid == 0) {
.....
// fork 进程成功, 执行函数 child()
child(argc, argv);
} else {
}
这个方法定义在文件 system/core/logwrapper/logwrap.c 中。
static void child(int argc, char* argv[]) {
// create null terminated argv_child array
char* argv_child[argc + 1];
memcpy(argv_child, argv, argc * sizeof(char *));
argv_child[argc] = NULL;
// 开始运行 vdc 程序,参数 cryptfs, enablefilecrypto
// 从 init 进程,进入到 vdc 进程
if (execvp(argv_child[0], argv_child)) {
FATAL_CHILD("executing %s failed: %s\n", argv_child[0],
strerror(errno));
}
}
这个方法定义在文件 system/core/logwrapper/logwrap.c 中。
int main(int argc, char **argv) {
// 定义待连接的 socket 标识
const char* sockname = "vold";
//在上面的参数中 argv[1] 等于 cryptfs, 所以 socket name 等于 cryptd
if (!strcmp(argv[1], "cryptfs")) {
sockname = "cryptd";
}
// 等待连接到 vold
while ((sock = socket_local_client(sockname,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM)) < 0) {
.....
}
if (!strcmp(argv[1], "monitor")) {
exit(do_monitor(sock, 0));
} else {
//argv[1] 等于 cryptfs, 执行函数 do_cmd()
exit(do_cmd(sock, argc, argv));
}
}
这个方法定义在文件 system/vold/vdc.cpp 中。
static int do_cmd(int sock, int argc, char **argv) {
.....
// 写入 socket,注意参数 cmd.c_str()
if ((write(sock, cmd.c_str(), cmd.length() + 1)) < 0) {
fprintf(stderr, "Failed to write command: %s\n", strerror(errno));
return errno;
}
return do_monitor(sock, seq);
}
这个方法定义在文件 system/vold/vdc.cpp 中。
socket 写入数据到远程后,执行到 vold 进程
int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if (subcommand == "checkpw") {
.....
}
.....
//传入的命令是 enablefilecrypto
} else if (subcommand == "enablefilecrypto") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
dumpArgs(argc, argv, -1);
rc = cryptfs_enable_file();
}
.....
}
这个方法定义在文件 system/vold/CryptCommandListener.cpp 中。
函数 cryptfs_enable_file() 定义如下
int cryptfs_enable_file()
{
return e4crypt_initialize_global_de();
}
这个函数定义在文件 system/vold/cryptfs.c 中。
bool e4crypt_initialize_global_de() {
.....
// device_key_path = /data/unencrypted/key/
if (path_exists(device_key_path)) {
if (!android::vold::retrieveKey(device_key_path,
kEmptyAuthentication, &device_key)) return false;
} else {
LOG(INFO) << "Creating new key";
// 创建 密钥
if (!random_key(&device_key)) return false;
// 保存密钥
if (!store_key(device_key_path, device_key_temp,
kEmptyAuthentication, device_key)) return false;
}
std::string device_key_ref;
//存储在密钥代码库中
if (!install_key(device_key, &device_key_ref)) {
LOG(ERROR) << "Failed to install device key";
return false;
}
// 应用密钥
std::string ref_filename = std::string("/data") + e4crypt_key_ref;
if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
PLOG(ERROR) << "Cannot save key reference";
return false;
}
s_global_de_initialized = true;
return true;
}
DE密钥创建过程就分析到这里。
CE密钥
同样在 init.rc 的 post-fs-data action 中
on post-fs-data
.....
installkey /data
.....
执行 init_user0 命令
init_user0
.....
这个 action 定义在文件 system/core/rootdir/init.rc 中。
init_user0 实质是执行函数
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits::max();
static const Map builtin_functions = {
.....
{"ifup", {1, 1, do_ifup}},
//执行 do_init_user0() 函数
{"init_user0", {0, 0, do_init_user0}},
.....
}
这个方法定义在文件 system/core/init/builtins.cpp 中。
函数 do_init_user0() 定义如下
static int do_init_user0(const std::vector& args) {
//直接调用了函数 e4crypt_do_init_user0()
return e4crypt_do_init_user0();
}
这个方法定义在文件 system/core/init/builtins.cpp 中。
函数 e4crypt_do_init_user0() 定义如下
int e4crypt_do_init_user0()
{
init_logging();
//执行 vdc , 参数 cryptfs 和 init_user0, 和 DE 的创建过程类似
const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "init_user0" };
// fork vdc 进程,并运行 vdc 程序
int rc = android_fork_execvp(4, (char**) argv, NULL, false, true);
LOG(INFO) << "init_user0 result: " << rc;
return rc;
}
这个方法定义在文件 system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中。
函数 android_fork_execvp() 运行 vdc 后,vdc 并没有做什么具体的操作,只是把相应的参数继续传递给 vold,和 DE 的密钥创建过程一样,参数 "cryptfs" 和 参数 "init_user0" 决定会执行到 vold 的如下代码
int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
.....
} else if (subcommand == "init_user0") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
//执行函数 e4crypt_init_user0()
return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
.....
}
这个方法定义在文件 system/vold/CryptCommandListener.cpp 中。
函数 e4crypt_init_user0() 定义如下
bool e4crypt_init_user0() {
LOG(DEBUG) << "e4crypt_init_user0";
if (e4crypt_is_native()) {
// user_key_dir 等于 data/misc/vold/user_keys
if (!prepare_dir(user_key_dir, 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/ce", 0700, AID_ROOT, AID_ROOT)) return false;
if (!prepare_dir(user_key_dir + "/de", 0700, AID_ROOT, AID_ROOT)) return false;
if (!path_exists(get_de_key_path(0))) {
//创建和安装 CD keys, user 为 0, 即开机默认的 user
if (!create_and_install_user_keys(0, false)) return false;
}
// TODO: switch to loading only DE_0 here once framework makes
// explicit calls to install DE keys for secondary users
if (!load_all_de_keys()) return false;
}
// We can only safely prepare DE storage here, since CE keys are probably
// entangled with user credentials. The framework will always prepare CE
// storage once CE keys are installed.
if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
LOG(ERROR) << "Failed to prepare user 0 storage";
return false;
}
// If this is a non-FBE device that recently left an emulated mode,
// restore user data directories to known-good state.
if (!e4crypt_is_native() && !e4crypt_is_emulated()) {
e4crypt_unlock_user_key(0, 0, "!", "!");
}
return true;
}
这个方法定义在文件 system/vold/Ext4Crypt.cpp 中。
函数 create_and_install_user_keys() 定义如下
static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
std::string de_key, ce_key;
//创建 DE 密钥
if (!random_key(&de_key)) return false;
//创建 CE 密钥
if (!random_key(&ce_key)) return false;
.....
std::string de_raw_ref;
// 存储 DE 密钥到密钥代码库
if (!install_key(de_key, &de_raw_ref)) return false;
s_de_key_raw_refs[user_id] = de_raw_ref;
std::string ce_raw_ref;
// 存储 CE 密钥到密钥代码库
if (!install_key(ce_key, &ce_raw_ref)) return false;
s_ce_keys[user_id] = ce_key;
s_ce_key_raw_refs[user_id] = ce_raw_ref;
LOG(DEBUG) << "Created keys for user " << user_id;
return true;
}
这个方法定义在文件 system/vold/Ext4Crypt.cpp 中。
再看看密钥的真正生成过程 random_key()
static bool random_key(std::string* key) {
// 读取随机密钥
if (android::vold::ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) {
// TODO status_t plays badly with PLOG, fix it.
LOG(ERROR) << "Random read failed";
return false;
}
return true;
}
这个方法定义在文件 system/vold/Ext4Crypt.cpp 中。
ReadRandomBytes() 定义如下
status_t ReadRandomBytes(size_t bytes, std::string& out) {
out.clear();
//打开 linux 的随机数文件
int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
if (fd == -1) {
return -errno;
}
char buf[BUFSIZ];
size_t n;
//读取一个随机数,作为密钥
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
out.append(buf, n);
bytes -= n;
}
close(fd);
if (bytes == 0) {
return OK;
} else {
return -EIO;
}
}
这个方法定义在文件 system/vold/Utils.cpp 中。
在解析 init.rc 文件时,会执行命令 mkdir, 如
mkdir /data/system_de 0770 system system
on post-fs-data
mkdir /data/system_ce 0770 system system
mkdir /data/misc_de 01771 system misc
mkdir /data/misc_ce 01771 system misc
//用户数据路径
mkdir /data/user 0711 system system
// 用户 DE 空间
mkdir /data/user_de 0711 system system
// /data/data 连接到目录 /data/user/0
// /data/user 和 /data/data 都是 CE 空间
symlink /data/data /data/user/0
这个 action 定义在文件 system/core/rootdir/init.rc 中。
命令 mkdir 实质执行的的是函数 do_mkdir()
BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits::max();
static const Map builtin_functions = {
.....
{"mkdir", {1, 4, do_mkdir}},
.....
}
这个方法定义在文件 system/core/init/builtins.cpp 中。
函数 do_mkdir() 的实现如下
static int do_mkdir(const std::vector& args) {
.....
// 创建目录
ret = make_dir(args[1].c_str(), mode);
.....
if (e4crypt_is_native()) {
// 加密目录
if (e4crypt_set_directory_policy(args[1].c_str())) {
wipe_data_via_recovery(std::string() + "set_policy_failed:" + args[1]);
return -1;
}
}
return 0;
}
这个方法定义在文件 system/core/init/builtins.cpp 中。
函数 e4crypt_set_directory_policy() 的实现如下
int e4crypt_set_directory_policy(const char* dir)
{
// 只加密 /data 目录以及子目录
if (!dir || strncmp(dir, "/data/", 6) || strchr(dir + 6, '/')) {
return 0;
}
// 不需要加密的目录在这里设置,但是,它们的子目录是会被加密的
std::vector directories_to_exclude = {
"lost+found",
"system_ce", "system_de",
"misc_ce", "misc_de",
"media",
"data", "user", "user_de",
};
std::string prefix = "/data/";
for (auto d: directories_to_exclude) {
if ((prefix + d) == dir) {
KLOG_INFO(TAG, "Not setting policy on %s\n", dir);
return 0;
}
}
// 密钥引用
std::string ref_filename = std::string("/data") + e4crypt_key_ref;
std::string policy;
if (!android::base::ReadFileToString(ref_filename, &policy)) {
KLOG_ERROR(TAG, "Unable to read system policy to set on %s\n", dir);
return -1;
}
KLOG_INFO(TAG, "Setting policy on %s\n", dir);
// 加密目录
int result = e4crypt_policy_ensure(dir, policy.c_str(), policy.size());
if (result) {
KLOG_ERROR(TAG, "Setting %02x%02x%02x%02x policy on %s failed!\n",
policy[0], policy[1], policy[2], policy[3], dir);
return -1;
}
return 0;
}
这个方法定义在文件 system/extras/ext4_utils/ext4_crypt_init_extensions.cpp 中。
函数 e4crypt_policy_ensure() 定义如下
int e4crypt_policy_ensure(const char *directory, const char *policy, size_t policy_length) {
bool is_empty;
if (!is_dir_empty(directory, &is_empty)) return -1;
if (is_empty) {
// 应用加密政策
if (!e4crypt_policy_set(directory, policy, policy_length)) return -1;
} else {
if (!e4crypt_policy_check(directory, policy, policy_length)) return -1;
}
return 0;
}
这个方法定义在文件 system/extras/ext4_utils/ext4_crypt.cpp 中。
函数 e4crypt_policy_set() 定义如下
static bool e4crypt_policy_set(const char *directory, const char *policy, size_t policy_length) {
int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
......
ext4_encryption_policy eep;
eep.version = 0;
// 设置加密类型 AES 256
eep.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
eep.flags = 0;
memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
// 用命令 EXT4_IOC_SET_ENCRYPTION_POLICY 控制 IO
if (ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &eep)) {
PLOG(ERROR) << "Failed to set encryption policy for " << directory;
close(fd);
return false;
}
close(fd);
char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
policy_to_hex(policy, policy_hex);
LOG(INFO) << "Policy for " << directory << " set to " << policy_hex;
return true;
}
这个方法定义在文件 system/extras/ext4_utils/ext4_crypt.cpp 中。
加密过程就分析到这里。
应用了文件级加密的设备,可以以直接启动的方式启动。此时,设备可以加载并使用没有通过文件级加密的目录,如 /data/user_de/0/。那么,直接启动的 APP 的数据保存在这个目录下。
在上文中,我们知道需要在直接启动就可以立马使用的的 APP,需要在应用的 manifest 的 application 标签声明 android:directBootAware="true" 属性。对于系统的应用,声明 android:defaultToDeviceProtectedStorage="true" 可以把应用的默认存储空间设置为 /data/user_de/。
因此,在用户没有输入凭据解密 CE 空间之前,系统只是加载 DE 下的应用。
在 AMS ready 时,如下(读者不了解这个过程的以看考文章《 Android系统之System Server大纲》)
public void systemReady(final Runnable goingCallback) {
.....
synchronized (this) {
// Only start up encryption-aware persistent apps; once user is
// unlocked we'll come back around and start unaware apps
//启动 persistent app,注意参数 PackageManager.MATCH_DIRECT_BOOT_AWARE
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
}
.....
这个方法定义在文件 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 中。
方法 startPersistentApps() 的实现如下
private void startPersistentApps(int matchFlags) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
synchronized (this) {
try {
//获取所有 direct boot 的 app
final List apps = AppGlobals.getPackageManager()
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName) && validNewProc(app.packageName, UserHandle.getUserId(app.uid))) {//modified by yongfeng.zhang for task 3682193 on 2016-12-28
// 加入启动队列
addAppLocked(app, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
}
}
}
这个方法定义在文件 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 中。
方法 addAppLocked() 定义如下
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
String abiOverride) {
.....
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
// 启动 APP
startProcessLocked(app, "added application", app.processName, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}
return app;
}
这个方法定义在文件 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 中。
在 PMS 启动时,扫描安装 APP 是,会过滤不是直接启动的 APP
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
throws PackageManagerException {
// Apply policy
if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
//直接启动的 APP
if (pkg.applicationInfo.isDirectBootAware()) {
// we're direct boot aware; set for all components
for (PackageParser.Service s : pkg.services) {
s.info.encryptionAware = s.info.directBootAware = true;
}
for (PackageParser.Provider p : pkg.providers) {
p.info.encryptionAware = p.info.directBootAware = true;
}
for (PackageParser.Activity a : pkg.activities) {
a.info.encryptionAware = a.info.directBootAware = true;
}
for (PackageParser.Activity r : pkg.receivers) {
r.info.encryptionAware = r.info.directBootAware = true;
}
}
}
}
这个方法定义在文件 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java 中。
文件级加密,比较全盘加密具有一些优点,可以让没有输入凭证的设备可以使用更多的功能。文件级加密分 CE 空间和 DE 空间,CE 空间需要凭证加密方可使用,DE 空间则是设备启动后即可使用。应用如果需要区分 CE 和 DE 空间,需要创建不同的上下文环境 Context。