1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "boot_animation.h"
16 #include "event_handler.h"
17 #include "rs_trace.h"
18 #include "transaction/rs_render_service_client.h"
19 #include "transaction/rs_interfaces.h"
20
21 using namespace OHOS;
22 static const std::string BOOT_PIC_ZIP = "/system/etc/init/bootpic.zip";
23 static const std::string BOOT_SOUND_URI = "file://system/etc/init/bootsound.wav";
24
25
OnDraw(SkCanvas * canvas,int32_t curNo)26 void BootAnimation::OnDraw(SkCanvas* canvas, int32_t curNo)
27 {
28 if (canvas == nullptr) {
29 LOGE("OnDraw canvas is nullptr");
30 return;
31 }
32 if (curNo > (imgVecSize_ - 1) || curNo < 0) {
33 return;
34 }
35 std::shared_ptr<ImageStruct> imgstruct = imageVector_[curNo];
36 sk_sp<SkImage> image = imgstruct->imageData;
37
38 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawRect");
39 SkPaint backPaint;
40 backPaint.setColor(SK_ColorBLACK);
41 canvas->drawRect(SkRect::MakeXYWH(0.0, 0.0, windowWidth_, windowHeight_), backPaint);
42 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
43 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawImageRect");
44 SkPaint paint;
45 SkRect rect;
46 rect.setXYWH(pointX_, pointY_, realWidth_, realHeight_);
47 canvas->drawImageRect(image.get(), rect, &paint);
48 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
49 }
50
Draw()51 void BootAnimation::Draw()
52 {
53 if (picCurNo_ < (imgVecSize_ - 1)) {
54 picCurNo_ = picCurNo_ + 1;
55 } else {
56 CheckExitAnimation();
57 return;
58 }
59 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw RequestFrame");
60 auto frame = rsSurface_->RequestFrame(windowWidth_, windowHeight_);
61 if (frame == nullptr) {
62 LOGE("Draw frame is nullptr");
63 return;
64 }
65 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
66 framePtr_ = std::move(frame);
67 auto canvas = framePtr_->GetCanvas();
68 OnDraw(canvas, picCurNo_);
69 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
70 rsSurface_->FlushFrame(framePtr_);
71 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
72 }
73
CheckFrameRateValid(int32_t ratevalue)74 bool BootAnimation::CheckFrameRateValid(int32_t ratevalue)
75 {
76 std::vector<int> freqs = {60, 30};
77 int nCount = std::count(freqs.begin(), freqs.end(), ratevalue);
78 if (nCount <= 0) {
79 return false;
80 }
81 return true;
82 }
83
Init(int32_t width,int32_t height)84 void BootAnimation::Init(int32_t width, int32_t height)
85 {
86 windowWidth_ = width;
87 windowHeight_ = height;
88 LOGI("Init enter, width: %{public}d, height: %{public}d", width, height);
89
90 auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
91 while (receiver_ == nullptr) {
92 receiver_ = rsClient.CreateVSyncReceiver("BootAnimation", mainHandler_);
93 }
94 VsyncError ret = receiver_->Init();
95 if (ret) {
96 LOGE("vsync receiver init failed: %{public}d", ret);
97 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
98 return;
99 }
100
101 InitBootWindow();
102 InitRsSurface();
103 InitPicCoordinates();
104 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::preload");
105 BootAniConfig jsonConfig;
106 ReadZipFile(BOOT_PIC_ZIP, imageVector_, jsonConfig);
107 imgVecSize_ = static_cast<int32_t>(imageVector_.size());
108 if (imgVecSize_ <= 0) {
109 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
110 LOGE("zip pic num is 0.");
111 return;
112 }
113 SortZipFile(imageVector_);
114 if (CheckFrameRateValid(jsonConfig.frameRate)) {
115 freq_ = jsonConfig.frameRate;
116 } else {
117 LOGI("Only Support 30, 60 frame rate: %{public}d", jsonConfig.frameRate);
118 }
119 LOGI("end to Readzip pics freq: %{public}d totalPicNum: %{public}d", freq_, imgVecSize_);
120 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
121
122 OHOS::Rosen::VSyncReceiver::FrameCallback fcb = {
123 .userData_ = this,
124 .callback_ = std::bind(&BootAnimation::OnVsync, this),
125 };
126 int32_t changefreq = static_cast<int32_t>((1000.0 / freq_) / 16);
127 ret = receiver_->SetVSyncRate(fcb, changefreq);
128 if (ret) {
129 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
130 LOGE("SetVSyncRate failed: %{public}d %{public}d %{public}d", ret, freq_, changefreq);
131 return;
132 } else {
133 LOGI("SetVSyncRate success: %{public}d %{public}d", freq_, changefreq);
134 }
135 }
136
Run(std::vector<sptr<OHOS::Rosen::Display>> & displays)137 void BootAnimation::Run(std::vector<sptr<OHOS::Rosen::Display>>& displays)
138 {
139 runner_ = AppExecFwk::EventRunner::Create(false);
140 mainHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
141 mainHandler_->PostTask(std::bind(&BootAnimation::Init, this, displays[0]->GetWidth(), displays[0]->GetHeight()));
142 mainHandler_->PostTask(std::bind(&BootAnimation::PlaySound, this));
143 runner_->Run();
144 }
145
InitBootWindow()146 void BootAnimation::InitBootWindow()
147 {
148 sptr<OHOS::Rosen::WindowOption> option = new OHOS::Rosen::WindowOption();
149 option->SetWindowType(OHOS::Rosen::WindowType::WINDOW_TYPE_BOOT_ANIMATION);
150 option->RemoveWindowFlag(OHOS::Rosen::WindowFlag::WINDOW_FLAG_NEED_AVOID);
151 option->SetWindowRect({0, 0, windowWidth_, windowHeight_} );
152 option->SetTouchable(false);
153 int displayId = 0;
154 sptr<OHOS::Rosen::IWindowLifeCycle> listener = nullptr;
155 scene_ = new OHOS::Rosen::WindowScene();
156 scene_->Init(displayId, nullptr, listener, option);
157 window_ = scene_->GetMainWindow();
158 while (window_ == nullptr) {
159 LOGI("window is nullptr, continue to init window");
160 scene_->Init(displayId, nullptr, listener, option);
161 window_ = scene_->GetMainWindow();
162 sleep(1);
163 }
164 scene_->GoForeground();
165 }
166
InitRsSurface()167 void BootAnimation::InitRsSurface()
168 {
169 rsSurface_ = OHOS::Rosen::RSSurfaceExtractor::ExtractRSSurface(window_->GetSurfaceNode());
170 if (rsSurface_ == nullptr) {
171 LOGE("rsSurface is nullptr");
172 return;
173 }
174 #ifdef ACE_ENABLE_GL
175 rc_ = OHOS::Rosen::RenderContextFactory::GetInstance().CreateEngine();
176 if (rc_ == nullptr) {
177 LOGE("InitilizeEglContext failed");
178 return;
179 } else {
180 LOGI("init egl context");
181 rc_->InitializeEglContext();
182 rsSurface_->SetRenderContext(rc_);
183 }
184 #endif
185 if (rc_ == nullptr) {
186 LOGI("rc is nullptr, use cpu");
187 }
188 }
189
~BootAnimation()190 BootAnimation::~BootAnimation()
191 {
192 window_->Destroy();
193 }
194
InitPicCoordinates()195 void BootAnimation::InitPicCoordinates()
196 {
197 if (windowWidth_ >= windowHeight_) {
198 realHeight_ = windowHeight_;
199 realWidth_ = realHeight_;
200 pointX_ = (windowWidth_ - realWidth_) / 2;
201 } else {
202 realWidth_ = windowWidth_;
203 realHeight_ = realWidth_;
204 pointY_ = (windowHeight_ - realHeight_) / 2;
205 }
206 }
207
OnVsync()208 void BootAnimation::OnVsync()
209 {
210 PostTask(std::bind(&BootAnimation::Draw, this));
211 }
212
CheckExitAnimation()213 void BootAnimation::CheckExitAnimation()
214 {
215 LOGI("CheckExitAnimation enter");
216 if (!setBootEvent_) {
217 LOGI("CheckExitAnimation set bootevent parameter");
218 system::SetParameter("bootevent.bootanimation.started", "true");
219 setBootEvent_ = true;
220 }
221 std::string windowInit = system::GetParameter("bootevent.boot.completed", "false");
222 if (windowInit == "true") {
223 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
224 LOGI("CheckExitAnimation read windowInit is true");
225 return;
226 }
227 }
228
PlaySound()229 void BootAnimation::PlaySound()
230 {
231 LOGI("PlaySound start");
232 bool bootSoundEnabled = system::GetBoolParameter("persist.graphic.bootsound.enabled", true);
233 if (bootSoundEnabled == true) {
234 LOGI("PlaySound read bootSoundEnabled is true");
235 if (soundPlayer_ == nullptr) {
236 soundPlayer_ = Media::PlayerFactory::CreatePlayer();
237 }
238 std::string uri = BOOT_SOUND_URI;
239 soundPlayer_->SetSource(uri);
240 soundPlayer_->SetLooping(false);
241 soundPlayer_->PrepareAsync();
242 soundPlayer_->Play();
243 }
244 LOGI("PlaySound end");
245 }
246