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