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