OpenHarmony系統(tǒng)解決方案 - 鎖屏引起的卡開機動畫
問題描述
問題環(huán)境
系統(tǒng)版本:OpenHarmony-3.2-Release
問題現(xiàn)象
設備接通電源,開機動畫正常播放結束,長時間靜止在開機動畫結束界面,無法正常進入系統(tǒng)。
OpenHarmony系統(tǒng)解決方案 - 鎖屏引起的卡開機動畫-開源基礎軟件社區(qū)
問題原因
- 設備性能導致的鎖屏應用未在鎖屏服務檢測監(jiān)聽事件的時間段內啟動完成,導致無法觸發(fā)關閉開機動畫。
- 系統(tǒng)不需要鎖屏應用,把鎖屏應用刪除后,未移除鎖屏服務(theme_screenlock_mgr)導致無法觸發(fā)關閉開機動畫。
解決方案
針對設備性能問題的解決方案
調整鎖屏檢測次數(shù),增加鎖屏檢測的時間,保證可以在鎖屏應用啟動后正常設置系統(tǒng)參數(shù)bootevent.lockscreen.ready為true。
根據(jù)設備性能調整OnSystemReady函數(shù)的tryTime變量數(shù)值,服務會間隔1S執(zhí)行檢測鎖屏應用是否成功注冊監(jiān)聽,并執(zhí)行回調。如果超過檢測次數(shù),則會一直處于開機動畫界面。
// base/theme/screenlock_mgr/services/src/screenlock_system_ability.cpp
void ScreenLockSystemAbility::OnSystemReady()
{
SCLOCK_HILOGI("ScreenLockSystemAbility OnSystemReady started.");
bool isExitFlag = false;
int tryTime = 20; // 根據(jù)設備性能調整此處嘗試次數(shù)
int minTryTime = 0;
while (!isExitFlag && (tryTime > minTryTime)) {
if (systemEventListener_ != nullptr) {
SCLOCK_HILOGI("ScreenLockSystemAbility OnSystemReady started1.");
std::lock_guard<std::mutex> lck(listenerMutex_);
SystemEvent systemEvent(SYSTEM_READY);
systemEventListener_->OnCallBack(systemEvent);
isExitFlag = true;
} else {
SCLOCK_HILOGE("ScreenLockSystemAbility OnSystemReady type not found., flag_ = %{public}d", flag_);
sleep(1);
}
--tryTime;
}
}
針對刪除鎖屏應用的解決方案
移除鎖屏服務(screenlock_mgr)組件,以RK3568編譯配置為例。需在編譯配置文件productdefine/common/inherit/rich.json中刪除screenlock_mgr組件的編譯配置。以下為刪除后的theme編譯配置。
{
"version": "3.0",
"subsystems": [
···
{
"subsystem": "theme",
"components": [
{
"component": "wallpaper_mgr",
"features": []
}
]
},
···
]
}
如果需要保留鎖屏服務,則需刪除鎖屏服務開機檢測項bootevents,配置項位于base/theme/screenlock_mgr/etc/init/screenlockservice.cfg。
定位過程
1. 開機動畫退出邏輯,當開機動畫獲取到bootevent.boot.completed屬性為true時,退出開機動畫。
// foundation/graphic/graphic_2d/frameworks/bootanimation/src/boot_animation.cpp
void BootAnimation::CheckExitAnimation()
{
LOGI("CheckExitAnimation enter");
if (!setBootEvent_) {
LOGI("CheckExitAnimation set bootevent parameter");
system::SetParameter("bootevent.bootanimation.started", "true");
setBootEvent_ = true;
}
std::string windowInit = system::GetParameter("bootevent.boot.completed", "false");
if (windowInit == "true") {
PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
LOGI("CheckExitAnimation read windowInit is true");
return;
}
}
2. 開機啟動服務組件會收集設備服務開機配置信息中的bootevents配置,并統(tǒng)計數(shù)量后賦值變量g_bootEventNum。當系統(tǒng)參數(shù)被設置時,過濾bootevent字段,調用下方函數(shù)進行g_bootEventNum--。當數(shù)量變?yōu)?時則將bootevent.bootanimation.started設置為true。
// base/startup/init/services/modules/bootevent.c
#define BOOT_EVENT_BOOT_COMPLETED "bootevent.boot.completed"
static void BootEventParaFireByName(const char *paramName){
ListNode *found = NULL;
char *bootEventValue = strrchr(paramName, '.');
if (bootEventValue == NULL) {
return;
}
bootEventValue[0] = '\0';
found = OH_ListFind(&bootEventList, (void *)paramName, BootEventParaListCompareProc);
if (found == NULL) {
return;
}
if (((BOOT_EVENT_PARAM_ITEM *)found)->timestamp[BOOTEVENT_READY].tv_sec != 0) {
return;
}
INIT_CHECK_ONLY_RETURN(clock_gettime(CLOCK_MONOTONIC,
&(((BOOT_EVENT_PARAM_ITEM *)found)->timestamp[BOOTEVENT_READY])) == 0);
g_bootEventNum--;
// Check if all boot event params are fired
if (g_bootEventNum > 0) {
return;
}
// All parameters are fired, set boot completed now ...
INIT_LOGI("All boot events are fired, boot complete now ...");
SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true"); // 設置 bootevent.boot.completed 參數(shù)為 true
g_bootEventEnable = BOOT_EVENT_FINISH;
SaveServiceBootEvent();
const char *clearBootEventArgv[] = {"bootevent"};
// clear servie extra data
PluginExecCmd("clear", ARRAY_LENGTH(clearBootEventArgv), clearBootEventArgv);
return;
}
3. 查看鎖屏服務開機配置,存在bootevents配置項。
// base/theme/screenlock_mgr/etc/init/screenlockservice.cfg
{
···
"services" : [{
···
"bootevents" : ["bootevent.lockscreen.ready"]
}
]
}
4. 通過shell查看系統(tǒng)中的參數(shù)。發(fā)現(xiàn)bootevent.lockscreen.ready參數(shù)未被設置。
param get | grep bootevent
OpenHarmony系統(tǒng)解決方案 - 鎖屏引起的卡開機動畫-開源基礎軟件社區(qū)
5. 嘗試手動添加參數(shù),判斷是否為此問題。如果可以正常退出開機動畫,則確定是由于鎖屏參數(shù)未設置導致的此問題。
param set bootevent.lockscreen.ready true
6. 查看鎖屏應用源碼,應用啟動后會注冊ScreenLockMar.onSystemEvent事件。事件注冊后,當觸發(fā)systemReady設置時,會將bootevent.lockscreen.ready參數(shù)設置為true。
// applications/standard/screenlock/features/screenlock/src/main/ets/com/ohos/model/screenLockModel.ts
export default class ScreenLockModel {
@SysFaultLogger({FAULT_ID: FaultID.SCREEN_LOCK_MANAGER, MSG: "call func on failed"})
eventListener(callback: Callback<String>) {
let isSuccess = ScreenLockMar.onSystemEvent((err, event) => {
Log.showInfo(TAG, `eventListener:callback:${event.eventType}`)
callback(event.eventType);
if (err) {
Log.showError(TAG, `on callback error -> ${JSON.stringify(err)}`);
}
});
if (!isSuccess) {
callback('serviceRestart');
}
}
···
}
// applications/standard/screenlock/features/screenlock/src/main/ets/com/ohos/model/screenLockService.ts
const EVENT_SYSTEM_READY: string = 'systemReady'
···
export class ScreenLockService {
monitorEvents() {
···
this.screenLockModel.eventListener((typeName: String) => {
switch (typeName) {
// System ready on device boot
case EVENT_SYSTEM_READY:
Log.showInfo(TAG, `EVENT_SYSTEM_READY event`);
this.lockScreen();
break;
})
···
}
lockScreen() {
···
this.screenLockModel.showScreenLockWindow(() => {
···
if (this.currentLockStatus == ScreenLockStatus.Locking) {
Log.showInfo(TAG, `had locked, no need to publish lock_screen`);
} else {
this.notifyLockScreenResult(LockResult.Success)
this.publishByUser("common.event.LOCK_SCREEN", this.accountModel.getCurrentUserId());
setTimeout(() => {
systemParameter.set('bootevent.lockscreen.ready','true')
}, 1000);
this.currentLockStatus = ScreenLockStatus.Locking;
}
});
}
}
7. 在鎖屏服務中遍歷判斷是否有systemEventListener_的監(jiān)聽,如果有systemReady事件將被觸發(fā)。而systemEventListener_則是由步驟6中鎖屏應用設置,形成閉環(huán)。
// base/theme/screenlock_mgr/services/src/screenlock_system_ability.cpp
void ScreenLockSystemAbility::OnSystemReady()
{
SCLOCK_HILOGI("ScreenLockSystemAbility OnSystemReady started.");
bool isExitFlag = false;
int tryTime = 20;
int minTryTime = 0;
while (!isExitFlag && (tryTime > minTryTime)) {
if (systemEventListener_ != nullptr) {
SCLOCK_HILOGI("ScreenLockSystemAbility OnSystemReady started1.");
std::lock_guard<std::mutex> lck(listenerMutex_);
SystemEvent systemEvent(SYSTEM_READY);
systemEventListener_->OnCallBack(systemEvent);
isExitFlag = true;
} else {
SCLOCK_HILOGE("ScreenLockSystemAbility OnSystemReady type not found., flag_ = %{public}d", flag_);
sleep(1);
}
--tryTime;
}
}
8. 落盤開機Log,查看日志中ScreenLockSystemAbility OnSystemReady type not found., flag_ = %{public}d日志的打印數(shù)量,如果為20條則確定是由于鎖屏應用未在檢測結束前注冊監(jiān)聽導致。