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