/* * Copyright (c) Hisilicon Technologies Co., Ltd.. 2016-2019. All rights reserved. * Description: bootvideo manager */ #include "BootvideoManager.h" #include #include #include #include #include "BootvideoInput.h" #include "BootvideoApi.h" #include "BootvideoConfiger.h" #include "BootvideoDftevent.h" #undef LOG_TAG #define LOG_TAG "BootVideo" namespace android { using std::string; using android::sp; using std::make_unique; string g_pathOne = ""; string g_pathApi = ""; sp g_bootVideoUi = nullptr; sp g_bootVideoPlayer = nullptr; namespace { const short PLAYER_VOLUME_MAX = 30; // player init volume max const short PLAYER_VOLUME_MIN = 10; // player init volume min const short CONVERT_SEC_TO_MS = 1000; // unit convert: sec to ms const short CONVERT_MS_TO_US = 1000; // unit convert: ms to us const short DELAY_100_MS = 100; // delay is 100ms const short PLAY_TIMER_INTERVAL = 10; // player timer, Once every 10 ms count const short WAIT_UI_READY_COUNT = 10; // wait UI ready max count(10ms per count) int g_totalPlayCounter = 0; // total play count, reference PLAY_TIMER_INTERVAL int g_countTime = -1; // count down unit(s) bool g_blFirst = true; } // signal handler of palyer timer, PLAY_TIMER_INTERVAL ms call // 50ms once draw count time of ui static void SignalHandler(int param) { (void)param; g_totalPlayCounter++; // first draw count time if (g_blFirst && (g_countTime >= 0)) { if (g_bootVideoUi != nullptr) { g_bootVideoUi->SetCountdownTime(g_countTime--); } g_blFirst = false; } // calculate the count time int counterSec = CONVERT_SEC_TO_MS / PLAY_TIMER_INTERVAL; // every 1s count if ((g_totalPlayCounter % counterSec == 0) && (g_countTime >= 0)) { if (g_bootVideoUi != nullptr) { g_bootVideoUi->SetCountdownTime(g_countTime--); } } } // limitMs unit is ms bool CheckIfTimeOut(int limitMs) { // check player count int maxCounter = limitMs / PLAY_TIMER_INTERVAL; if (g_totalPlayCounter >= maxCounter) { return true; } return false; } int GetPlayTimeInfo() { if (g_bootVideoPlayer == nullptr) { ALOGE("GetPlayTimeInfo: bootVideo Player is NULL"); return -1; } int playedMs, totalMs; if (g_bootVideoPlayer->GetPlayTimeInfo(playedMs, totalMs)) { return totalMs - playedMs; } else { ALOGE("GetPlayTimeInfo: bootVideo Player get play time info failure"); return -1; } } bool SetDrawTime(int limitMs) { int playedMs, totalMs; if (g_bootVideoPlayer == nullptr) { ALOGE("SetDrawTime: bootVideo Player is NULL"); return false; } if (g_bootVideoPlayer->GetPlayTimeInfo(playedMs, totalMs)) { int remainMs = totalMs - playedMs; // player countdown int leftMs = limitMs - playedMs; // actually countdown if (remainMs < leftMs) { g_countTime = remainMs / CONVERT_SEC_TO_MS; } else { g_countTime = leftMs / CONVERT_SEC_TO_MS; } ALOGI("SetDrawTime: Total count time is %d.", g_countTime); return true; } else { ALOGE("SetDrawTime: bootVideo Player get play time info failure"); return false; } } void ManagerSetTimer() { // Calculation of seconds const long sec = 0; // Calculation of microseconds const long us = (PLAY_TIMER_INTERVAL % CONVERT_SEC_TO_MS) * CONVERT_SEC_TO_MS; struct itimerval itv; itv.it_value.tv_sec = sec; itv.it_value.tv_usec = us; itv.it_interval.tv_sec = sec; itv.it_interval.tv_usec = us; // warning: don't change the timer type setitimer(ITIMER_REAL, &itv, nullptr); return; } // SUPPORT_LIB_BOOTVIDEO is true void BootvideoSetPath(string path) { // if you are using the API, you must call this function to set path // else you must not call this function and the path of config.xml g_pathApi = path; } int BootvideoInitVolume() { int initVolume = 0; char propVloume[PROPERTY_VALUE_MAX] = {0}; // get init volume if (property_get("persist.service.bootvideo.volume", propVloume, nullptr)) { initVolume = atoi(propVloume); ALOGD("volume property is %s, init bootvideo volume is %d", propVloume, initVolume); } else { ALOGE("volume property get failure"); } // cancel the mute state property_set("persist.service.bootvideo.mute", "0"); // check init volume if (initVolume > PLAYER_VOLUME_MAX) { initVolume = PLAYER_VOLUME_MAX; } if (initVolume < PLAYER_VOLUME_MIN) { initVolume = PLAYER_VOLUME_MIN; } return initVolume; } bool IsBootComplete() { char proVal[PROPERTY_VALUE_MAX] = {0}; // property is boot complete , default is 0 if (!property_get(SYS_BOOTCOMPLETE.c_str(), proVal, nullptr)) { return false; } if (proVal[0] == '1') { return true; } else { return false; } } bool IsSTRPlay() { char strprop[PROPERTY_VALUE_MAX] = {0}; char bootop[PROPERTY_VALUE_MAX] = {0}; if (!property_get("sys.str.enable", strprop, nullptr)) { return false; } if (!property_get("persist.service.strbootop.type", bootop, nullptr)) { ALOGE("failed to get prop strbootop"); return false; } if ((!strncmp(strprop, "true", strlen("true"))) && (!strncmp(bootop, "bootvideo", strlen("bootvideo")))) { ALOGD("str bootvideo enable"); return true; } return false; } // start bootanim when bootvideo play failed bool BootvideoFailProc() { if (!IsSTRPlay()) { ALOGE("property_set bootanim"); property_set("service.bootop.type", "bootanim"); // Clear BootAnimation exit flag property_set("service.bootanim.exit", "0"); // Start BootAnimation if not started property_set("ctl.start", "bootanim"); } return true; } // get bootvideo path string BootvideoGetPath() { string tempPathOne = ""; auto configer = make_unique(); if (IsSTRPlay()) { tempPathOne = configer->GetFeature(BootvideoConfiger::PROPERTY_PATH_STR_FIRST); } else { tempPathOne = configer->GetFeature(BootvideoConfiger::PROPERTY_PATH_FIRST); } // if api set path, the video path is g_pathApi if (!g_pathApi.empty()) { tempPathOne = g_pathApi; } return tempPathOne; } void InitAudioVolume() { const int speaker = 0; const int headPhone = 1; int volume = GetVolume(speaker); SetVolume(speaker, volume); volume = GetVolume(headPhone); SetVolume(headPhone, volume); } // start paly bootvideo bool StartPlayBootvideo() { // creat palyer g_bootVideoUi = new BootvideoUI(); g_bootVideoPlayer = new BootvideoPlayer(); // init player bool isSuc = g_bootVideoPlayer->InitPlay(); if (!isSuc) { ALOGE("palyer init failure"); BootvideoFailProc(); StopPlayBootVideo(); return false; } // set player path isSuc = g_bootVideoPlayer->SetDataSource(BootvideoGetPath()); if (!isSuc) { ALOGE("palyer set path failure"); BootvideoFailProc(); StopPlayBootVideo(); return false; } // init system volume int initVolume = BootvideoInitVolume(); auto configer = make_unique(); // start input and ui if (configer->IsFeature(BootvideoConfiger::PROPERTY_EN_INPUT)) { ALOGD("support input"); StartInput(initVolume, g_bootVideoUi, g_bootVideoPlayer); } InitAudioManager(); // if not strplay, set port volume if (!IsSTRPlay()) { InitAudioVolume(); } // set player sideband isSuc = g_bootVideoPlayer->SetSideBand(g_bootVideoUi->GetSideBand()); if (!isSuc) { ALOGE("palyer set side band failure"); } int waitUiCount = WAIT_UI_READY_COUNT; while (!g_bootVideoUi->CheckReady() && waitUiCount > 0) { waitUiCount--; usleep(PLAY_TIMER_INTERVAL * CONVERT_MS_TO_US); } ALOGD("Bootvideo UI is ready."); // start player if (!g_bootVideoPlayer->StartPlay(initVolume)) { ALOGE("palyer start play failure"); BootvideoFailProc(); StopPlayBootVideo(); return false; } // loop player CheckIfExitPlay(); return true; } // stop play bootvideo bool StopPlayBootVideo() { auto configer = make_unique(); // stop input if (configer->IsFeature(BootvideoConfiger::PROPERTY_EN_INPUT)) { ALOGI("StopPlayBootVideo: start to stop input thread."); StopInput(); } // stop ui ALOGI("StopPlayBootVideo: start to stop UI thread."); if (g_bootVideoUi) { g_bootVideoUi->SetUIFinish(); g_bootVideoUi = nullptr; } // stop palyer ALOGI("StopPlayBootVideo: start to stop player thread."); if (g_bootVideoPlayer) { g_bootVideoPlayer->StopPlay(); g_bootVideoPlayer = nullptr; } ALOGI("StopPlayBootVideo: all thread stop."); return true; } // loop check bootvideo void CheckIfExitPlay() { auto configer = make_unique(); // playing duration time const short tmpLimit = configer->GetVideoLimit(); const short limit = tmpLimit > 120 ? 120 : tmpLimit; // 120 is in 2minute in second const int limitTimeMs = limit * CONVERT_SEC_TO_MS; bool isPlayErr = false; bool isPlayFail = false; bool isPlayStop = false; // static frame play: if the system has not complete and player is end, on the last frame bool isSyscmp = false; string bootvideoPath = BootvideoGetPath(); // set and init remaining play time SetDrawTime(limitTimeMs); // set signal of draw the remaining play time signal(SIGALRM, SignalHandler); // set timer interval, unit is ms ManagerSetTimer(); // start loop while (true) { // check player if (g_bootVideoPlayer == nullptr) { ALOGE("paly loop: bootVideoPlayer is NULL"); isPlayErr = true; break; } // check paly failed isPlayFail = g_bootVideoPlayer->IsPlayFail(); if (isPlayFail) { BootvideoDfteventReport(E_955050801, "CheckIfExitPlay", "StartPlayBootvideo", bootvideoPath); ALOGE("paly loop: bootVideoPlayer failure"); break; } // check system boot complete isSyscmp = IsBootComplete(); // check play end bool isPlayEnd = g_bootVideoPlayer->IsPlayEnd(); if (isPlayEnd) { ALOGE("paly loop: bootvideo player end"); } // check play timeout bool isTimeout = CheckIfTimeOut(limitTimeMs); if (isTimeout) { ALOGE("paly loop: bootvideo player time out"); } // when timeout or end, stop play and stop if (isPlayEnd || isTimeout) { isPlayStop = true; break; } usleep(DELAY_100_MS * CONVERT_MS_TO_US); // wait delay 100ms } // need start bootanim if (isPlayFail || isPlayErr) { BootvideoFailProc(); StopPlayBootVideo(); } // stop bootvideo if (isPlayStop) { StopPlayBootVideo(); } } } // namespace android