锁屏应用未在检测前启动完成导致卡开机动画界面问题分析报告
锁屏应用未在检测前启动完成导致卡开机动画界面问题分析报告
1 关键字
锁屏;卡开机动画;性能;
2 问题描述
环境:OpenHarmony-3.2-Release
问题现象:开机卡开机动画界面,无法正常进入系统。
3 问题原因
3.1 正常机制
系统启动成功,开机动画消失,显示锁屏界面或进入桌面。
3.2 异常机制
系统启动失败,开机动画不消失,无法正常进入系统。
4 解决方案
调整锁屏检测次数,增加锁屏检测的时间,保证可以在锁屏应用启动后正常设置系统参数bootevent.lockscreen.ready为true。
修改文件:base/theme/screenlock_mgr/services/src/screenlock_system_ability.cpp
根据设备性能调整OnSystemReady函数的tryTime变量数值,服务会间隔1S执行轮训检测锁屏应用是否成功注册监听,并执行回调。如果超过检测次数,则会一直处于开机动画界面。
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;
}
}
5 定位过程
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. 查看bootevent.bootanimation.started何时会被设置为true。开机启动服务会收集设备服务开机配置信息中的bootevents配置,并统计数量后赋值变量g_bootEventNum。当系统参数被设置时,过滤发现bootevent字段,调用下方函数进行g_bootEventNum--。当数量变为0时则将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 参数为 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查看系统中的参数。发现缺少bootevent.lockscreen.ready参数。
param get | grep bootevent
5. 尝试手动添加参数,判断是否为此问题。如果可以正常退出开机动画,则确定是由于锁屏参数未设置导致的此问题。
> param set bootevent.lockscreen.ready true
6. 查看锁屏应用源码,应用启动后会注册ScreenLockMar.onSystemEvent事件,事件注册后则会触发systemReady设置bootevent.lockscreen.ready参数为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_的监听,如果有systemReady事件将被触发。而systemEventListener_则是由步骤6中锁屏应用设置,形成闭环。
// 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日志的打印数量,如果为20条则是由于锁屏应用未在检测结束前注册监听导致。
6 知识分享
如果系统不需要锁屏,把锁屏应用移除后,需同时去掉锁屏服务或者删除锁屏服务的开机配置项bootevents。
更多推荐
所有评论(0)