1 /*
2 * Copyright (c) 2021-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 "mission_data_storage.h"
17 #include <cstdio>
18 #include "directory_ex.h"
19 #include "file_ex.h"
20 #include "hilog_tag_wrapper.h"
21 #include "hitrace_meter.h"
22 #include "image_packer.h"
23 #include "image_source.h"
24 #include "media_errors.h"
25 #include "mission_info_mgr.h"
26 #ifdef SUPPORT_GRAPHICS
27 #include <cstdio>
28 #include "securec.h"
29 #endif
30
31 namespace OHOS {
32 namespace AAFwk {
33 namespace {
34 constexpr const char* IMAGE_FORMAT = "image/jpeg";
35 constexpr uint8_t IMAGE_QUALITY = 75;
36 }
37 #ifdef SUPPORT_GRAPHICS
38 constexpr int32_t RGB888_PIXEL_BYTES = 3;
39 const mode_t MODE = 0770;
40 #endif
41
MissionDataStorage(int userId)42 MissionDataStorage::MissionDataStorage(int userId)
43 {
44 userId_ = userId;
45 }
46
~MissionDataStorage()47 MissionDataStorage::~MissionDataStorage()
48 {}
49
LoadAllMissionInfo(std::list<InnerMissionInfo> & missionInfoList)50 bool MissionDataStorage::LoadAllMissionInfo(std::list<InnerMissionInfo> &missionInfoList)
51 {
52 std::vector<std::string> fileNameVec;
53 std::vector<int32_t> tempMissions;
54 std::string dirPath = GetMissionDataDirPath();
55 OHOS::GetDirFiles(dirPath, fileNameVec);
56
57 for (auto fileName : fileNameVec) {
58 if (!CheckFileNameValid(fileName)) {
59 TAG_LOGE(AAFwkTag::ABILITYMGR, "load mission info: file name %{public}s invalid.", fileName.c_str());
60 continue;
61 }
62
63 std::string content;
64 bool loadFile = OHOS::LoadStringFromFile(fileName, content);
65 if (!loadFile) {
66 TAG_LOGE(AAFwkTag::ABILITYMGR, "load string from file %{public}s failed.", fileName.c_str());
67 continue;
68 }
69
70 InnerMissionInfo misssionInfo;
71 if (!misssionInfo.FromJsonStr(content)) {
72 TAG_LOGE(AAFwkTag::ABILITYMGR, "parse mission info failed. file: %{public}s", fileName.c_str());
73 continue;
74 }
75 if (misssionInfo.isTemporary) {
76 tempMissions.push_back(misssionInfo.missionInfo.id);
77 continue;
78 }
79 missionInfoList.push_back(misssionInfo);
80 }
81
82 for (auto missionId : tempMissions) {
83 DeleteMissionInfo(missionId);
84 }
85 return true;
86 }
87
SaveMissionInfo(const InnerMissionInfo & missionInfo)88 void MissionDataStorage::SaveMissionInfo(const InnerMissionInfo &missionInfo)
89 {
90 std::string filePath = GetMissionDataFilePath(missionInfo.missionInfo.id);
91 std::string dirPath = OHOS::ExtractFilePath(filePath);
92 if (!OHOS::FileExists(dirPath)) {
93 bool createDir = OHOS::ForceCreateDirectory(dirPath);
94 if (!createDir) {
95 TAG_LOGE(AAFwkTag::ABILITYMGR, "create dir %{public}s failed.", dirPath.c_str());
96 return;
97 }
98 chmod(dirPath.c_str(), MODE);
99 }
100
101 std::string jsonStr = missionInfo.ToJsonStr();
102 bool saveMissionFile = OHOS::SaveStringToFile(filePath, jsonStr, true);
103 if (!saveMissionFile) {
104 TAG_LOGE(AAFwkTag::ABILITYMGR, "save mission file %{public}s failed.", filePath.c_str());
105 }
106 }
107
DeleteMissionInfo(int missionId)108 void MissionDataStorage::DeleteMissionInfo(int missionId)
109 {
110 std::string filePath = GetMissionDataFilePath(missionId);
111 bool removeMissionFile = OHOS::RemoveFile(filePath);
112 if (!removeMissionFile) {
113 TAG_LOGE(AAFwkTag::ABILITYMGR, "remove mission file %{public}s failed.", filePath.c_str());
114 return;
115 }
116 DeleteMissionSnapshot(missionId);
117 }
118
SaveMissionSnapshot(int32_t missionId,const MissionSnapshot & missionSnapshot)119 void MissionDataStorage::SaveMissionSnapshot(int32_t missionId, const MissionSnapshot& missionSnapshot)
120 {
121 #ifdef SUPPORT_GRAPHICS
122 TAG_LOGI(AAFwkTag::ABILITYMGR, "snapshot: save snapshot from cache, missionId = %{public}d", missionId);
123 SaveCachedSnapshot(missionId, missionSnapshot);
124 SaveSnapshotFile(missionId, missionSnapshot);
125 TAG_LOGI(AAFwkTag::ABILITYMGR, "snapshot: delete snapshot from cache, missionId = %{public}d", missionId);
126 DeleteCachedSnapshot(missionId);
127 #endif
128 }
129
DeleteMissionSnapshot(int32_t missionId)130 void MissionDataStorage::DeleteMissionSnapshot(int32_t missionId)
131 {
132 #ifdef SUPPORT_GRAPHICS
133 DeleteMissionSnapshot(missionId, false);
134 DeleteMissionSnapshot(missionId, true);
135 #endif
136 }
137
GetMissionSnapshot(int32_t missionId,MissionSnapshot & missionSnapshot,bool isLowResolution)138 bool MissionDataStorage::GetMissionSnapshot(int32_t missionId, MissionSnapshot& missionSnapshot, bool isLowResolution)
139 {
140 #ifdef SUPPORT_GRAPHICS
141 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
142 if (GetCachedSnapshot(missionId, missionSnapshot)) {
143 if (isLowResolution) {
144 missionSnapshot.snapshot = GetReducedPixelMap(missionSnapshot.snapshot);
145 }
146 TAG_LOGI(AAFwkTag::ABILITYMGR, "snapshot: GetMissionSnapshot from cache, missionId = %{public}d", missionId);
147 return true;
148 }
149
150 auto pixelMap = GetPixelMap(missionId, isLowResolution);
151 if (!pixelMap) {
152 TAG_LOGE(AAFwkTag::ABILITYMGR, "%{public}s: GetPixelMap failed.", __func__);
153 return false;
154 }
155 missionSnapshot.snapshot = std::move(pixelMap);
156 #endif
157 return true;
158 }
159
GetMissionDataDirPath() const160 std::string MissionDataStorage::GetMissionDataDirPath() const
161 {
162 return std::string(TASK_DATA_FILE_BASE_PATH) + "/" + std::to_string(userId_) + "/"
163 + std::string(MISSION_DATA_FILE_PATH);
164 }
165
GetMissionDataFilePath(int missionId)166 std::string MissionDataStorage::GetMissionDataFilePath(int missionId)
167 {
168 return GetMissionDataDirPath() + "/"
169 + MISSION_JSON_FILE_PREFIX + "_" + std::to_string(missionId) + JSON_FILE_SUFFIX;
170 }
171
GetMissionSnapshotPath(int32_t missionId,bool isLowResolution) const172 std::string MissionDataStorage::GetMissionSnapshotPath(int32_t missionId, bool isLowResolution) const
173 {
174 std::string filePath = GetMissionDataDirPath() + FILE_SEPARATOR + MISSION_JSON_FILE_PREFIX +
175 UNDERLINE_SEPARATOR + std::to_string(missionId);
176 if (isLowResolution) {
177 filePath = filePath + UNDERLINE_SEPARATOR + LOW_RESOLUTION_FLAG;
178 }
179 filePath = filePath + JPEG_FILE_SUFFIX;
180 return filePath;
181 }
182
CheckFileNameValid(const std::string & fileName)183 bool MissionDataStorage::CheckFileNameValid(const std::string &fileName)
184 {
185 std::string fileNameExcludePath = OHOS::ExtractFileName(fileName);
186 if (fileNameExcludePath.find(MISSION_JSON_FILE_PREFIX) != 0) {
187 return false;
188 }
189
190 if (fileNameExcludePath.find("_") != std::string(MISSION_JSON_FILE_PREFIX).length()) {
191 return false;
192 }
193
194 if (fileNameExcludePath.find(JSON_FILE_SUFFIX) != fileNameExcludePath.length()
195 - std::string(JSON_FILE_SUFFIX).length()) {
196 return false;
197 }
198
199 size_t missionIdLength = fileNameExcludePath.find(JSON_FILE_SUFFIX) - fileNameExcludePath.find("_") - 1;
200 std::string missionId = fileNameExcludePath.substr(fileNameExcludePath.find("_") + 1, missionIdLength);
201 for (auto ch : missionId) {
202 if (!isdigit(ch)) {
203 return false;
204 }
205 }
206
207 return true;
208 }
209
210 #ifdef SUPPORT_GRAPHICS
SaveSnapshotFile(int32_t missionId,const MissionSnapshot & missionSnapshot)211 void MissionDataStorage::SaveSnapshotFile(int32_t missionId, const MissionSnapshot& missionSnapshot)
212 {
213 SaveSnapshotFile(missionId, missionSnapshot.snapshot, missionSnapshot.isPrivate, false);
214 SaveSnapshotFile(missionId, GetReducedPixelMap(missionSnapshot.snapshot), missionSnapshot.isPrivate, true);
215 DelayedSingleton<MissionInfoMgr>::GetInstance()->CompleteSaveSnapshot(missionId);
216 }
217
SaveSnapshotFile(int32_t missionId,const std::shared_ptr<OHOS::Media::PixelMap> & snapshot,bool isPrivate,bool isLowResolution)218 void MissionDataStorage::SaveSnapshotFile(int32_t missionId, const std::shared_ptr<OHOS::Media::PixelMap>& snapshot,
219 bool isPrivate, bool isLowResolution)
220 {
221 if (!snapshot) {
222 return;
223 }
224
225 std::string filePath = GetMissionSnapshotPath(missionId, isLowResolution);
226 std::string dirPath = OHOS::ExtractFilePath(filePath);
227 if (!OHOS::FileExists(dirPath)) {
228 bool createDir = OHOS::ForceCreateDirectory(dirPath);
229 if (!createDir) {
230 TAG_LOGE(AAFwkTag::ABILITYMGR, "snapshot: create dir %{public}s failed.", dirPath.c_str());
231 return;
232 }
233 chmod(dirPath.c_str(), MODE);
234 }
235
236 if (isPrivate) {
237 TAG_LOGD(AAFwkTag::ABILITYMGR, "snapshot: the param isPrivate is true.");
238 ssize_t dataLength = snapshot->GetWidth() * snapshot->GetHeight() * RGB888_PIXEL_BYTES;
239 uint8_t* data = (uint8_t*) malloc(dataLength);
240 if (data == nullptr) {
241 TAG_LOGE(AAFwkTag::ABILITYMGR, "malloc failed.");
242 return;
243 }
244 if (memset_s(data, dataLength, 0xff, dataLength) == EOK) {
245 Media::SourceOptions sourceOptions;
246 uint32_t errCode = 0;
247 auto imageSource = Media::ImageSource::CreateImageSource(data, dataLength, sourceOptions, errCode);
248 WriteToJpeg(filePath, *imageSource);
249 }
250 free(data);
251 } else {
252 WriteToJpeg(filePath, *snapshot);
253 }
254 }
255
GetReducedPixelMap(const std::shared_ptr<OHOS::Media::PixelMap> & snapshot)256 std::shared_ptr<OHOS::Media::PixelMap> MissionDataStorage::GetReducedPixelMap(
257 const std::shared_ptr<OHOS::Media::PixelMap>& snapshot)
258 {
259 if (!snapshot) {
260 return nullptr;
261 }
262
263 OHOS::Media::InitializationOptions options;
264 options.size.width = snapshot->GetWidth() / SCALE;
265 options.size.height = snapshot->GetHeight() / SCALE;
266 std::unique_ptr<OHOS::Media::PixelMap> reducedPixelMap = OHOS::Media::PixelMap::Create(*snapshot, options);
267 return std::shared_ptr<OHOS::Media::PixelMap>(reducedPixelMap.release());
268 }
269
GetCachedSnapshot(int32_t missionId,MissionSnapshot & missionSnapshot)270 bool MissionDataStorage::GetCachedSnapshot(int32_t missionId, MissionSnapshot& missionSnapshot)
271 {
272 std::lock_guard<ffrt::mutex> lock(cachedPixelMapMutex_);
273 auto pixelMap = cachedPixelMap_.find(missionId);
274 if (pixelMap != cachedPixelMap_.end()) {
275 missionSnapshot.snapshot = pixelMap->second;
276 return true;
277 }
278 return false;
279 }
280
SaveCachedSnapshot(int32_t missionId,const MissionSnapshot & missionSnapshot)281 bool MissionDataStorage::SaveCachedSnapshot(int32_t missionId, const MissionSnapshot& missionSnapshot)
282 {
283 std::lock_guard<ffrt::mutex> lock(cachedPixelMapMutex_);
284 auto result = cachedPixelMap_.insert_or_assign(missionId, missionSnapshot.snapshot);
285 if (!result.second) {
286 TAG_LOGE(AAFwkTag::ABILITYMGR, "snapshot: save snapshot cache failed, missionId = %{public}d", missionId);
287 return false;
288 }
289 return true;
290 }
291
DeleteCachedSnapshot(int32_t missionId)292 bool MissionDataStorage::DeleteCachedSnapshot(int32_t missionId)
293 {
294 std::lock_guard<ffrt::mutex> lock(cachedPixelMapMutex_);
295 auto result = cachedPixelMap_.erase(missionId);
296 if (result != 1) {
297 TAG_LOGE(AAFwkTag::ABILITYMGR, "snapshot: delete snapshot cache failed, missionId = %{public}d", missionId);
298 return false;
299 }
300 return true;
301 }
302
DeleteMissionSnapshot(int32_t missionId,bool isLowResolution)303 void MissionDataStorage::DeleteMissionSnapshot(int32_t missionId, bool isLowResolution)
304 {
305 std::string filePath = GetMissionSnapshotPath(missionId, isLowResolution);
306 if (!OHOS::FileExists(filePath)) {
307 TAG_LOGW(AAFwkTag::ABILITYMGR, "snapshot: remove snapshot file %{public}s failed, file not exists",
308 filePath.c_str());
309 return;
310 }
311 bool removeResult = OHOS::RemoveFile(filePath);
312 if (!removeResult) {
313 TAG_LOGE(AAFwkTag::ABILITYMGR, "snapshot: remove snapshot file %{public}s failed.", filePath.c_str());
314 }
315 }
316
GetSnapshot(int missionId,bool isLowResolution) const317 std::shared_ptr<Media::PixelMap> MissionDataStorage::GetSnapshot(int missionId, bool isLowResolution) const
318 {
319 auto pixelMapPtr = GetPixelMap(missionId, isLowResolution);
320 if (!pixelMapPtr) {
321 TAG_LOGE(AAFwkTag::ABILITYMGR, "%{public}s: GetPixelMap failed.", __func__);
322 return nullptr;
323 }
324 return std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
325 }
326
ReadFileToBuffer(const std::string & filePath,size_t & bufferSize) const327 std::unique_ptr<uint8_t[]> MissionDataStorage::ReadFileToBuffer(const std::string &filePath, size_t &bufferSize) const
328 {
329 struct stat statbuf;
330 int ret = stat(filePath.c_str(), &statbuf);
331 if (ret != 0) {
332 TAG_LOGE(AAFwkTag::ABILITYMGR, "GetPixelMap: get the file size failed, ret:%{public}d.", ret);
333 return nullptr;
334 }
335 bufferSize = static_cast<size_t>(statbuf.st_size);
336 std::string realPath;
337 if (!OHOS::PathToRealPath(filePath, realPath)) {
338 TAG_LOGE(AAFwkTag::ABILITYMGR, "ReadFileToBuffer:file path to real path failed, file path=%{public}s.",
339 filePath.c_str());
340 return nullptr;
341 }
342
343 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(bufferSize);
344 if (buffer == nullptr) {
345 TAG_LOGE(AAFwkTag::ABILITYMGR, "ReadFileToBuffer:buffer is nullptr");
346 return nullptr;
347 }
348
349 FILE *fp = fopen(realPath.c_str(), "rb");
350 if (fp == nullptr) {
351 TAG_LOGE(AAFwkTag::ABILITYMGR, "ReadFileToBuffer:open file failed, real path=%{public}s.", realPath.c_str());
352 return nullptr;
353 }
354 fseek(fp, 0, SEEK_END);
355 size_t fileSize = static_cast<size_t>(ftell(fp));
356 fseek(fp, 0, SEEK_SET);
357 if (bufferSize < fileSize) {
358 TAG_LOGE(AAFwkTag::ABILITYMGR,
359 "ReadFileToBuffer:buffer size:(%{public}zu) is smaller than file size:(%{public}zu).", bufferSize,
360 fileSize);
361 fclose(fp);
362 return nullptr;
363 }
364 size_t retSize = std::fread(buffer.get(), 1, fileSize, fp);
365 if (retSize != fileSize) {
366 TAG_LOGE(AAFwkTag::ABILITYMGR, "ReadFileToBuffer:read file result size = %{public}zu, size = %{public}zu.",
367 retSize, fileSize);
368 fclose(fp);
369 return nullptr;
370 }
371 fclose(fp);
372 return buffer;
373 }
374
GetPixelMap(int missionId,bool isLowResolution) const375 std::unique_ptr<Media::PixelMap> MissionDataStorage::GetPixelMap(int missionId, bool isLowResolution) const
376 {
377 std::string filePath = GetMissionSnapshotPath(missionId, isLowResolution);
378 if (!OHOS::FileExists(filePath)) {
379 TAG_LOGI(AAFwkTag::ABILITYMGR, "snapshot: storage snapshot not exists, missionId = %{public}d", missionId);
380 return nullptr;
381 }
382 uint32_t errCode = 0;
383
384 size_t bufferSize = 0;
385 const std::string fileName = filePath;
386 std::unique_ptr<uint8_t[]> buffer = MissionDataStorage::ReadFileToBuffer(fileName, bufferSize);
387 if (buffer == nullptr) {
388 TAG_LOGE(AAFwkTag::ABILITYMGR, "GetPixelMap: get buffer error buffer == nullptr");
389 return nullptr;
390 }
391 Media::SourceOptions sourceOptions;
392 auto imageSource = Media::ImageSource::CreateImageSource(buffer.get(), bufferSize, sourceOptions, errCode);
393 if (errCode != OHOS::Media::SUCCESS || imageSource == nullptr) {
394 TAG_LOGE(AAFwkTag::ABILITYMGR, "snapshot: CreateImageSource failed, nullptr or errCode = %{public}d", errCode);
395 return nullptr;
396 }
397 Media::DecodeOptions decodeOptions;
398 decodeOptions.allocatorType = Media::AllocatorType::SHARE_MEM_ALLOC;
399 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOptions, errCode);
400 if (errCode != OHOS::Media::SUCCESS) {
401 TAG_LOGE(AAFwkTag::ABILITYMGR, "snapshot: CreatePixelMap failed, errCode = %{public}d", errCode);
402 return nullptr;
403 }
404 return pixelMapPtr;
405 }
406
407 template<typename T>
WriteToJpeg(const std::string & filePath,T & snapshot) const408 void MissionDataStorage::WriteToJpeg(const std::string &filePath, T &snapshot) const
409 {
410 TAG_LOGI(AAFwkTag::ABILITYMGR, "file:%{public}s", filePath.c_str());
411 OHOS::Media::PackOption option;
412 option.format = IMAGE_FORMAT;
413 option.quality = IMAGE_QUALITY;
414 Media::ImagePacker imagePacker;
415 uint32_t err = imagePacker.StartPacking(filePath, option);
416 if (err != ERR_OK) {
417 TAG_LOGE(AAFwkTag::ABILITYMGR, "Failed to StartPacking %{public}d.", err);
418 return;
419 }
420 err = imagePacker.AddImage(snapshot);
421 if (err != ERR_OK) {
422 TAG_LOGE(AAFwkTag::ABILITYMGR, "Failed to AddImage %{public}d.", err);
423 return;
424 }
425 int64_t packedSize = 0;
426 imagePacker.FinalizePacking(packedSize);
427 }
428 #endif
429 } // namespace AAFwk
430 } // namespace OHOS
431