OpenHarmony系統(tǒng)解決方案 - 鎖屏引起的卡開(kāi)機(jī)動(dòng)畫(huà)
想了解更多關(guān)于開(kāi)源的內(nèi)容,請(qǐng)?jiān)L問(wèn):
問(wèn)題描述
問(wèn)題環(huán)境
系統(tǒng)版本:OpenHarmony-3.2-Release
問(wèn)題現(xiàn)象
設(shè)備接通電源,開(kāi)機(jī)動(dòng)畫(huà)正常播放結(jié)束,長(zhǎng)時(shí)間靜止在開(kāi)機(jī)動(dòng)畫(huà)結(jié)束界面,無(wú)法正常進(jìn)入系統(tǒng)。
OpenHarmony系統(tǒng)解決方案 - 鎖屏引起的卡開(kāi)機(jī)動(dòng)畫(huà)-開(kāi)源基礎(chǔ)軟件社區(qū)
問(wèn)題原因
- 設(shè)備性能導(dǎo)致的鎖屏應(yīng)用未在鎖屏服務(wù)檢測(cè)監(jiān)聽(tīng)事件的時(shí)間段內(nèi)啟動(dòng)完成,導(dǎo)致無(wú)法觸發(fā)關(guān)閉開(kāi)機(jī)動(dòng)畫(huà)。
- 系統(tǒng)不需要鎖屏應(yīng)用,把鎖屏應(yīng)用刪除后,未移除鎖屏服務(wù)(theme_screenlock_mgr)導(dǎo)致無(wú)法觸發(fā)關(guān)閉開(kāi)機(jī)動(dòng)畫(huà)。
解決方案
針對(duì)設(shè)備性能問(wèn)題的解決方案
調(diào)整鎖屏檢測(cè)次數(shù),增加鎖屏檢測(cè)的時(shí)間,保證可以在鎖屏應(yīng)用啟動(dòng)后正常設(shè)置系統(tǒng)參數(shù)bootevent.lockscreen.ready為true。
根據(jù)設(shè)備性能調(diào)整OnSystemReady函數(shù)的tryTime變量數(shù)值,服務(wù)會(huì)間隔1S執(zhí)行檢測(cè)鎖屏應(yīng)用是否成功注冊(cè)監(jiān)聽(tīng),并執(zhí)行回調(diào)。如果超過(guò)檢測(cè)次數(shù),則會(huì)一直處于開(kāi)機(jī)動(dòng)畫(huà)界面。
// 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è)備性能調(diào)整此處嘗試次數(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;
}
}
針對(duì)刪除鎖屏應(yīng)用的解決方案
移除鎖屏服務(wù)(screenlock_mgr)組件,以RK3568編譯配置為例。需在編譯配置文件productdefine/common/inherit/rich.json中刪除screenlock_mgr組件的編譯配置。以下為刪除后的theme編譯配置。
{
"version": "3.0",
"subsystems": [
···
{
"subsystem": "theme",
"components": [
{
"component": "wallpaper_mgr",
"features": []
}
]
},
···
]
}
如果需要保留鎖屏服務(wù),則需刪除鎖屏服務(wù)開(kāi)機(jī)檢測(cè)項(xiàng)bootevents,配置項(xiàng)位于base/theme/screenlock_mgr/etc/init/screenlockservice.cfg。
定位過(guò)程
1. 開(kāi)機(jī)動(dòng)畫(huà)退出邏輯,當(dāng)開(kāi)機(jī)動(dòng)畫(huà)獲取到bootevent.boot.completed屬性為true時(shí),退出開(kāi)機(jī)動(dòng)畫(huà)。
// 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. 開(kāi)機(jī)啟動(dòng)服務(wù)組件會(huì)收集設(shè)備服務(wù)開(kāi)機(jī)配置信息中的bootevents配置,并統(tǒng)計(jì)數(shù)量后賦值變量g_bootEventNum。當(dāng)系統(tǒng)參數(shù)被設(shè)置時(shí),過(guò)濾bootevent字段,調(diào)用下方函數(shù)進(jìn)行g(shù)_bootEventNum--。當(dāng)數(shù)量變?yōu)?時(shí)則將bootevent.bootanimation.started設(shè)置為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"); // 設(shè)置 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. 查看鎖屏服務(wù)開(kāi)機(jī)配置,存在bootevents配置項(xiàng)。
// base/theme/screenlock_mgr/etc/init/screenlockservice.cfg
{
···
"services" : [{
···
"bootevents" : ["bootevent.lockscreen.ready"]
}
]
}
4. 通過(guò)shell查看系統(tǒng)中的參數(shù)。發(fā)現(xiàn)bootevent.lockscreen.ready參數(shù)未被設(shè)置。
param get | grep bootevent
OpenHarmony系統(tǒng)解決方案 - 鎖屏引起的卡開(kāi)機(jī)動(dòng)畫(huà)-開(kāi)源基礎(chǔ)軟件社區(qū)
5. 嘗試手動(dòng)添加參數(shù),判斷是否為此問(wèn)題。如果可以正常退出開(kāi)機(jī)動(dòng)畫(huà),則確定是由于鎖屏參數(shù)未設(shè)置導(dǎo)致的此問(wèn)題。
param set bootevent.lockscreen.ready true
6. 查看鎖屏應(yīng)用源碼,應(yīng)用啟動(dòng)后會(huì)注冊(cè)ScreenLockMar.onSystemEvent事件。事件注冊(cè)后,當(dāng)觸發(fā)systemReady設(shè)置時(shí),會(huì)將bootevent.lockscreen.ready參數(shù)設(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. 在鎖屏服務(wù)中遍歷判斷是否有systemEventListener_的監(jiān)聽(tīng),如果有systemReady事件將被觸發(fā)。而systemEventListener_則是由步驟6中鎖屏應(yīng)用設(shè)置,形成閉環(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. 落盤(pán)開(kāi)機(jī)Log,查看日志中ScreenLockSystemAbility OnSystemReady type not found., flag_ = %{public}d日志的打印數(shù)量,如果為20條則確定是由于鎖屏應(yīng)用未在檢測(cè)結(jié)束前注冊(cè)監(jiān)聽(tīng)導(dǎo)致。