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, "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 %{public}s fail", fileName.c_str());
67 continue;
68 }
69
70 InnerMissionInfo misssionInfo;
71 if (!misssionInfo.FromJsonStr(content)) {
72 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail. 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 fail", dirPath.c_str());
96 return;
97 }
98 #ifdef SUPPORT_GRAPHICS
99 chmod(dirPath.c_str(), MODE);
100 #endif // SUPPORT_GRAPHICS
101 }
102
103 std::string jsonStr = missionInfo.ToJsonStr();
104 bool saveMissionFile = OHOS::SaveStringToFile(filePath, jsonStr, true);
105 if (!saveMissionFile) {
106 TAG_LOGE(AAFwkTag::ABILITYMGR, "save %{public}s fail", filePath.c_str());
107 }
108 }
109
DeleteMissionInfo(int missionId)110 void MissionDataStorage::DeleteMissionInfo(int missionId)
111 {
112 std::string filePath = GetMissionDataFilePath(missionId);
113 bool removeMissionFile = OHOS::RemoveFile(filePath);
114 if (!removeMissionFile) {
115 TAG_LOGE(AAFwkTag::ABILITYMGR, "remove %{public}s fail", filePath.c_str());
116 return;
117 }
118 DeleteMissionSnapshot(missionId);
119 }
120
SaveMissionSnapshot(int32_t missionId, const MissionSnapshot& missionSnapshot)121 void MissionDataStorage::SaveMissionSnapshot(int32_t missionId, const MissionSnapshot& missionSnapshot)
122 {
123 #ifdef SUPPORT_SCREEN
124 TAG_LOGI(AAFwkTag::ABILITYMGR, "save snapshot from cache, missionId = %{public}d", missionId);
125 SaveCachedSnapshot(missionId, missionSnapshot);
126 SaveSnapshotFile(missionId, missionSnapshot);
127 TAG_LOGI(AAFwkTag::ABILITYMGR, "delete snapshot from cache, missionId = %{public}d", missionId);
128 DeleteCachedSnapshot(missionId);
129 #endif
130 }
131
DeleteMissionSnapshot(int32_t missionId)132 void MissionDataStorage::DeleteMissionSnapshot(int32_t missionId)
133 {
134 #ifdef SUPPORT_SCREEN
135 DeleteMissionSnapshot(missionId, false);
136 DeleteMissionSnapshot(missionId, true);
137 #endif
138 }
139
GetMissionSnapshot(int32_t missionId, MissionSnapshot& missionSnapshot, bool isLowResolution)140 bool MissionDataStorage::GetMissionSnapshot(int32_t missionId, MissionSnapshot& missionSnapshot, bool isLowResolution)
141 {
142 #ifdef SUPPORT_SCREEN
143 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
144 if (GetCachedSnapshot(missionId, missionSnapshot)) {
145 if (isLowResolution) {
146 missionSnapshot.snapshot = GetReducedPixelMap(missionSnapshot.snapshot);
147 }
148 TAG_LOGI(AAFwkTag::ABILITYMGR, "GetMissionSnapshot from cache, missionId = %{public}d", missionId);
149 return true;
150 }
151
152 auto pixelMap = GetPixelMap(missionId, isLowResolution);
153 if (!pixelMap) {
154 TAG_LOGE(AAFwkTag::ABILITYMGR, "%{public}s: GetPixelMap fail", __func__);
155 return false;
156 }
157 missionSnapshot.snapshot = std::move(pixelMap);
158 #endif
159 return true;
160 }
161
GetMissionDataDirPath() const162 std::string MissionDataStorage::GetMissionDataDirPath() const
163 {
164 return std::string(TASK_DATA_FILE_BASE_PATH) + "/" + std::to_string(userId_) + "/"
165 + std::string(MISSION_DATA_FILE_PATH);
166 }
167
GetMissionDataFilePath(int missionId)168 std::string MissionDataStorage::GetMissionDataFilePath(int missionId)
169 {
170 return GetMissionDataDirPath() + "/"
171 + MISSION_JSON_FILE_PREFIX + "_" + std::to_string(missionId) + JSON_FILE_SUFFIX;
172 }
173
GetMissionSnapshotPath(int32_t missionId, bool isLowResolution) const174 std::string MissionDataStorage::GetMissionSnapshotPath(int32_t missionId, bool isLowResolution) const
175 {
176 std::string filePath = GetMissionDataDirPath() + FILE_SEPARATOR + MISSION_JSON_FILE_PREFIX +
177 UNDERLINE_SEPARATOR + std::to_string(missionId);
178 if (isLowResolution) {
179 filePath = filePath + UNDERLINE_SEPARATOR + LOW_RESOLUTION_FLAG;
180 }
181 filePath = filePath + JPEG_FILE_SUFFIX;
182 return filePath;
183 }
184
CheckFileNameValid(const std::string &fileName)185 bool MissionDataStorage::CheckFileNameValid(const std::string &fileName)
186 {
187 std::string fileNameExcludePath = OHOS::ExtractFileName(fileName);
188 if (fileNameExcludePath.find(MISSION_JSON_FILE_PREFIX) != 0) {
189 return false;
190 }
191
192 if (fileNameExcludePath.find("_") != std::string(MISSION_JSON_FILE_PREFIX).length()) {
193 return false;
194 }
195
196 if (fileNameExcludePath.find(JSON_FILE_SUFFIX) != fileNameExcludePath.length()
197 - std::string(JSON_FILE_SUFFIX).length()) {
198 return false;
199 }
200
201 size_t missionIdLength = fileNameExcludePath.find(JSON_FILE_SUFFIX) - fileNameExcludePath.find("_") - 1;
202 std::string missionId = fileNameExcludePath.substr(fileNameExcludePath.find("_") + 1, missionIdLength);
203 for (auto ch : missionId) {
204 if (!isdigit(ch)) {
205 return false;
206 }
207 }
208
209 return true;
210 }
211
212 #ifdef SUPPORT_SCREEN
SaveSnapshotFile(int32_t missionId, const MissionSnapshot& missionSnapshot)213 void MissionDataStorage::SaveSnapshotFile(int32_t missionId, const MissionSnapshot& missionSnapshot)
214 {
215 SaveSnapshotFile(missionId, missionSnapshot.snapshot, missionSnapshot.isPrivate, false);
216 SaveSnapshotFile(missionId, GetReducedPixelMap(missionSnapshot.snapshot), missionSnapshot.isPrivate, true);
217 DelayedSingleton<MissionInfoMgr>::GetInstance()->CompleteSaveSnapshot(missionId);
218 }
219
SaveSnapshotFile(int32_t missionId, const std::shared_ptr<OHOS::Media::PixelMap>& snapshot, bool isPrivate, bool isLowResolution)220 void MissionDataStorage::SaveSnapshotFile(int32_t missionId, const std::shared_ptr<OHOS::Media::PixelMap>& snapshot,
221 bool isPrivate, bool isLowResolution)
222 {
223 if (!snapshot) {
224 return;
225 }
226
227 std::string filePath = GetMissionSnapshotPath(missionId, isLowResolution);
228 std::string dirPath = OHOS::ExtractFilePath(filePath);
229 if (!OHOS::FileExists(dirPath)) {
230 bool createDir = OHOS::ForceCreateDirectory(dirPath);
231 if (!createDir) {
232 TAG_LOGE(AAFwkTag::ABILITYMGR, "create dir %{public}s fail", dirPath.c_str());
233 return;
234 }
235 chmod(dirPath.c_str(), MODE);
236 }
237
238 if (isPrivate) {
239 TAG_LOGD(AAFwkTag::ABILITYMGR, "snapshot: the param isPrivate is true.");
240 ssize_t dataLength = snapshot->GetWidth() * snapshot->GetHeight() * RGB888_PIXEL_BYTES;
241 uint8_t* data = (uint8_t*) malloc(dataLength);
242 if (data == nullptr) {
243 TAG_LOGE(AAFwkTag::ABILITYMGR, "malloc fail");
244 return;
245 }
246 if (memset_s(data, dataLength, 0xff, dataLength) == EOK) {
247 Media::SourceOptions sourceOptions;
248 uint32_t errCode = 0;
249 auto imageSource = Media::ImageSource::CreateImageSource(data, dataLength, sourceOptions, errCode);
250 WriteToJpeg(filePath, *imageSource);
251 }
252 free(data);
253 } else {
254 WriteToJpeg(filePath, *snapshot);
255 }
256 }
257
GetReducedPixelMap( const std::shared_ptr<OHOS::Media::PixelMap>& snapshot)258 std::shared_ptr<OHOS::Media::PixelMap> MissionDataStorage::GetReducedPixelMap(
259 const std::shared_ptr<OHOS::Media::PixelMap>& snapshot)
260 {
261 if (!snapshot) {
262 return nullptr;
263 }
264
265 OHOS::Media::InitializationOptions options;
266 options.size.width = snapshot->GetWidth() / SCALE;
267 options.size.height = snapshot->GetHeight() / SCALE;
268 std::unique_ptr<OHOS::Media::PixelMap> reducedPixelMap = OHOS::Media::PixelMap::Create(*snapshot, options);
269 return std::shared_ptr<OHOS::Media::PixelMap>(reducedPixelMap.release());
270 }
271
GetCachedSnapshot(int32_t missionId, MissionSnapshot& missionSnapshot)272 bool MissionDataStorage::GetCachedSnapshot(int32_t missionId, MissionSnapshot& missionSnapshot)
273 {
274 std::lock_guard<ffrt::mutex> lock(cachedPixelMapMutex_);
275 auto pixelMap = cachedPixelMap_.find(missionId);
276 if (pixelMap != cachedPixelMap_.end()) {
277 missionSnapshot.snapshot = pixelMap->second;
278 return true;
279 }
280 return false;
281 }
282
SaveCachedSnapshot(int32_t missionId, const MissionSnapshot& missionSnapshot)283 bool MissionDataStorage::SaveCachedSnapshot(int32_t missionId, const MissionSnapshot& missionSnapshot)
284 {
285 std::lock_guard<ffrt::mutex> lock(cachedPixelMapMutex_);
286 auto result = cachedPixelMap_.insert_or_assign(missionId, missionSnapshot.snapshot);
287 if (!result.second) {
288 TAG_LOGE(AAFwkTag::ABILITYMGR, "save fail, missionId = %{public}d", missionId);
289 return false;
290 }
291 return true;
292 }
293
DeleteCachedSnapshot(int32_t missionId)294 bool MissionDataStorage::DeleteCachedSnapshot(int32_t missionId)
295 {
296 std::lock_guard<ffrt::mutex> lock(cachedPixelMapMutex_);
297 auto result = cachedPixelMap_.erase(missionId);
298 if (result != 1) {
299 TAG_LOGE(AAFwkTag::ABILITYMGR, "delete fail, missionId = %{public}d", missionId);
300 return false;
301 }
302 return true;
303 }
304
DeleteMissionSnapshot(int32_t missionId, bool isLowResolution)305 void MissionDataStorage::DeleteMissionSnapshot(int32_t missionId, bool isLowResolution)
306 {
307 std::string filePath = GetMissionSnapshotPath(missionId, isLowResolution);
308 if (!OHOS::FileExists(filePath)) {
309 TAG_LOGW(AAFwkTag::ABILITYMGR, "fail, file: %{public}s",
310 filePath.c_str());
311 return;
312 }
313 bool removeResult = OHOS::RemoveFile(filePath);
314 if (!removeResult) {
315 TAG_LOGE(AAFwkTag::ABILITYMGR, "remove %{public}s fail", filePath.c_str());
316 }
317 }
318
GetSnapshot(int missionId, bool isLowResolution) const319 std::shared_ptr<Media::PixelMap> MissionDataStorage::GetSnapshot(int missionId, bool isLowResolution) const
320 {
321 auto pixelMapPtr = GetPixelMap(missionId, isLowResolution);
322 if (!pixelMapPtr) {
323 TAG_LOGE(AAFwkTag::ABILITYMGR, "%{public}s: GetPixelMap fail", __func__);
324 return nullptr;
325 }
326 return std::shared_ptr<Media::PixelMap>(pixelMapPtr.release());
327 }
328
ReadFileToBuffer(const std::string &filePath, size_t &bufferSize) const329 std::unique_ptr<uint8_t[]> MissionDataStorage::ReadFileToBuffer(const std::string &filePath, size_t &bufferSize) const
330 {
331 struct stat statbuf;
332 int ret = stat(filePath.c_str(), &statbuf);
333 if (ret != 0) {
334 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail, ret:%{public}d", ret);
335 return nullptr;
336 }
337 bufferSize = static_cast<size_t>(statbuf.st_size);
338 std::string realPath;
339 if (!OHOS::PathToRealPath(filePath, realPath)) {
340 TAG_LOGE(AAFwkTag::ABILITYMGR, "PathToRealPath fail, file path=%{public}s",
341 filePath.c_str());
342 return nullptr;
343 }
344
345 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(bufferSize);
346 if (buffer == nullptr) {
347 TAG_LOGE(AAFwkTag::ABILITYMGR, "buffer null");
348 return nullptr;
349 }
350
351 FILE *fp = fopen(realPath.c_str(), "rb");
352 if (fp == nullptr) {
353 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail, real path=%{public}s", realPath.c_str());
354 return nullptr;
355 }
356 fseek(fp, 0, SEEK_END);
357 size_t fileSize = static_cast<size_t>(ftell(fp));
358 fseek(fp, 0, SEEK_SET);
359 if (bufferSize < fileSize) {
360 TAG_LOGE(AAFwkTag::ABILITYMGR,
361 "buffer size:(%{public}zu) is smaller than file size:(%{public}zu)", bufferSize,
362 fileSize);
363 fclose(fp);
364 return nullptr;
365 }
366 size_t retSize = std::fread(buffer.get(), 1, fileSize, fp);
367 if (retSize != fileSize) {
368 TAG_LOGE(AAFwkTag::ABILITYMGR, "read file result size = %{public}zu, size = %{public}zu",
369 retSize, fileSize);
370 fclose(fp);
371 return nullptr;
372 }
373 fclose(fp);
374 return buffer;
375 }
376
GetPixelMap(int missionId, bool isLowResolution) const377 std::unique_ptr<Media::PixelMap> MissionDataStorage::GetPixelMap(int missionId, bool isLowResolution) const
378 {
379 std::string filePath = GetMissionSnapshotPath(missionId, isLowResolution);
380 if (!OHOS::FileExists(filePath)) {
381 TAG_LOGI(AAFwkTag::ABILITYMGR, "storage snapshot not exists, missionId = %{public}d", missionId);
382 return nullptr;
383 }
384 uint32_t errCode = 0;
385
386 size_t bufferSize = 0;
387 const std::string fileName = filePath;
388 std::unique_ptr<uint8_t[]> buffer = MissionDataStorage::ReadFileToBuffer(fileName, bufferSize);
389 if (buffer == nullptr) {
390 TAG_LOGE(AAFwkTag::ABILITYMGR, "buffer null");
391 return nullptr;
392 }
393 Media::SourceOptions sourceOptions;
394 auto imageSource = Media::ImageSource::CreateImageSource(buffer.get(), bufferSize, sourceOptions, errCode);
395 if (errCode != OHOS::Media::SUCCESS || imageSource == nullptr) {
396 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail, null or errCode = %{public}d", errCode);
397 return nullptr;
398 }
399 Media::DecodeOptions decodeOptions;
400 decodeOptions.allocatorType = Media::AllocatorType::SHARE_MEM_ALLOC;
401 auto pixelMapPtr = imageSource->CreatePixelMap(decodeOptions, errCode);
402 if (errCode != OHOS::Media::SUCCESS) {
403 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail, errCode = %{public}d", errCode);
404 return nullptr;
405 }
406 return pixelMapPtr;
407 }
408
409 template<typename T>
WriteToJpeg(const std::string &filePath, T &snapshot) const410 void MissionDataStorage::WriteToJpeg(const std::string &filePath, T &snapshot) const
411 {
412 TAG_LOGI(AAFwkTag::ABILITYMGR, "file:%{public}s", filePath.c_str());
413 OHOS::Media::PackOption option;
414 option.format = IMAGE_FORMAT;
415 option.quality = IMAGE_QUALITY;
416 Media::ImagePacker imagePacker;
417 uint32_t err = imagePacker.StartPacking(filePath, option);
418 if (err != ERR_OK) {
419 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail. %{public}d", err);
420 return;
421 }
422 err = imagePacker.AddImage(snapshot);
423 if (err != ERR_OK) {
424 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail. %{public}d", err);
425 return;
426 }
427 int64_t packedSize = 0;
428 imagePacker.FinalizePacking(packedSize);
429 }
430 #endif
431 } // namespace AAFwk
432 } // namespace OHOS
433