• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         TLOGD(WmsLogTag::WMS_PATTERN, "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         TLOGD(WmsLogTag::DEFAULT, "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_PATTERN, "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             TLOGNE(WmsLogTag::WMS_PATTERN, "scenePersistence %{public}s nullptr, pixelMap %{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             TLOGNE(WmsLogTag::WMS_PATTERN, "Save snapshot failed, starting packing error");
127             resetSnapshotCallback();
128             return;
129         }
130         if (imagePacker.AddImage(*pixelMap)) {
131             TLOGNE(WmsLogTag::WMS_PATTERN, "Save snapshot failed, adding image error");
132             resetSnapshotCallback();
133             return;
134         }
135         int64_t packedSize = 0;
136         if (imagePacker.FinalizePacking(packedSize)) {
137             TLOGNE(WmsLogTag::WMS_PATTERN, "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         }
145         TLOGNI(WmsLogTag::WMS_PATTERN, "Save snapshot end, packed size %{public}" PRIu64, packedSize);
146     };
147     snapshotFfrtHelper_->SubmitTask(std::move(task), "SaveSnapshot" + snapshotPath_);
148 }
149 
IsSavingSnapshot()150 bool ScenePersistence::IsSavingSnapshot()
151 {
152     return isSavingSnapshot_.load();
153 }
154 
ResetSnapshotCache()155 void ScenePersistence::ResetSnapshotCache()
156 {
157     isSavingSnapshot_.store(false);
158 }
159 
RenameSnapshotFromOldPersistentId(const int32_t & oldPersistentId)160 void ScenePersistence::RenameSnapshotFromOldPersistentId(const int32_t& oldPersistentId)
161 {
162     auto task = [weakThis = wptr(this), oldPersistentId]() {
163         auto scenePersistence = weakThis.promote();
164         if (scenePersistence == nullptr) {
165             TLOGNE(WmsLogTag::WMS_PATTERN, "scenePersistence is nullptr");
166             return;
167         }
168         std::string oldSnapshotPath;
169         if (IsAstcEnabled()) {
170             oldSnapshotPath = snapshotDirectory_ + scenePersistence->bundleName_ + UNDERLINE_SEPARATOR +
171                 std::to_string(oldPersistentId) + ASTC_IMAGE_SUFFIX;
172         } else {
173             oldSnapshotPath = snapshotDirectory_ + scenePersistence->bundleName_ + UNDERLINE_SEPARATOR +
174                 std::to_string(oldPersistentId) + IMAGE_SUFFIX;
175         }
176         std::lock_guard lock(scenePersistence->savingSnapshotMutex_);
177         int ret = std::rename(oldSnapshotPath.c_str(), scenePersistence->snapshotPath_.c_str());
178         if (ret == 0) {
179             TLOGNI(WmsLogTag::WMS_PATTERN, "Rename snapshot from %{public}s to %{public}s.",
180                 oldSnapshotPath.c_str(), scenePersistence->snapshotPath_.c_str());
181         } else {
182             TLOGNW(WmsLogTag::WMS_PATTERN, "Failed to rename snapshot from %{public}s to %{public}s.",
183                 oldSnapshotPath.c_str(), scenePersistence->snapshotPath_.c_str());
184         }
185     };
186     snapshotFfrtHelper_->SubmitTask(std::move(task), "RenameSnapshotFromOldPersistentId"
187         + std::to_string(oldPersistentId));
188 }
189 
GetSnapshotFilePath()190 std::string ScenePersistence::GetSnapshotFilePath()
191 {
192     return snapshotPath_;
193 }
194 
SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap> & pixelMap)195 void ScenePersistence::SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap>& pixelMap)
196 {
197     if (pixelMap == nullptr || updatedIconPath_.find('/') == std::string::npos) {
198         return;
199     }
200 
201     OHOS::Media::ImagePacker imagePacker;
202     OHOS::Media::PackOption option;
203     option.format = IMAGE_FORMAT;
204     option.quality = IMAGE_QUALITY;
205     option.numberHint = 1;
206 
207     if (remove(updatedIconPath_.c_str())) {
208         TLOGD(WmsLogTag::DEFAULT, "Failed to delete old file");
209     }
210     if (imagePacker.StartPacking(GetUpdatedIconPath(), option)) {
211         TLOGE(WmsLogTag::DEFAULT, "Save updated icon failed, starting packing error");
212         return;
213     }
214     if (imagePacker.AddImage(*pixelMap)) {
215         TLOGE(WmsLogTag::DEFAULT, "Save updated icon failed, adding image error");
216         return;
217     }
218     int64_t packedSize = 0;
219     if (imagePacker.FinalizePacking(packedSize)) {
220         TLOGE(WmsLogTag::DEFAULT, "Save updated icon failed, finalizing packing error");
221         return;
222     }
223     TLOGD(WmsLogTag::DEFAULT, "SaveUpdatedIcon finished");
224 }
225 
GetUpdatedIconPath() const226 std::string ScenePersistence::GetUpdatedIconPath() const
227 {
228     return updatedIconPath_;
229 }
230 
GetSnapshotSize() const231 std::pair<uint32_t, uint32_t> ScenePersistence::GetSnapshotSize() const
232 {
233     return snapshotSize_;
234 }
235 
SetHasSnapshot(bool hasSnapshot)236 void ScenePersistence::SetHasSnapshot(bool hasSnapshot)
237 {
238     hasSnapshot_ = hasSnapshot;
239 }
240 
HasSnapshot() const241 bool ScenePersistence::HasSnapshot() const
242 {
243     return hasSnapshot_;
244 }
245 
IsSnapshotExisted() const246 bool ScenePersistence::IsSnapshotExisted() const
247 {
248     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IsSnapshotExisted");
249     struct stat buf;
250     if (stat(snapshotPath_.c_str(), &buf)) {
251         TLOGD(WmsLogTag::WMS_PATTERN, "Snapshot file %{public}s does not exist", snapshotPath_.c_str());
252         return false;
253     }
254     return S_ISREG(buf.st_mode);
255 }
256 
GetLocalSnapshotPixelMap(const float oriScale,const float newScale) const257 std::shared_ptr<Media::PixelMap> ScenePersistence::GetLocalSnapshotPixelMap(const float oriScale,
258     const float newScale) const
259 {
260     if (!IsSnapshotExisted()) {
261         TLOGE(WmsLogTag::WMS_PATTERN, "local snapshot pic is not existed");
262         return nullptr;
263     }
264 
265     uint32_t errorCode = 0;
266     Media::SourceOptions sourceOpts;
267     sourceOpts.formatHint = IsAstcEnabled() ? ASTC_IMAGE_FORMAT : IMAGE_FORMAT;
268     std::lock_guard lock(savingSnapshotMutex_);
269     auto imageSource = Media::ImageSource::CreateImageSource(snapshotPath_, sourceOpts, errorCode);
270     if (!imageSource) {
271         TLOGE(WmsLogTag::WMS_PATTERN, "create image source fail, errCode: %{public}u", errorCode);
272         return nullptr;
273     }
274 
275     Media::ImageInfo info;
276     int32_t decoderWidth = 0;
277     int32_t decoderHeight = 0;
278     errorCode = imageSource->GetImageInfo(info);
279     if (errorCode == SUCCESS) {
280         decoderWidth = info.size.width;
281         decoderHeight = info.size.height;
282     }
283     Media::DecodeOptions decodeOpts;
284     decodeOpts.desiredPixelFormat = Media::PixelFormat::RGBA_8888;
285     if (oriScale != 0 && decoderWidth > 0 && decoderHeight > 0) {
286         auto isNeedToScale = newScale < oriScale;
287         decodeOpts.desiredSize.width = isNeedToScale ?
288             static_cast<int>(decoderWidth * newScale / oriScale) : decoderWidth;
289         decodeOpts.desiredSize.height = isNeedToScale ?
290             static_cast<int>(decoderHeight * newScale / oriScale) : decoderHeight;
291     }
292     return imageSource->CreatePixelMap(decodeOpts, errorCode);
293 }
294 } // namespace OHOS::Rosen
295