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