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 <hitrace_meter.h>
19 #include <image_packer.h>
20
21 #include "window_manager_hilog.h"
22
23 namespace OHOS::Rosen {
24 namespace {
25 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "ScenePersistence" };
26 constexpr const char* UNDERLINE_SEPARATOR = "_";
27 constexpr const char* IMAGE_SUFFIX = ".png";
28 constexpr uint8_t IMAGE_QUALITY = 100;
29 constexpr uint8_t SUCCESS = 0;
30 const std::string SNAPSHOT_THREAD = "OS_SnapshotThread";
31 } // namespace
32
33 std::string ScenePersistence::snapshotDirectory_;
34 std::string ScenePersistence::updatedIconDirectory_;
35 std::shared_ptr<TaskScheduler> ScenePersistence::snapshotScheduler_;
36
CreateSnapshotDir(const std::string & directory)37 bool ScenePersistence::CreateSnapshotDir(const std::string& directory)
38 {
39 snapshotDirectory_ = directory + "/SceneSnapShot/";
40 if (mkdir(snapshotDirectory_.c_str(), S_IRWXU)) {
41 WLOGFD("mkdir failed or the directory already exists");
42 return false;
43 }
44 return true;
45 }
46
CreateUpdatedIconDir(const std::string & directory)47 bool ScenePersistence::CreateUpdatedIconDir(const std::string& directory)
48 {
49 updatedIconDirectory_ = directory + "/UpdatedIcon/";
50 if (mkdir(updatedIconDirectory_.c_str(), S_IRWXU)) {
51 WLOGFD("mkdir failed or the directory already exists");
52 return false;
53 }
54 return true;
55 }
56
ScenePersistence(const std::string & bundleName,const int32_t & persistentId)57 ScenePersistence::ScenePersistence(const std::string& bundleName, const int32_t& persistentId)
58 {
59 bundleName_ = bundleName;
60 uint32_t fileID = static_cast<uint32_t>(persistentId) & 0x3fffffff;
61 snapshotPath_ = snapshotDirectory_ + bundleName + UNDERLINE_SEPARATOR + std::to_string(fileID) + IMAGE_SUFFIX;
62 updatedIconPath_ = updatedIconDirectory_ + bundleName + IMAGE_SUFFIX;
63 if (snapshotScheduler_ == nullptr) {
64 snapshotScheduler_ = std::make_shared<TaskScheduler>(SNAPSHOT_THREAD);
65 }
66 }
67
SaveSnapshot(const std::shared_ptr<Media::PixelMap> & pixelMap,const std::function<void ()> resetSnapshotCallback)68 void ScenePersistence::SaveSnapshot(const std::shared_ptr<Media::PixelMap>& pixelMap,
69 const std::function<void()> resetSnapshotCallback)
70 {
71 savingSnapshotSum_.fetch_add(1);
72 isSavingSnapshot_.store(true);
73 auto task = [weakThis = wptr(this), pixelMap, resetSnapshotCallback,
74 savingSnapshotSum = savingSnapshotSum_.load()]() {
75 auto scenePersistence = weakThis.promote();
76 if (scenePersistence == nullptr || pixelMap == nullptr ||
77 scenePersistence->snapshotPath_.find('/') == std::string::npos) {
78 WLOGFE("scenePersistence is%{public}s nullptr, pixelMap is%{public}s nullptr",
79 scenePersistence == nullptr ? "" : " not", pixelMap == nullptr ? "" : " not");
80 return;
81 }
82
83 WLOGFD("Save snapshot begin");
84 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "ScenePersistence:SaveSnapshot %s",
85 scenePersistence->snapshotPath_.c_str());
86 OHOS::Media::ImagePacker imagePacker;
87 OHOS::Media::PackOption option;
88 option.format = "image/png";
89 option.quality = IMAGE_QUALITY;
90 option.numberHint = 1;
91 std::set<std::string> formats;
92 if (imagePacker.GetSupportedFormats(formats)) {
93 WLOGFE("Failed to get supported formats");
94 return;
95 }
96
97 if (remove(scenePersistence->snapshotPath_.c_str())) {
98 WLOGFE("Failed to delete old file");
99 }
100 scenePersistence->snapshotSize_ = { pixelMap->GetWidth(), pixelMap->GetHeight() };
101 imagePacker.StartPacking(scenePersistence->snapshotPath_, option);
102 imagePacker.AddImage(*pixelMap);
103 int64_t packedSize = 0;
104 imagePacker.FinalizePacking(packedSize);
105 // If the current num is equals to the latest num, it is the last saveSnapshot task
106 if (savingSnapshotSum == scenePersistence->savingSnapshotSum_.load()) {
107 resetSnapshotCallback();
108 scenePersistence->isSavingSnapshot_.store(false);
109 }
110 WLOGFD("Save snapshot end, packed size %{public}" PRIu64, packedSize);
111 };
112 snapshotScheduler_->RemoveTask("SaveSnapshot" + snapshotPath_);
113 snapshotScheduler_->PostAsyncTask(task, "SaveSnapshot" + snapshotPath_);
114 }
115
IsSavingSnapshot()116 bool ScenePersistence::IsSavingSnapshot()
117 {
118 return isSavingSnapshot_.load();
119 }
120
RenameSnapshotFromOldPersistentId(const int32_t & oldPersistentId)121 void ScenePersistence::RenameSnapshotFromOldPersistentId(const int32_t &oldPersistentId)
122 {
123 auto task = [weakThis = wptr(this), oldPersistentId]() {
124 auto scenePersistence = weakThis.promote();
125 if (scenePersistence == nullptr) {
126 WLOGFE("scenePersistence is nullptr");
127 return;
128 }
129 uint32_t oldfileID = static_cast<uint32_t>(oldPersistentId) & 0x3fffffff;
130 std::string oldSnapshotPath_ = snapshotDirectory_ + scenePersistence->bundleName_ + UNDERLINE_SEPARATOR +
131 std::to_string(oldfileID) + IMAGE_SUFFIX;
132 int ret = std::rename(oldSnapshotPath_.c_str(), scenePersistence->snapshotPath_.c_str());
133 if (ret == 0) {
134 WLOGFI("Rename snapshot from %{public}s to %{public}s.",
135 oldSnapshotPath_.c_str(), scenePersistence->snapshotPath_.c_str());
136 } else {
137 WLOGFW("Failed to rename snapshot from %{public}s to %{public}s.",
138 oldSnapshotPath_.c_str(), scenePersistence->snapshotPath_.c_str());
139 }
140 };
141 snapshotScheduler_->PostAsyncTask(task, "RenameSnapshotFromOldPersistentId");
142 }
143
GetSnapshotFilePath()144 std::string ScenePersistence::GetSnapshotFilePath()
145 {
146 auto task = [weakThis = wptr(this)]() -> std::string {
147 auto scenePersistence = weakThis.promote();
148 if (scenePersistence == nullptr) {
149 WLOGFE("scenePersistence is nullptr");
150 return "";
151 }
152 return scenePersistence->snapshotPath_;
153 };
154 return snapshotScheduler_->PostSyncTask(task, "GetSnapshotFilePath");
155 }
156
GetSnapshotFilePathFromAce()157 std::string ScenePersistence::GetSnapshotFilePathFromAce()
158 {
159 return snapshotPath_;
160 }
161
SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap> & pixelMap)162 void ScenePersistence::SaveUpdatedIcon(const std::shared_ptr<Media::PixelMap>& pixelMap)
163 {
164 if (pixelMap == nullptr || updatedIconPath_.find('/') == std::string::npos) {
165 return;
166 }
167
168 OHOS::Media::ImagePacker imagePacker;
169 OHOS::Media::PackOption option;
170 option.format = "image/png";
171 option.quality = IMAGE_QUALITY;
172 option.numberHint = 1;
173 std::set<std::string> formats;
174 if (imagePacker.GetSupportedFormats(formats)) {
175 WLOGFE("Failed to get supported formats");
176 return;
177 }
178
179 if (remove(updatedIconPath_.c_str())) {
180 WLOGFD("Failed to delete old file");
181 }
182 imagePacker.StartPacking(GetUpdatedIconPath(), option);
183 imagePacker.AddImage(*pixelMap);
184 int64_t packedSize = 0;
185 imagePacker.FinalizePacking(packedSize);
186 WLOGFD("SaveUpdatedIcon finished");
187 }
188
GetUpdatedIconPath() const189 std::string ScenePersistence::GetUpdatedIconPath() const
190 {
191 return updatedIconPath_;
192 }
193
GetSnapshotSize() const194 std::pair<uint32_t, uint32_t> ScenePersistence::GetSnapshotSize() const
195 {
196 return snapshotSize_;
197 }
198
IsSnapshotExisted() const199 bool ScenePersistence::IsSnapshotExisted() const
200 {
201 struct stat buf;
202 if (stat(snapshotPath_.c_str(), &buf)) {
203 WLOGFD("Snapshot file %{public}s does not exist", snapshotPath_.c_str());
204 return false;
205 }
206 return S_ISREG(buf.st_mode);
207 }
208
GetLocalSnapshotPixelMap(const float oriScale,const float newScale) const209 std::shared_ptr<Media::PixelMap> ScenePersistence::GetLocalSnapshotPixelMap(const float oriScale,
210 const float newScale) const
211 {
212 if (!IsSnapshotExisted()) {
213 WLOGE("local snapshot pic is not existed");
214 return nullptr;
215 }
216
217 uint32_t errorCode = 0;
218 Media::SourceOptions sourceOpts;
219 sourceOpts.formatHint = "image/png";
220 auto imageSource = Media::ImageSource::CreateImageSource(snapshotPath_, sourceOpts, errorCode);
221 if (!imageSource) {
222 WLOGE("create image source fail, errCode : %{public}d", errorCode);
223 return nullptr;
224 }
225
226 Media::ImageInfo info;
227 int32_t decoderWidth = 0;
228 int32_t decoderHeight = 0;
229 errorCode = imageSource->GetImageInfo(info);
230 if (errorCode == SUCCESS) {
231 decoderWidth = info.size.width;
232 decoderHeight = info.size.height;
233 }
234 Media::DecodeOptions decodeOpts;
235 decodeOpts.desiredPixelFormat = Media::PixelFormat::RGBA_8888;
236 if (oriScale != 0 && decoderWidth > 0 && decoderHeight > 0) {
237 auto isNeedToScale = newScale < oriScale;
238 decodeOpts.desiredSize.width = isNeedToScale ?
239 static_cast<int>(decoderWidth * newScale / oriScale) : decoderWidth;
240 decodeOpts.desiredSize.height = isNeedToScale ?
241 static_cast<int>(decoderHeight * newScale / oriScale) : decoderHeight;
242 }
243 return imageSource->CreatePixelMap(decodeOpts, errorCode);
244 }
245 } // namespace OHOS::Rosen
246