由于android的文件系统加密依赖的内核模块dm-crypt只能在块设备层起作用,因此这种加密方式无法应用在YAFFS文件系统中。这是因为YAFFS文件系统直接在NAND Flash芯片的裸设备上进行各种操作。但是EMMC或类似的存储芯片是作为块设备挂载在内核中的,因此是可以使用加密功能的。dm-crypt的代码位于内核的driver/md/dm-crypt.c中。
为了实现挂载加密文件系统的工作,系统将所有服务分配到了三个不同组中:核心(core),主要(main),后启动(late_start)。对这三个服务组的控制,实现了对/daa分区进行加密的主要流程:
1)关闭主要和后启动服务组,卸载/data分区。
2)将/data分区挂载到临时文件系统(tmpfs),然后启动主要服务和临时框架。
3)对文件系统进行加密操作
4)停止主要服务和临时框架,卸载/data,然后挂载解密后的/data分区
5)停止主要服务和后启动服务。
在块存储设备上启用加密文件系统
1) 为确保加密过程可以顺利完成,系统首先会检查电池的电量是否充足以及是否连接了外部电源。这是因为如果在加密过程中系统因为电量不足而关机,文件系统的文件会因为只有部分进行了加密而导致数据不可用,只有回复出场设置才能使设备回复正常,所有的数据都会丢失。在确保电力充足后,界面向vold发送“cryptfs enablecrypto inplace”命令启动加密流程,加密使用的密码为用户锁屏密码
2) vold进行错误检查,如果无法进行加密的会返回状态代码“-1”,并且在日志中输入错误原因。如果可以进行加密操作,程序会将vold.decrypt属性设置为“trigger_shutdown_framework”。这会导致init.rc停止所有的后启动服务和主要服务。然后vold卸载/mnt/sdcard和/data。
3) 如果使用inplace模式加密,vold会将/data挂载到临时文件系统上(使用ro.crypto.tmpfs_options中的选项),并且将vold.encrypt_progress属性设置为“0”。之后vold会对新的/data分区进行准备,然后将vold.decrypt属性设置为“trigger_restart_min_framework”。这会是init.rc启动所有主要服务。这时框架会看到vold.encypt_process的值为0,并且显示一个进度条来提示加密过程。界面每5秒中查询一下这个属性,并且会更新进度条。
4) 之后vold会将真正的块设备通过加密映射到一个虚拟的加密块设备上。这个新的块设备对所有写入的数据进行加密,对所有读取的数据进行解密。然后vold将相关的加密信息写入分区尾部。
5) 如果使用wipe方式进行加密,vold对加密块设备使用make_ext4fs命令来格式化文件系统,并且保证新的文件系统不会包含分区的最后16K字节。如果以inplace方式加密,vold从原始的设备中读出每个扇区的数据,然后写入加密设备。
6) 当加密完成时,vold清除ENCRYPTION_IN_PROGRESS标识,然后重新启动系统,如果重启失败,程序将vold.encrypt_progress设置为“error_not_failed”。这时界面会弹出提示,要求用户手动重新启动系统。
7) 如果vold在加密过程中出现了错误且还没有数据被破坏(例如加密还没有开始),vold会将vold.encrypt_progress属性设置为“error_not_encrypted”,并且以界面显示提示用户加密流程没有开始并给出用户重启系统的选项。如果错误发生在框架停止且进度条出现之前,vold会立即重新启动系统。如果重启也失败了,程序会将vold.encrypt_progress设置为“error_shutting_down”并且返回-1。如果在进行加密操作时遇到了错误,vold.encrypt_progress设置为“error_partially_encrypted”并返回-1。这时界面会提示用户加密失败并向用户提供恢复出厂设置的选项按钮。