1 /*
2 * Copyright (c) 2022 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 "bundle_state_storage.h"
17
18 #include <fstream>
19 #include <sys/stat.h>
20 #include <unistd.h>
21
22 #include "app_log_wrapper.h"
23 #include "bundle_constants.h"
24 #include "bundle_util.h"
25 #include "installd_client.h"
26 #include "string_ex.h"
27
28 namespace OHOS {
29 namespace AppExecFwk {
30 namespace {
31 const std::string::size_type EXPECT_SPLIT_SIZE = 2;
32
NameAndUserIdToKey(const std::string & bundleName,int32_t userId,std::string & key)33 void NameAndUserIdToKey(
34 const std::string &bundleName, int32_t userId, std::string &key)
35 {
36 key.append(bundleName);
37 key.append(Constants::FILE_UNDERLINE);
38 key.append(std::to_string(userId));
39 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
40 }
41
KeyToNameAndUserId(const std::string & key,std::string & bundleName,int32_t & userId)42 bool KeyToNameAndUserId(
43 const std::string &key, std::string &bundleName, int32_t &userId)
44 {
45 bool ret = false;
46 std::vector<std::string> splitStrs;
47 OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs);
48 if (splitStrs.size() == EXPECT_SPLIT_SIZE) {
49 bundleName = splitStrs[0];
50 userId = atoi(splitStrs[1].c_str());
51 ret = true;
52 }
53
54 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
55 return ret;
56 }
57 }
58
HasBundleUserInfoJsonDb()59 bool BundleStateStorage::HasBundleUserInfoJsonDb()
60 {
61 APP_LOGD("HasBundleUserInfoJsonDb start");
62 if (BundleUtil::IsExistFile(Constants::BUNDLE_USER_INFO_PATH)) {
63 APP_LOGD("Json db exist");
64 return true;
65 }
66
67 APP_LOGD("Json db not exist, and create it");
68 bool isDirExist = BundleUtil::IsExistDir(Constants::BUNDLE_MANAGER_SERVICE_PATH);
69 if (!isDirExist) {
70 mode_t mode = S_IRWXU | S_IXGRP | S_IXOTH;
71 ErrCode result = InstalldClient::GetInstance()->Mkdir(
72 Constants::BUNDLE_MANAGER_SERVICE_PATH, mode, getuid(), getgid());
73 if (result != ERR_OK) {
74 APP_LOGE("fail to create dir, error is %{public}d", result);
75 return false;
76 }
77 }
78
79 auto file = fopen(Constants::BUNDLE_USER_INFO_PATH, "at++");
80 if (file == nullptr) {
81 APP_LOGE("create json db failed");
82 return false;
83 }
84
85 auto ret = fclose(file);
86 if (ret != 0) {
87 APP_LOGE("ret: %{public}d", ret);
88 }
89
90 return false;
91 }
92
LoadAllBundleStateData(std::map<std::string,std::map<int32_t,BundleUserInfo>> & infos)93 bool BundleStateStorage::LoadAllBundleStateData(
94 std::map<std::string, std::map<int32_t, BundleUserInfo>> &infos)
95 {
96 APP_LOGD("load all bundle state data to map");
97 std::lock_guard<std::mutex> lock(bundleStateMutex_);
98 std::fstream i(Constants::BUNDLE_USER_INFO_PATH);
99 nlohmann::json jParse;
100 if (!i.is_open()) {
101 APP_LOGE("failed to open bundle database file");
102 return false;
103 }
104
105 APP_LOGD("Open bundle state db file success");
106 i.seekg(0, std::ios::end);
107 int len = static_cast<int>(i.tellg());
108 if (len <= 0) {
109 APP_LOGD("Tellg failed.");
110 i.close();
111 return false;
112 }
113
114 i.seekg(0, std::ios::beg);
115 jParse = nlohmann::json::parse(i, nullptr, false);
116 i.close();
117 return LoadAllBundleStateDataFromJson(jParse, infos);
118 }
119
LoadAllBundleStateDataFromJson(nlohmann::json & jParse,std::map<std::string,std::map<int32_t,BundleUserInfo>> & infos)120 bool BundleStateStorage::LoadAllBundleStateDataFromJson(
121 nlohmann::json &jParse, std::map<std::string, std::map<int32_t, BundleUserInfo>> &infos)
122 {
123 if (jParse.is_discarded()) {
124 APP_LOGE("Bad json due to jParse is discarded");
125 return false;
126 }
127
128 for (auto &item : jParse.items()) {
129 std::string bundleName;
130 int32_t userId;
131 if (!KeyToNameAndUserId(item.key(), bundleName, userId)) {
132 continue;
133 }
134
135 BundleUserInfo bundleUserInfo;
136 nlohmann::json& jsonObject = item.value();
137 if (jsonObject.is_discarded()) {
138 APP_LOGE("Load failed due to data is discarded");
139 continue;
140 }
141
142 bundleUserInfo = jsonObject.get<BundleUserInfo>();
143 if (infos.find(bundleName) == infos.end()) {
144 std::map<int32_t, BundleUserInfo> tempUser;
145 tempUser.try_emplace(userId, bundleUserInfo);
146 infos.try_emplace(bundleName, tempUser);
147 continue;
148 }
149
150 auto& bundleUserInfoMaps = infos.at(bundleName);
151 if (bundleUserInfoMaps.find(userId) == bundleUserInfoMaps.end()) {
152 bundleUserInfoMaps.try_emplace(userId, bundleUserInfo);
153 continue;
154 }
155
156 bundleUserInfoMaps.at(userId) = bundleUserInfo;
157 }
158
159 return !infos.empty();
160 }
161
SaveBundleStateStorage(const std::string bundleName,int32_t userId,const BundleUserInfo & bundleUserInfo)162 bool BundleStateStorage::SaveBundleStateStorage(
163 const std::string bundleName, int32_t userId, const BundleUserInfo &bundleUserInfo)
164 {
165 APP_LOGD("Save bundle state to json db");
166 if (bundleName.empty() || userId < 0) {
167 APP_LOGE("Save bundle state failed due to param invalid.");
168 return false;
169 }
170
171 std::lock_guard<std::mutex> lock(bundleStateMutex_);
172 std::string appName;
173 NameAndUserIdToKey(bundleName, userId, appName);
174 std::fstream f(Constants::BUNDLE_USER_INFO_PATH);
175 if (!f.is_open()) {
176 APP_LOGE("failed to open bundle database file");
177 return false;
178 }
179
180 f.seekg(0, std::ios::end);
181 int len = static_cast<int>(f.tellg());
182 if (len == 0) {
183 nlohmann::json appRoot;
184 appRoot[appName] = bundleUserInfo;
185 f << std::setw(Constants::DUMP_INDENT) << appRoot << std::endl;
186 } else {
187 f.seekg(0, std::ios::beg);
188 nlohmann::json jsonFile;
189 f >> jsonFile;
190 jsonFile[appName] = bundleUserInfo;
191 f.seekp(0, std::ios::beg);
192 f << std::setw(Constants::DUMP_INDENT) << jsonFile << std::endl;
193 }
194
195 f.close();
196 return true;
197 }
198
GetBundleStateStorage(const std::string bundleName,int32_t userId,BundleUserInfo & bundleUserInfo)199 bool BundleStateStorage::GetBundleStateStorage(
200 const std::string bundleName, int32_t userId, BundleUserInfo &bundleUserInfo)
201 {
202 if (bundleName.empty() || userId < 0) {
203 APP_LOGE("Get bundle state data failed due to param invalid.");
204 return false;
205 }
206
207 std::lock_guard<std::mutex> lock(bundleStateMutex_);
208 std::string appName;
209 NameAndUserIdToKey(bundleName, userId, appName);
210 std::fstream f(Constants::BUNDLE_USER_INFO_PATH);
211 if (!f.is_open()) {
212 APP_LOGE("failed to open bundle database file");
213 return false;
214 }
215
216 f.seekg(0, std::ios::end);
217 int len = static_cast<int>(f.tellg());
218 if (len == 0) {
219 f.close();
220 APP_LOGE("failed to open bundle database file due to tellg invalid");
221 return false;
222 }
223
224 f.seekg(0, std::ios::beg);
225 nlohmann::json jsonFile;
226 f >> jsonFile;
227 if (jsonFile.is_discarded()) {
228 f.close();
229 APP_LOGE("Get failed due to data is discarded");
230 return false;
231 }
232
233 bundleUserInfo = jsonFile.get<BundleUserInfo>();
234 f.close();
235 return true;
236 }
237
DeleteBundleState(const std::string bundleName,int32_t userId)238 bool BundleStateStorage::DeleteBundleState(
239 const std::string bundleName, int32_t userId)
240 {
241 APP_LOGD("Delete bundle state data");
242 if (bundleName.empty() || userId < 0) {
243 APP_LOGE("Delete bundle state data failed due to param invalid.");
244 return false;
245 }
246
247 std::lock_guard<std::mutex> lock(bundleStateMutex_);
248 bool isEmpty = false;
249 std::string appName;
250 NameAndUserIdToKey(bundleName, userId, appName);
251 std::ifstream i(Constants::BUNDLE_USER_INFO_PATH);
252 nlohmann::json jParse;
253 if (!i.is_open()) {
254 APP_LOGE("failed to open bundle database file");
255 return false;
256 }
257
258 i.seekg(0, std::ios::end);
259 int len = static_cast<int>(i.tellg());
260 if (len == 0) {
261 i.close();
262 APP_LOGE("file is empty appName = %{private}s", appName.c_str());
263 return true;
264 }
265
266 i.seekg(0, std::ios::beg);
267 i >> jParse;
268 if (jParse.find(appName) == jParse.end()) {
269 i.close();
270 APP_LOGD("not find appName = %{public}s", appName.c_str());
271 return true;
272 }
273
274 jParse.erase(appName);
275 isEmpty = (jParse.size() == 0) ? true : false;
276 i.close();
277 std::ofstream o(Constants::BUNDLE_USER_INFO_PATH);
278 if (!o.is_open()) {
279 APP_LOGE("failed to open bundle database file");
280 return false;
281 }
282
283 if (!isEmpty) {
284 o << std::setw(Constants::DUMP_INDENT) << jParse;
285 }
286
287 o.close();
288 return true;
289 }
290 } // namespace AppExecFwk
291 } // namespace OHOS
292