本文鏈接:https://blog.csdn.net/xuhui_7810/article/details/87911245
android9.0上,開啟了默認(rèn)加密后,手機(jī)在開機(jī)的過程中,會發(fā)現(xiàn)開機(jī)動畫在播放一會兒,突然黑屏或閃屏一下,然后重新播放,看起來像是手機(jī)ap端突然重啟了一樣的。針對這個問題,仔細(xì)分析后發(fā)現(xiàn),這個不是手機(jī)ap端重啟了,而是加密導(dǎo)致的framework重啟。具體原因如下.
加密又分全盤加密(Android 4.4 引入)和文件級加密(Android 7.0 引入),本文將論述加密中的全盤加密的基本知識。全盤加密是使用已加密的密鑰對 Android 設(shè)備上的所有用戶數(shù)據(jù)進(jìn)行編碼的過程。設(shè)備經(jīng)過加密后,所有由用戶創(chuàng)建的數(shù)據(jù)在寫入磁盤之前都會自動加密,并且所有讀取操作都會在將數(shù)據(jù)返回給調(diào)用進(jìn)程之前自動解密數(shù)據(jù)。
Android 全盤加密基于在塊設(shè)備層運(yùn)行的內(nèi)核功能 dm-crypt。因此,這種加密方式適用于以塊設(shè)備的形式呈現(xiàn)給內(nèi)核的嵌入式多媒體卡 (eMMC) 和類似閃存設(shè)備。YAFFS 會直接與原始 NAND 閃存芯片交互,無法進(jìn)行全盤加密。
全盤加密采用的是 128 位高級加密標(biāo)準(zhǔn) (AES) 算法(搭配密碼塊鏈接 (CBC) 和 ESSIV:SHA256)。對主密鑰進(jìn)行加密時使用的是 128 位 AES 算法,并會調(diào)用 OpenSSL 庫。對于該密鑰,您必須使用 128 位或更多位(可以選擇 256 位)。
加密操作由 init 和 vold 管理。 init 負(fù)責(zé)調(diào)用 vold,然后 vold 會設(shè)置相關(guān)屬性以觸發(fā) init 中的事件。系統(tǒng)的其他部分也會查看這些屬性以執(zhí)行各項(xiàng)任務(wù),例如報告狀態(tài)、提示輸入密碼,或有嚴(yán)重錯誤發(fā)生時提示恢復(fù)出廠設(shè)置。為了調(diào)用 vold 中的加密功能,系統(tǒng)會使用命令行工具 vdc 的 cryptfs 命令:checkpw、restart、enablecrypto、changepw、cryptocomplete、verifypw、setfield、getfield、mountdefaultencrypted、getpwtype、getpw 以及 clearpw。
要加密、解密或清空 /data,/data 不得處于裝載狀態(tài)。但要顯示任何界面,框架都必須啟動,而框架需要 /data 才能運(yùn)行。為了解決這一沖突,/data 上會裝載一個臨時文件系統(tǒng)。通過該文件系統(tǒng),Android 可以提示輸入密碼、顯示進(jìn)度或根據(jù)需要建議清除數(shù)據(jù)。不過,該文件系統(tǒng)會帶來以下限制:要從臨時文件系統(tǒng)切換到實(shí)際的 /data 文件系統(tǒng),系統(tǒng)必須停止臨時文件系統(tǒng)中打開了文件的所有進(jìn)程,并在實(shí)際的 /data 文件系統(tǒng)中重啟這些進(jìn)程。為此,所有服務(wù)都必須位于以下其中一個組內(nèi):core、main 和 late_start。
core:啟動后一直不會關(guān)閉。
main:關(guān)閉,然后在用戶輸入磁盤密碼后會重啟。
late_start:在 /data 未解密并裝載之前,一直不會啟動。
加密流程和啟動流程
使用 forceencrypt 加密新設(shè)備
這是 Android 5.0 以后設(shè)備首次啟動時的常規(guī)流程。
檢測帶有 forceencrypt 標(biāo)記的未加密文件系統(tǒng),這個標(biāo)記一般在fstab文件里設(shè)置,以高通的為例,放device/qcom/項(xiàng)目名/fstabs-4.9/fstab_non_AB_variant.qti文件里,比如userdata分區(qū)要加密,則用forceencrypt如下配置:
/dev/block/bootdevice/by-name/userdata /data ext4 noatime,nosuid,nodev,barrier=1,noauto_da_alloc,discard wait,forceencrypt=footer,quota,reservedsize=128M
/data 未加密,但需要加密,因?yàn)?forceencrypt 強(qiáng)制要求進(jìn)行此項(xiàng)加密。卸載 /data。
開始加密 /data
vold.decrypt = “trigger_encryption” 會觸發(fā) init.rc,從而使 vold 對 /data 進(jìn)行無密碼加密。(因?yàn)檫@應(yīng)該是新設(shè)備,還沒有設(shè)置密碼。)
裝載 tmpfs
vold 會裝載一個 tmpfs /data(使用 ro.crypto.tmpfs_options 中的 tmpfs 選項(xiàng)),并會將 vold.encrypt_progress 屬性設(shè)為 0。 vold 會準(zhǔn)備 tmpfs /data 以便啟動已加密的系統(tǒng),并會將 vold.decrypt 屬性設(shè)為 trigger_restart_min_framework
啟動框架以顯示進(jìn)度,這里會開啟第一次動畫。
由于設(shè)備上幾乎沒有要加密的數(shù)據(jù),加密過程很快就會完成,因此實(shí)際上通常并不會顯示進(jìn)度條。如需關(guān)于進(jìn)度界面的更多詳細(xì)信息,請參閱加密現(xiàn)有設(shè)備。
/data 加密后,關(guān)閉框架
vold 會將 vold.decrypt 設(shè)為 trigger_default_encryption,這會啟動 defaultcrypto 服務(wù)。(這會啟動以下流程來裝載默認(rèn)的已加密用戶數(shù)據(jù)。)trigger_default_encryption 會檢查加密類型,以了解 /data 加密是否使用了密碼。由于 Android 5.0 設(shè)備是在首次啟動時加密,應(yīng)該沒有設(shè)置任何密碼,因此我們要解密并裝載 /data。
裝載 /data
接下來,init 會使用從 ro.crypto.tmpfs_options(在 init.rc 中設(shè)置)中選取的參數(shù)在 tmpfs RAMDisk 中裝載 /data。
啟動框架
將 vold 設(shè)為 trigger_restart_framework,這會繼續(xù)常規(guī)啟動過程,重新啟動framework,開機(jī)動畫也會重新再調(diào)一次。
這可以從system/core/rootdir/init.rc這個里面看到:
on property:vold.decrypt=trigger_restart_framework
stop surfaceflinger
start surfaceflinger
# A/B update verifier that marks a successful boot.
exec_start update_verifier
class_start main
class_start late_start
這里顯示,當(dāng)vold.decrypt的值為trigger_restart_framework時,會先stop surfaceflinger,然后start surfaceflinger
現(xiàn)在的情形就是這樣,如果要開啟手機(jī)加密,則開機(jī)必定會跑兩次framework,一次是在裝載tmpfs/data時跑,另一次是在加密完成后,重新裝載data后跑,這個流程是不可能被更改的。那么為了避免跑兩次開機(jī)動畫,就必須另想辦法了。
我們可以在frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp這個文件里做如下修改:
char voldDecryptBuf[PROPERTY_VALUE_MAX];
property_get("vold.decrypt", voldDecryptBuf, "");
ALOGI("xuhui bootanim cryptState is: %s ", voldDecryptBuf);
if(strcmp(voldDecryptBuf, "trigger_restart_framework") == 0)
{
if (mStartPropertySetThread->Start() != NO_ERROR) {
ALOGI("Run StartPropertySetThread failed!");
}
}
因?yàn)樵陂_機(jī)加密完成后,vold一定會將"vold.decrypt"它的值設(shè)置為trigger_restart_framework,以便重新啟動framework。這時會停止surfaceflinger進(jìn)程,然衙再重啟surfaceflinger進(jìn)程。而我們的開機(jī)動畫,是在這個進(jìn)程里來啟動的。我們可以從\frameworks\native\services\surfaceflinger\StartPropertySetThread.cpp這個文件里看到:
bool StartPropertySetThread::threadLoop() {
// Set property service.sf.present_timestamp, consumer need check its readiness
property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
// Clear BootAnimation exit flag
property_set("service.bootanim.exit", "0");
// Start BootAnimation if not started
property_set("ctl.start", "bootanim");
// Exit immediately
return false;
}
這里表明, mStartPropertySetThread->Start() 的時候,會property_set("ctl.start", "bootanim"); 開啟動畫。 所以,我們可以通過這個值來判斷,只有當(dāng)"vold.decrypt"的值為trigger_restart_framework的時候,才播放開機(jī)動畫,否則不播放。那么這樣的效果就是,在沒有啟動開機(jī)動畫的時候,手機(jī)界面會一直停留在開機(jī)的第一張logo那里。
————————————————
版權(quán)聲明:本文為CSDN博主「xuhui_7810」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/xuhui_7810/article/details/87911245