1 /*
2 * Copyright (c) 2023 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 "session/host/include/scene_persistence.h"
17
18 #include <sys/stat.h>
19
20 #include <hitrace_meter.h>
21 #include <image_packer.h>
22 #include <parameters.h>
23
24 #include "window_manager_hilog.h"
25
26 namespace OHOS::Rosen {
27 namespace {
28 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "ScenePersistence" };
29 constexpr const char* UNDERLINE_SEPARATOR = "_";
30 constexpr const char* ASTC_IMAGE_FORMAT = "image/astc/4*4";
31 constexpr const char* ASTC_IMAGE_SUFFIX = ".astc";
32 constexpr uint8_t ASTC_IMAGE_QUALITY = 20;
33
34 constexpr const char* IMAGE_FORMAT = "image/png";
35 constexpr const char* IMAGE_SUFFIX = ".png";
36 constexpr uint8_t IMAGE_QUALITY = 100;
37
38 constexpr uint8_t SUCCESS = 0;
39 } // namespace
40
41 std::string ScenePersistence::snapshotDirectory_;
42 std::string ScenePersistence::updatedIconDirectory_;
43 std::shared_ptr<WSFFRTHelper> ScenePersistence::snapshotFfrtHelper_;
44
CreateSnapshotDir(const std::string & directory)45 bool ScenePersistence::CreateSnapshotDir(const std::string& directory)
46 {
47 snapshotDirectory_ = directory + "/SceneSnapShot/";
48 if (mkdir(snapshotDirectory_.c_str(), S_IRWXU)) {
49 WLOGFD("mkdir failed or the directory already exists");
50 return false;
51 }
52 return true;
53 }
54
CreateUpdatedIconDir(const std::string & directory)55 bool ScenePersistence::CreateUpdatedIconDir(const std::string& directory)
56 {
57 updatedIconDirectory_ = directory + "/UpdatedIcon/";
58 if (mkdir(updatedIconDirectory_.c_str(), S_IRWXU)) {
59 WLOGFD("mkdir failed or the directory already exists");
60 return false;
61 }
62 return true;
63 }
64
ScenePersistence(const std::string & bundleName,int32_t persistentId)65 ScenePersistence::ScenePersistence(const std::string& bundleName, int32_t persistentId)
66 : bundleName_(bundleName), persistentId_(persistentId)
67 {
68 if (IsAstcEnabled()) {
69 snapshotPath_ = snapshotDirectory_ + bundleName + UNDERLINE_SEPARATOR +
70 std::to_string(persistentId) + ASTC_IMAGE_SUFFIX;
71 } else {
72 snapshotPath_ = snapshotDirectory_ + bundleName + UNDERLINE_SEPARATOR +
73 std::to_string(persistentId) + IMAGE_SUFFIX;
74 }
75 updatedIconPath_ = updatedIconDirectory_ + bundleName + IMAGE_SUFFIX;
76 if (snapshotFfrtHelper_ == nullptr) {
77 snapshotFfrtHelper_ = std::make_shared<WSFFRTHelper>();
78 }
79 }
80
~ScenePersistence()81 ScenePersistence::~ScenePersistence()
82 {
83 TLOGI(WmsLogTag::WMS_LIFE, "destroyed, persistentId: %{public}d", persistentId_);
84 remove(snapshotPath_.c_str());
85 }
86
GetSnapshotFfrtHelper() const87 std::shared_ptr<WSFFRTHelper> ScenePersistence::GetSnapshotFfrtHelper() const
88 {
89 return snapshotFfrtHelper_;
90 }
91
IsAstcEnabled()92 bool ScenePersistence::IsAstcEnabled()
93 {
94 static bool isAstcEnabled = system::GetBoolParameter("persist.multimedia.image.astc.enabled", true);
95 return isAstcEnabled;
96 }
97
SaveSnapshot(const std::shared_ptr<Media::PixelMap> & pixelMap,const std::function<void ()> resetSnapshotCallback)98 void ScenePersistence::SaveSnapshot(const std::shared_ptr<Media::PixelMap>& pixelMap,
99 const std::function<void()> resetSnapshotCallback)
100 {
101 savingSnapshotSum_.fetch_add(1);
102 isSavingSnapshot_.store(true);
103 auto task = [weakThis = wptr(this), pixelMap, resetSnapshotCallback,
104 savingSnapshotSum = savingSnapshotSum_.load()]() {
105 auto scenePersistence = weakThis.promote();
106 if (scenePersistence == nullptr || pixelMap == nullptr ||
107 scenePersistence->snapshotPath_.find('/') == std::string::npos) {
108 WLOGFE("scenePersistence is%{public}s nullptr, pixelMap is%{public}s nullptr",
109 scenePersistence == nullptr ? "" : " not", pixelMap == nullptr ? "" : " not");
110 resetSnapshotCallback();
111 return;
112 }
113
114 TLOGNI(WmsLogTag::WMS_PATTERN, "Save snapshot begin");
115 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "SaveSnapshot %s", scenePersistence->snapshotPath_.c_str());
116 OHOS::Media::ImagePacker imagePacker;
117 OHOS::Media::PackOption option;
118 option.format = IsAstcEnabled() ? ASTC_IMAGE_FORMAT : IMAGE_FORMAT;
119 option.quality = IsAstcEnabled() ? ASTC_IMAGE_QUALITY : IMAGE_QUALITY;
120 option.numberHint = 1;
121
122 std::lock_guard lock(scenePersistence->savingSnapshotMutex_);
123 remove(scenePersistence->snapshotPath_.c_str());
124 scenePersistence->snapshotSize_ = { pixelMap->GetWidth(), pixelMap->GetHeight() };
125 if (imagePacker.StartPacking(scenePersistence->snapshotPath_, option)) {
126 TLOGE(WmsLogTag::WMS_MAIN, "Save snapshot failed, starting packing error");
127 resetSnapshotCallback();
128 return;
129 }
130 if (imagePacker.AddImage(*pixelMap)) {
131 TLOGE(WmsLogTag::WMS_MAIN, "Save snapshot failed, adding image error");
132 resetSnapshotCallback();
133 return;
134 }
135 int64_t packedSize = 0;
136 if (imagePacker.FinalizePacking(packedSize)) {
137 TLOGE(WmsLogTag::WMS_MAIN, "Save snapshot failed, finalizing packing error");
138 resetSnapshotCallback();
139 return;
140 }
141 // If the current num is equals to the latest num, it is the last saveSnapshot task
142 if (savingSnapshotSum == scenePersistence->savingSnapshotSum_.load()) {
143 resetSnapshotCallback();
144 scenePersistence->isSavingSnapshot_.store(false);
145 }
146 TLOGNI(WmsLogTag::WMS_PATTERN, "Save snapshot end, packed size %{public}" PRIu64, packedSize);
147 };
148 snapshotFfrtHelper_->SubmitTask(std::move(task), "SaveSnapshot" + snapshotPath_);
149 }
150
IsSavingSnapshot()151 bool ScenePersistence::IsSavingSnapshot()
152 {
153 return isSavingSnapshot_.load();
154 }
155
RenameSnapshotFromOldPersistentId(const int32_t & oldPersistentId)156 void ScenePersistence::RenameSnapshotFromOldPersistentId(const int32_t& oldPersistentId)
157 {
158 auto task = [weakThis = wptr(this), oldPersistentId]() {
159 auto scenePersistence = weakThis.promote();
160 if (scenePersistence == nullptr) {
161 WLOGFE("scenePersistence is nullptr");
162 return;
163 }
164 std::string oldSnapshotPath;
165 if (IsAstcEnabled()) {
166 oldSnapshotPath = snapshotDirectory_ + scenePersistence->bundleName_ + UNDERLINE_SEPARATOR +
167 std::to_string(oldPersistentId) + ASTC_IMAGE_SUFFIX;
168 } else {
169 oldSnapshotPath = snapshotDirectory_ + scenePersistence->bundleName_ + UNDERLINE_SEPARATOR +
170 std::to_string(oldPersistentId) + IMAGE_SUFFIX;
171 }
172 std::lock_guard lock(scenePersistence->savingSnapshotMutex_);
173 int ret = std::rename(oldSnapshotPath.c_str(), scenePersistence->snapshotPath_.c_str());
174 if (ret == 0) {
175 WLOGFI("Rename snapshot from %{public}s to %{public}s.",
176 oldSnapshotPath.c_str(), scenePersistence->snapshotPath_.c_str());
177 } else {
178 WLOGFW("Failed to rename snapshot from %{public}s to %{public}s.",
179 oldSnapshotPath.c_str(), scenePersistence->snapshotPath_.c_str());
180 }
181 };
182 snapshotFfrtHelper_->SubmitTask(std::move(task), "RenameSnapshotFromOldPersistentId"
183 + std::to_string(oldPersistentId));
184 }
185
GetSnapshotFilePath()186 std::string ScenePersistence::GetSnapshotFilePath()
187 {
188 return snapshotPath_;
189 }
190
SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap> & pixelMap)191 void ScenePersistence::SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap>& pixelMap)
192 {
193 if (pixelMap == nullptr || updatedIconPath_.find('/') == std::string::npos) {
194 return;
195 }
196
197 OHOS::Media::ImagePacker imagePacker;
198 OHOS::Media::PackOption option;
199 option.format = IMAGE_FORMAT;
200 option.quality = IMAGE_QUALITY;
201 option.numberHint = 1;
202
203 if (remove(updatedIconPath_.c_str())) {
204 WLOGFD("Failed to delete old file");
205 }
206 if (imagePacker.StartPacking(GetUpdatedIconPath(), option)) {
207 TLOGE(WmsLogTag::WMS_MAIN, "Save updated icon failed, starting packing error");
208 return;
209 }
210 if (imagePacker.AddImage(*pixelMap)) {
211 TLOGE(WmsLogTag::WMS_MAIN, "Save updated icon failed, adding image error");
212 return;
213 }
214 int64_t packedSize = 0;
215 if (imagePacker.FinalizePacking(packedSize)) {
216 TLOGE(WmsLogTag::WMS_MAIN, "Save updated icon failed, finalizing packing error");
217 return;
218 }
219 WLOGFD("SaveUpdatedIcon finished");
220 }
221
GetUpdatedIconPath() const222 std::string ScenePersistence::GetUpdatedIconPath() const
223 {
224 return updatedIconPath_;
225 }
226
GetSnapshotSize() const227 std::pair<uint32_t, uint32_t> ScenePersistence::GetSnapshotSize() const
228 {
229 return snapshotSize_;
230 }
231
SetHasSnapshot(bool hasSnapshot)232 void ScenePersistence::SetHasSnapshot(bool hasSnapshot)
233 {
234 hasSnapshot_ = hasSnapshot;
235 }
236
HasSnapshot() const237 bool ScenePersistence::HasSnapshot() const
238 {
239 return hasSnapshot_;
240 }
241
IsSnapshotExisted() const242 bool ScenePersistence::IsSnapshotExisted() const
243 {
244 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IsSnapshotExisted");
245 struct stat buf;
246 if (stat(snapshotPath_.c_str(), &buf)) {
247 WLOGFD("Snapshot file %{public}s does not exist", snapshotPath_.c_str());
248 return false;
249 }
250 return S_ISREG(buf.st_mode);
251 }
252
GetLocalSnapshotPixelMap(const float oriScale,const float newScale) const253 std::shared_ptr<Media::PixelMap> ScenePersistence::GetLocalSnapshotPixelMap(const float oriScale,
254 const float newScale) const
255 {
256 if (!IsSnapshotExisted()) {
257 WLOGE("local snapshot pic is not existed");
258 return nullptr;
259 }
260
261 uint32_t errorCode = 0;
262 Media::SourceOptions sourceOpts;
263 sourceOpts.formatHint = IsAstcEnabled() ? ASTC_IMAGE_FORMAT : IMAGE_FORMAT;
264 std::lock_guard lock(savingSnapshotMutex_);
265 auto imageSource = Media::ImageSource::CreateImageSource(snapshotPath_, sourceOpts, errorCode);
266 if (!imageSource) {
267 WLOGE("create image source fail, errCode : %{public}d", errorCode);
268 return nullptr;
269 }
270
271 Media::ImageInfo info;
272 int32_t decoderWidth = 0;
273 int32_t decoderHeight = 0;
274 errorCode = imageSource->GetImageInfo(info);
275 if (errorCode == SUCCESS) {
276 decoderWidth = info.size.width;
277 decoderHeight = info.size.height;
278 }
279 Media::DecodeOptions decodeOpts;
280 decodeOpts.desiredPixelFormat = Media::PixelFormat::RGBA_8888;
281 if (oriScale != 0 && decoderWidth > 0 && decoderHeight > 0) {
282 auto isNeedToScale = newScale < oriScale;
283 decodeOpts.desiredSize.width = isNeedToScale ?
284 static_cast<int>(decoderWidth * newScale / oriScale) : decoderWidth;
285 decodeOpts.desiredSize.height = isNeedToScale ?
286 static_cast<int>(decoderHeight * newScale / oriScale) : decoderHeight;
287 }
288 return imageSource->CreatePixelMap(decodeOpts, errorCode);
289 }
290 } // namespace OHOS::Rosen
291