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 (!GetBundleStateJson(jParse) || jParse.is_discarded()) {
103 APP_LOGE("GetBundleStateJson failed or jParse is discarded");
104 return false;
105 }
106
107 return LoadAllBundleStateDataFromJson(jParse, infos);
108 }
109
LoadAllBundleStateDataFromJson(nlohmann::json & jParse,std::map<std::string,std::map<int32_t,BundleUserInfo>> & infos)110 bool BundleStateStorage::LoadAllBundleStateDataFromJson(
111 nlohmann::json &jParse, std::map<std::string, std::map<int32_t, BundleUserInfo>> &infos)
112 {
113 if (jParse.is_discarded()) {
114 APP_LOGE("Bad json due to jParse is discarded");
115 return false;
116 }
117
118 for (auto &item : jParse.items()) {
119 std::string bundleName;
120 int32_t userId;
121 if (!KeyToNameAndUserId(item.key(), bundleName, userId)) {
122 continue;
123 }
124
125 BundleUserInfo bundleUserInfo;
126 nlohmann::json& jsonObject = item.value();
127 if (jsonObject.is_discarded()) {
128 APP_LOGE("Load failed due to data is discarded");
129 continue;
130 }
131
132 bundleUserInfo = jsonObject.get<BundleUserInfo>();
133 if (infos.find(bundleName) == infos.end()) {
134 std::map<int32_t, BundleUserInfo> tempUser;
135 tempUser.try_emplace(userId, bundleUserInfo);
136 infos.try_emplace(bundleName, tempUser);
137 continue;
138 }
139
140 auto& bundleUserInfoMaps = infos.at(bundleName);
141 if (bundleUserInfoMaps.find(userId) == bundleUserInfoMaps.end()) {
142 bundleUserInfoMaps.try_emplace(userId, bundleUserInfo);
143 continue;
144 }
145
146 bundleUserInfoMaps.at(userId) = bundleUserInfo;
147 }
148
149 return !infos.empty();
150 }
151
SaveBundleStateStorage(const std::string bundleName,int32_t userId,const BundleUserInfo & bundleUserInfo)152 bool BundleStateStorage::SaveBundleStateStorage(
153 const std::string bundleName, int32_t userId, const BundleUserInfo &bundleUserInfo)
154 {
155 APP_LOGD("Save bundle state to json db");
156 if (bundleName.empty() || userId < 0) {
157 APP_LOGE("Save bundle state failed due to param invalid.");
158 return false;
159 }
160
161 std::lock_guard<std::mutex> lock(bundleStateMutex_);
162 std::string appName;
163 NameAndUserIdToKey(bundleName, userId, appName);
164 nlohmann::json rootJson;
165 nlohmann::json jParse;
166 if (GetBundleStateJson(jParse) && !jParse.is_discarded()) {
167 rootJson = jParse;
168 } else {
169 APP_LOGW("GetBundleStateJson failed or jParse is discarded, overwrite old data");
170 }
171
172 rootJson[appName] = bundleUserInfo;
173 bool isEmpty = (rootJson.size() == 0) ? true : false;
174 std::ofstream o(BUNDLE_USER_INFO_PATH, std::ios::out | std::ios::trunc);
175 if (!o.is_open()) {
176 APP_LOGE("failed to open bundle state file");
177 return false;
178 }
179 if (!isEmpty) {
180 o << std::setw(Constants::DUMP_INDENT) << rootJson;
181 }
182 o.close();
183 return true;
184 }
185
GetBundleStateStorage(const std::string bundleName,int32_t userId,BundleUserInfo & bundleUserInfo)186 bool BundleStateStorage::GetBundleStateStorage(
187 const std::string bundleName, int32_t userId, BundleUserInfo &bundleUserInfo)
188 {
189 if (bundleName.empty() || userId < 0) {
190 APP_LOGE("Get bundle state data failed due to param invalid.");
191 return false;
192 }
193
194 std::lock_guard<std::mutex> lock(bundleStateMutex_);
195 std::string appName;
196 NameAndUserIdToKey(bundleName, userId, appName);
197 nlohmann::json jParse;
198 if (!GetBundleStateJson(jParse) || jParse.is_discarded()) {
199 APP_LOGE("GetBundleStateJson failed or jParse is discarded");
200 return false;
201 }
202
203 if (jParse.find(appName) == jParse.end()) {
204 APP_LOGE("not find appName = %{public}s", appName.c_str());
205 return false;
206 }
207
208 bundleUserInfo = jParse.at(appName).get<BundleUserInfo>();
209 return true;
210 }
211
DeleteBundleState(const std::string bundleName,int32_t userId)212 bool BundleStateStorage::DeleteBundleState(
213 const std::string bundleName, int32_t userId)
214 {
215 APP_LOGD("Delete bundle state data");
216 if (bundleName.empty() || userId < 0) {
217 APP_LOGE("Delete bundle state data failed due to param invalid.");
218 return false;
219 }
220 std::lock_guard<std::mutex> lock(bundleStateMutex_);
221 std::string appName;
222 NameAndUserIdToKey(bundleName, userId, appName);
223 nlohmann::json jParse;
224 if (!GetBundleStateJson(jParse) || jParse.is_discarded()) {
225 APP_LOGE("GetBundleStateJson failed or jParse is discarded");
226 return false;
227 }
228
229 if (jParse.find(appName) == jParse.end()) {
230 APP_LOGD("not find appName = %{public}s", appName.c_str());
231 return true;
232 }
233 jParse.erase(appName);
234 bool isEmpty = (jParse.size() == 0) ? true : false;
235 std::ofstream o(BUNDLE_USER_INFO_PATH, std::ios::out | std::ios::trunc);
236 if (!o.is_open()) {
237 APP_LOGE("failed to open bundle state file");
238 return false;
239 }
240 if (!isEmpty) {
241 o << std::setw(Constants::DUMP_INDENT) << jParse;
242 }
243 o.close();
244 return true;
245 }
246
GetBundleStateJson(nlohmann::json & jParse)247 bool BundleStateStorage::GetBundleStateJson(nlohmann::json &jParse)
248 {
249 std::ifstream i(BUNDLE_USER_INFO_PATH);
250 if (!i.is_open()) {
251 APP_LOGE("failed to open bundle state file");
252 return false;
253 }
254 i.seekg(0, std::ios::end);
255 int len = static_cast<int>(i.tellg());
256 if (len == 0) {
257 i.close();
258 APP_LOGE("bundle state file is empty");
259 return true;
260 }
261 i.seekg(0, std::ios::beg);
262 jParse = nlohmann::json::parse(i, nullptr, false);
263 if (jParse.is_discarded()) {
264 i.close();
265 APP_LOGE("Get failed due to data is discarded");
266 return false;
267 }
268 i.close();
269 return true;
270 }
271 } // namespace AppExecFwk
272 } // namespace OHOS
273