• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 
16 #include "boot_compile_progress.h"
17 
18 #include <chrono>
19 #include "event_handler.h"
20 #include "parameter.h"
21 #include "parameters.h"
22 #include "platform/common/rs_system_properties.h"
23 #include "recording/recording_canvas.h"
24 #include "animation/rs_animation_common.h"
25 #include "animation/rs_cubic_bezier_interpolator.h"
26 #include "animation/rs_interpolator.h"
27 #include "transaction/rs_interfaces.h"
28 #include "transaction/rs_render_service_client.h"
29 #include "transaction/rs_transaction.h"
30 #include "ui/rs_ui_context_manager.h"
31 #include "util.h"
32 
33 namespace OHOS {
34 namespace {
35     constexpr const char* OTA_COMPILE_TIME_LIMIT = "persist.bms.optimizing_apps.timing";
36     constexpr int32_t OTA_COMPILE_TIME_LIMIT_DEFAULT = 4 * 60;
37     constexpr const char* OTA_COMPILE_DISPLAY_INFO = "const.bms.optimizing_apps.display_info";
38     const std::string BOOTEVENT_BMS_MAIN_BUNDLES_READY = "bootevent.bms.main.bundles.ready";
39     const std::string OTA_COMPILE_DISPLAY_INFO_DEFAULT = "正在优化应用";
40     const std::string OTA_COMPILE_DISPLAY_INFO_OVERSEA = "Optimizing Apps";
41     constexpr const char* REGION_PARA_STR_CUST = "const.cust.region";
42     constexpr const char* CHINA_REGION = "cn";
43     constexpr const int32_t ONE_HUNDRED_PERCENT = 100;
44     constexpr const int32_t SEC_MS = 1000;
45     constexpr const int32_t CIRCLE_NUM = 3;
46     constexpr const float RADIUS = 3.0f;
47     constexpr const float RADIUS_WEARABLE = 5.0f;
48     constexpr const float OFFSET_Y_PERCENT = 0.2f;
49     constexpr const float HEIGHT_PERCENT = 0.05f;
50     constexpr const int TEXT_BLOB_OFFSET = 5;
51     constexpr const int FONT_SIZE_PHONE = 12;
52     constexpr const int FONT_SIZE_OTHER = 24;
53     constexpr const int FONT_SIZE_WEARABLE = 24;
54     constexpr const int OFFSET_Y_WEARABLE = 120;
55     constexpr const int MAGIN_WEARABLE = 12;
56     constexpr const int HEIGHT_WEARABLE = FONT_SIZE_WEARABLE + RADIUS_WEARABLE * 2 + MAGIN_WEARABLE;
57     constexpr const int32_t MAX_RETRY_TIMES = 5;
58     constexpr const int32_t WAIT_MS = 500;
59     constexpr const int32_t LOADING_FPS = 30;
60     constexpr const int32_t PERIOD_FPS = 10;
61     constexpr const int32_t CHANGE_FREQ = 4;
62     constexpr const float TEN_FRAME_TIMES = 10.0f;
63     constexpr const float SHARP_CURVE_CTLX1 = 0.33f;
64     constexpr const float SHARP_CURVE_CTLY1 = 0.0f;
65     constexpr const float SHARP_CURVE_CTLX2 = 0.67f;
66     constexpr const float SHARP_CURVE_CTLY2 = 1.0f;
67     constexpr const float OPACITY_ARR[3][3][2] = {
68         { { 0.2f, 1.0f }, { 1.0f, 0.5f }, { 0.5f, 0.2f } },
69         { { 0.5f, 0.2f }, { 0.2f, 1.0f }, { 1.0f, 0.5f } },
70         { { 1.0f, 0.5f }, { 0.5f, 0.2f }, { 0.2f, 1.0f } },
71     };
72     constexpr const int DOUBLE_TIMES = 2;
73 }
74 
Init(const std::string & configPath,const BootAnimationConfig & config)75 void BootCompileProgress::Init(const std::string& configPath, const BootAnimationConfig& config)
76 {
77     LOGI("ota compile, screenId: " BPUBU64 "", config.screenId);
78     RecordDeviceType();
79     screenId_ = config.screenId;
80     rotateDegree_ = config.rotateDegree;
81     if (!config.screenStatus.empty()) {
82         screenStatus_ = std::atoi(config.screenStatus.c_str());
83     }
84     ParseProgressConfig(configPath, progressConfigsMap_);
85     Rosen::RSInterfaces& interface = Rosen::RSInterfaces::GetInstance();
86     Rosen::RSScreenModeInfo modeInfo = interface.GetScreenActiveMode(config.screenId);
87     windowWidth_ = modeInfo.GetScreenWidth();
88     windowHeight_ = modeInfo.GetScreenHeight();
89     fontSize_ = isWearable_ ? FONT_SIZE_WEARABLE :
90         TranslateVp2Pixel(std::min(windowWidth_, windowHeight_), isOther_ ? FONT_SIZE_OTHER : FONT_SIZE_PHONE);
91     currentRadius_ = isWearable_ ? RADIUS_WEARABLE :
92         TranslateVp2Pixel(std::min(windowWidth_, windowHeight_), isOther_ ? RADIUS * DOUBLE_TIMES : RADIUS);
93 
94     timeLimitSec_ = system::GetIntParameter<int32_t>(OTA_COMPILE_TIME_LIMIT, OTA_COMPILE_TIME_LIMIT_DEFAULT);
95     tf_ = Rosen::Drawing::Typeface::MakeFromName("HarmonyOS Sans SC", Rosen::Drawing::FontStyle());
96 
97     std::string defaultDisplayInfo = OTA_COMPILE_DISPLAY_INFO_DEFAULT;
98     if (system::GetParameter(REGION_PARA_STR_CUST, CHINA_REGION) != CHINA_REGION) {
99         defaultDisplayInfo = OTA_COMPILE_DISPLAY_INFO_OVERSEA;
100     }
101     displayInfo_ = system::GetParameter(OTA_COMPILE_DISPLAY_INFO, defaultDisplayInfo);
102     sharpCurve_ = std::make_shared<Rosen::RSCubicBezierInterpolator>(
103         SHARP_CURVE_CTLX1, SHARP_CURVE_CTLY1, SHARP_CURVE_CTLX2, SHARP_CURVE_CTLY2);
104     compileRunner_ = AppExecFwk::EventRunner::Create(false);
105     compileHandler_ = std::make_shared<AppExecFwk::EventHandler>(compileRunner_);
106     compileHandler_->PostTask([this] { this->CreateCanvasNode(); });
107     compileHandler_->PostTask([this] { this->RegisterVsyncCallback(); });
108     compileRunner_->Run();
109 }
110 
CreateCanvasNode()111 bool BootCompileProgress::CreateCanvasNode()
112 {
113     struct Rosen::RSSurfaceNodeConfig surfaceNodeConfig;
114     surfaceNodeConfig.SurfaceNodeName = "BootCompileProgressNode";
115     surfaceNodeConfig.isSync = true;
116     Rosen::RSSurfaceNodeType surfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
117     rsUIDirector_ = OHOS::Rosen::RSUIDirector::Create();
118     rsUIDirector_->Init(false, false);
119     auto rsUIContext = rsUIDirector_->GetRSUIContext();
120     rsSurfaceNode_ = Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType, true, false, rsUIContext);
121     if (!rsSurfaceNode_) {
122         LOGE("ota compile, SFNode create failed");
123         compileRunner_->Stop();
124         return false;
125     }
126     float positionZ = MAX_ZORDER + 1;
127     rsSurfaceNode_->SetRotation(rotateDegree_);
128     rsSurfaceNode_->SetPositionZ(positionZ);
129     rsSurfaceNode_->SetBounds(0, 0, windowWidth_, windowHeight_);
130     rsSurfaceNode_->SetBackgroundColor(SK_ColorTRANSPARENT);
131     rsSurfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT);
132     rsSurfaceNode_->SetBootAnimation(true);
133     Rosen::RSTransaction::FlushImplicitTransaction();
134     rsSurfaceNode_->AttachToDisplay(screenId_);
135     Rosen::RSTransaction::FlushImplicitTransaction();
136 
137     rsCanvasNode_ = Rosen::RSCanvasNode::Create(true, false, rsUIContext);
138     rsCanvasNode_->SetBounds(0, 0, windowWidth_, windowHeight_);
139     SetFrame();
140     rsCanvasNode_->SetBackgroundColor(Rosen::Drawing::Color::COLOR_TRANSPARENT);
141     rsCanvasNode_->SetPositionZ(positionZ);
142     rsSurfaceNode_->AddChild(rsCanvasNode_, 0);
143 
144     LOGI("CreateCanvasNode success");
145     return true;
146 }
147 
RegisterVsyncCallback()148 bool BootCompileProgress::RegisterVsyncCallback()
149 {
150     if (IsBmsBundleReady()) {
151         LOGI("bms bundle is already done.");
152         compileRunner_->Stop();
153         return false;
154     }
155 
156     auto& rsClient = Rosen::RSInterfaces::GetInstance();
157     int32_t retry = 0;
158     while (receiver_ == nullptr) {
159         if (retry++ > MAX_RETRY_TIMES) {
160             LOGE("get vsync receiver failed");
161             compileRunner_->Stop();
162             return false;
163         }
164         if (retry > 1) {
165             std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
166         }
167         receiver_ = rsClient.CreateVSyncReceiver("BootCompileProgress", compileHandler_);
168     }
169     VsyncError ret = receiver_->Init();
170     if (ret) {
171         compileRunner_->Stop();
172         LOGE("init vsync receiver failed");
173         return false;
174     }
175 
176     Rosen::VSyncReceiver::FrameCallback fcb = {
177         .userData_ = this,
178         .callback_ = [this](int64_t, void*) { this->OnVsync(); },
179     };
180     ret = receiver_->SetVSyncRate(fcb, CHANGE_FREQ);
181     if (ret) {
182         compileRunner_->Stop();
183         LOGE("set vsync rate failed");
184     }
185 
186     startTimeMs_ = GetSystemCurrentTime();
187     endTimePredictMs_ = startTimeMs_ + timeLimitSec_ * SEC_MS;
188 
189     LOGI("RegisterVsyncCallback success");
190     return true;
191 }
192 
IsBmsBundleReady()193 bool BootCompileProgress::IsBmsBundleReady()
194 {
195     return system::GetBoolParameter(BOOTEVENT_BMS_MAIN_BUNDLES_READY, false);
196 }
197 
OnVsync()198 void BootCompileProgress::OnVsync()
199 {
200     if (!isUpdateOptEnd_) {
201         compileHandler_->PostTask([this] { this->DrawCompileProgress(); });
202     } else {
203         LOGI("ota compile completed");
204         compileRunner_->Stop();
205     }
206 }
207 
DrawCompileProgress()208 void BootCompileProgress::DrawCompileProgress()
209 {
210     UpdateCompileProgress();
211 
212     auto canvas = static_cast<Rosen::Drawing::RecordingCanvas*>(rsCanvasNode_->BeginRecording(windowWidth_,
213         isWearable_ ? HEIGHT_WEARABLE : std::max(windowWidth_, windowHeight_) * HEIGHT_PERCENT));
214     if (canvas == nullptr) {
215         LOGE("DrawCompileProgress canvas is null");
216         return;
217     }
218 
219     Rosen::Drawing::Font font;
220     font.SetTypeface(tf_);
221     font.SetSize(fontSize_);
222     char info[64] = {0};
223     int ret = sprintf_s(info, sizeof(info), "%s %d%%", displayInfo_.c_str(), progress_);
224     if (ret == -1) {
225         LOGE("set info failed");
226         return;
227     }
228     std::shared_ptr<Rosen::Drawing::TextBlob> textBlob = Rosen::Drawing::TextBlob::MakeFromString(info, font);
229     auto textBound = textBlob->Bounds();
230     if (textBound == nullptr) {
231         LOGE("textBound is null");
232         return;
233     }
234 
235     Rosen::Drawing::Brush whiteBrush;
236     whiteBrush.SetColor(0xFFFFFFFF);
237     whiteBrush.SetAntiAlias(true);
238     canvas->AttachBrush(whiteBrush);
239 
240     auto textWidth = font.MeasureText(info, strlen(info), Rosen::Drawing::TextEncoding::UTF8, nullptr);
241     float scalarX = windowWidth_ / NUMBER_TWO - textWidth / NUMBER_TWO;
242     float scalarY = TEXT_BLOB_OFFSET + textBound->GetHeight() / NUMBER_TWO;
243     canvas->DrawTextBlob(textBlob.get(), scalarX, scalarY);
244     canvas->DetachBrush();
245 
246     DrawMarginBrush(canvas);
247 
248     int32_t freqNum = times_++;
249     for (int i = 0; i < CIRCLE_NUM; i++) {
250         canvas->AttachBrush(DrawProgressPoint(i, freqNum));
251         int pointX = windowWidth_/2.0f + 4 * currentRadius_ * (i - 1);
252         int pointY = rsCanvasNode_->GetPaintHeight() - currentRadius_;
253         canvas->DrawCircle({pointX, pointY}, currentRadius_);
254         canvas->DetachBrush();
255     }
256 
257     rsCanvasNode_->FinishRecording();
258     Rosen::RSTransaction::FlushImplicitTransaction();
259 
260     if (progress_ >= ONE_HUNDRED_PERCENT) {
261         isUpdateOptEnd_ = true;
262     }
263 }
264 
DrawMarginBrush(Rosen::Drawing::RecordingCanvas * canvas)265 void BootCompileProgress::DrawMarginBrush(Rosen::Drawing::RecordingCanvas* canvas)
266 {
267     if (isWearable_) {
268         Rosen::Drawing::Brush marginBrush;
269         marginBrush.SetColor(0x00000000);
270         marginBrush.SetAntiAlias(true);
271         Rosen::Drawing::Rect rect(0, FONT_SIZE_WEARABLE, windowWidth_, FONT_SIZE_WEARABLE + MAGIN_WEARABLE);
272         canvas->AttachBrush(marginBrush);
273         canvas->DrawRect(rect);
274         canvas->DetachBrush();
275     }
276 }
277 
UpdateCompileProgress()278 void BootCompileProgress::UpdateCompileProgress()
279 {
280     if (!IsBmsBundleReady()) {
281         int64_t now = GetSystemCurrentTime();
282         if (endTimePredictMs_ < now) {
283             progress_ = ONE_HUNDRED_PERCENT;
284             return;
285         }
286         if (!timeLimitSec_) {
287             return;
288         }
289         progress_ = (int32_t)((now - startTimeMs_) * ONE_HUNDRED_PERCENT / (timeLimitSec_ * SEC_MS));
290         progress_ = progress_ < 0 ? 0 : progress_ > ONE_HUNDRED_PERCENT ? ONE_HUNDRED_PERCENT: progress_;
291     } else {
292         progress_++;
293     }
294 
295     LOGD("update progress: %{public}d", progress_);
296 }
297 
DrawProgressPoint(int32_t idx,int32_t frameNum)298 Rosen::Drawing::Brush BootCompileProgress::DrawProgressPoint(int32_t idx, int32_t frameNum)
299 {
300     int32_t fpsNo = frameNum % LOADING_FPS;
301     int32_t fpsStage = fpsNo / PERIOD_FPS;
302     float input  = fpsNo % PERIOD_FPS / TEN_FRAME_TIMES;
303 
304     float startOpaCity = OPACITY_ARR[idx][fpsStage][0];
305     float endOpaCity = OPACITY_ARR[idx][fpsStage][1];
306 
307     float fraction = sharpCurve_->Interpolate(input);
308     float opacity = startOpaCity + (endOpaCity - startOpaCity) * fraction;
309 
310     Rosen::Drawing::Brush brush;
311     brush.SetColor(0xFFFFFFFF);
312     brush.SetAntiAlias(true);
313     brush.SetAlphaF(opacity);
314     return brush;
315 }
316 
RecordDeviceType()317 void BootCompileProgress::RecordDeviceType()
318 {
319     std::string deviceType = GetDeviceType();
320     LOGI("deviceType: %{public}s", deviceType.c_str());
321     if (deviceType == DEVICE_TYPE_WEARABLE) {
322         isWearable_ = true;
323     } else if (deviceType != DEVICE_TYPE_PHONE) {
324         isOther_ = true;
325     }
326 }
327 
SetSpecialProgressFrame(int32_t maxLength,int32_t screenId)328 void BootCompileProgress::SetSpecialProgressFrame(int32_t maxLength, int32_t screenId)
329 {
330     BootAnimationProgressConfig progressConfig = progressConfigsMap_.find(screenId)->second;
331     float positionX = progressConfig.progressOffset == -1 ? 0 : progressConfig.progressOffset;
332     float positionY = progressConfig.progressHeight == -1 ? windowHeight_ - maxLength * OFFSET_Y_PERCENT
333         : progressConfig.progressHeight;
334     float frameHeight = progressConfig.progressFrameHeight == -1 ? maxLength * HEIGHT_PERCENT
335         : progressConfig.progressFrameHeight;
336     rsCanvasNode_->SetFrame(positionX, positionY, windowWidth_, frameHeight);
337     fontSize_ = progressConfig.progressFontSize == -1 ? fontSize_ : progressConfig.progressFontSize;
338     currentRadius_ = progressConfig.progressRadiusSize == -1 ? currentRadius_ : progressConfig.progressRadiusSize;
339     if (progressConfig.progressDegree > 0) {
340         rsCanvasNode_->SetRotation(progressConfig.progressDegree);
341     }
342 }
343 
SetFrame()344 void BootCompileProgress::SetFrame()
345 {
346     int32_t maxLength = std::max(windowWidth_, windowHeight_);
347     int32_t tempScreenId = screenStatus_ == -1 ? static_cast<int32_t> (screenId_) : screenStatus_;
348     if (!progressConfigsMap_.empty() && progressConfigsMap_.find(tempScreenId) != progressConfigsMap_.end()) {
349         SetSpecialProgressFrame(maxLength, tempScreenId);
350     } else if (isWearable_) {
351         rsCanvasNode_->SetFrame(0, windowHeight_ - OFFSET_Y_WEARABLE - HEIGHT_WEARABLE, windowWidth_, HEIGHT_WEARABLE);
352     } else {
353         rsCanvasNode_->SetFrame(0, windowHeight_ - maxLength * OFFSET_Y_PERCENT, windowWidth_,
354             maxLength * HEIGHT_PERCENT);
355     }
356 }
357 } // namespace OHOS
358