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 "distributed_data_storage.h"
17
18 #include <unistd.h>
19
20 #include "account_manager_helper.h"
21 #include "app_log_wrapper.h"
22 #include "distributed_bms.h"
23 #include "parameter.h"
24
25 using namespace OHOS::DistributedKv;
26
27 namespace OHOS {
28 namespace AppExecFwk {
29 namespace {
30 const std::string BMS_KV_BASE_DIR = "/data/service/el1/public/database/";
31 const int32_t EL1 = 1;
32 const int32_t MAX_TIMES = 600; // 1min
33 const int32_t SLEEP_INTERVAL = 100 * 1000; // 100ms
34 const int32_t FLAGS = BundleFlag::GET_BUNDLE_WITH_ABILITIES |
35 ApplicationFlag::GET_APPLICATION_INFO_WITH_DISABLE |
36 AbilityInfoFlag::GET_ABILITY_INFO_WITH_DISABLE;
37 const uint32_t DEVICE_UDID_LENGTH = 65;
38 } // namespace
39
40 std::shared_ptr<DistributedDataStorage> DistributedDataStorage::instance_ = nullptr;
41 std::recursive_mutex DistributedDataStorage::mutex_;
42
GetInstance()43 std::shared_ptr<DistributedDataStorage> DistributedDataStorage::GetInstance()
44 {
45 if (instance_ == nullptr) {
46 std::lock_guard<std::recursive_mutex> lock_l(mutex_);
47 if (instance_ == nullptr) {
48 instance_ = std::make_shared<DistributedDataStorage>();
49 }
50 }
51 return instance_;
52 }
53
DistributedDataStorage()54 DistributedDataStorage::DistributedDataStorage()
55 {
56 APP_LOGI("instance is created");
57 TryTwice([this] { return GetKvStore(); });
58 }
59
~DistributedDataStorage()60 DistributedDataStorage::~DistributedDataStorage()
61 {
62 APP_LOGI("instance is destroyed");
63 dataManager_.CloseKvStore(appId_, storeId_);
64 }
65
SaveStorageDistributeInfo(const std::string & bundleName,int32_t userId)66 void DistributedDataStorage::SaveStorageDistributeInfo(const std::string &bundleName, int32_t userId)
67 {
68 APP_LOGI("save DistributedBundleInfo data");
69 {
70 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
71 if (!CheckKvStore()) {
72 APP_LOGE("kvStore is nullptr");
73 return;
74 }
75 }
76 int32_t currentUserId = AccountManagerHelper::GetCurrentActiveUserId();
77 if (currentUserId == Constants::INVALID_USERID) {
78 currentUserId = Constants::START_USERID;
79 }
80 if (userId != currentUserId) {
81 APP_LOGW("install userid:%{public}d is not currentUserId:%{public}d", userId, currentUserId);
82 return;
83 }
84 auto bundleMgr = DelayedSingleton<DistributedBms>::GetInstance()->GetBundleMgr();
85 if (bundleMgr == nullptr) {
86 APP_LOGE("Get bundleMgr shared_ptr nullptr");
87 return;
88 }
89 BundleInfo bundleInfo;
90 bool ret = bundleMgr->GetBundleInfo(bundleName, FLAGS, bundleInfo, currentUserId);
91 if (!ret) {
92 APP_LOGW("GetBundleInfo:%{public}s userid:%{public}d failed", bundleName.c_str(), currentUserId);
93 DeleteStorageDistributeInfo(bundleName, currentUserId);
94 return;
95 }
96 ret = InnerSaveStorageDistributeInfo(ConvertToDistributedBundleInfo(bundleInfo));
97 if (!ret) {
98 APP_LOGW("InnerSaveStorageDistributeInfo:%{public}s failed", bundleName.c_str());
99 }
100 }
101
InnerSaveStorageDistributeInfo(const DistributedBundleInfo & distributedBundleInfo)102 bool DistributedDataStorage::InnerSaveStorageDistributeInfo(const DistributedBundleInfo &distributedBundleInfo)
103 {
104 std::string udid;
105 bool ret = GetLocalUdid(udid);
106 if (!ret) {
107 APP_LOGE("GetLocalUdid error");
108 return false;
109 }
110 std::string keyOfData = DeviceAndNameToKey(udid, distributedBundleInfo.bundleName);
111 Key key(keyOfData);
112 Value value(distributedBundleInfo.ToString());
113 Status status = kvStorePtr_->Put(key, value);
114 if (status == Status::IPC_ERROR) {
115 status = kvStorePtr_->Put(key, value);
116 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
117 }
118 if (status != Status::SUCCESS) {
119 APP_LOGE("put to kvStore error: %{public}d", status);
120 return false;
121 }
122 APP_LOGI("put value to kvStore success");
123 return true;
124 }
125
DeleteStorageDistributeInfo(const std::string & bundleName,int32_t userId)126 void DistributedDataStorage::DeleteStorageDistributeInfo(const std::string &bundleName, int32_t userId)
127 {
128 APP_LOGI("delete DistributedBundleInfo");
129 {
130 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
131 if (!CheckKvStore()) {
132 APP_LOGE("kvStore is nullptr");
133 return;
134 }
135 }
136 int32_t currentUserId = AccountManagerHelper::GetCurrentActiveUserId();
137 if (userId != currentUserId) {
138 APP_LOGW("install userid:%{public}d is not currentUserId:%{public}d", userId, currentUserId);
139 return;
140 }
141 std::string udid;
142 bool ret = GetLocalUdid(udid);
143 if (!ret) {
144 APP_LOGE("GetLocalUdid error");
145 return;
146 }
147 std::string keyOfData = DeviceAndNameToKey(udid, bundleName);
148 Key key(keyOfData);
149 Status status = kvStorePtr_->Delete(key);
150 if (status == Status::IPC_ERROR) {
151 status = kvStorePtr_->Delete(key);
152 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
153 }
154 if (status != Status::SUCCESS) {
155 APP_LOGE("delete key error: %{public}d", status);
156 return;
157 }
158 APP_LOGI("delete value to kvStore success");
159 }
160
GetStorageDistributeInfo(const std::string & networkId,const std::string & bundleName,DistributedBundleInfo & info)161 bool DistributedDataStorage::GetStorageDistributeInfo(const std::string &networkId,
162 const std::string &bundleName, DistributedBundleInfo &info)
163 {
164 APP_LOGI("get DistributedBundleInfo");
165 {
166 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
167 if (!CheckKvStore()) {
168 APP_LOGE("kvStore is nullptr");
169 return false;
170 }
171 }
172 std::string udid;
173 int32_t ret = GetUdidByNetworkId(networkId, udid);
174 if (ret != 0) {
175 APP_LOGI("can not get udid by networkId error:%{public}d", ret);
176 return false;
177 }
178 std::string keyOfData = DeviceAndNameToKey(udid, bundleName);
179 APP_LOGI("keyOfData: [%{public}s]", keyOfData.c_str());
180 Key key(keyOfData);
181 Value value;
182 Status status = kvStorePtr_->Get(key, value);
183 if (status == Status::IPC_ERROR) {
184 status = kvStorePtr_->Get(key, value);
185 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
186 }
187 if (status == Status::SUCCESS) {
188 if (!info.FromJsonString(value.ToString())) {
189 APP_LOGE("it's an error value");
190 kvStorePtr_->Delete(key);
191 return false;
192 }
193 return true;
194 }
195 APP_LOGE("get value status: %{public}d", status);
196 return false;
197 }
198
DeviceAndNameToKey(const std::string & udid,const std::string & bundleName) const199 std::string DistributedDataStorage::DeviceAndNameToKey(
200 const std::string &udid, const std::string &bundleName) const
201 {
202 std::string key = udid + Constants::FILE_UNDERLINE + bundleName;
203 return key;
204 }
205
CheckKvStore()206 bool DistributedDataStorage::CheckKvStore()
207 {
208 if (kvStorePtr_ != nullptr) {
209 return true;
210 }
211 int32_t tryTimes = MAX_TIMES;
212 while (tryTimes > 0) {
213 Status status = GetKvStore();
214 if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
215 return true;
216 }
217 APP_LOGI("CheckKvStore, Times: %{public}d", tryTimes);
218 usleep(SLEEP_INTERVAL);
219 tryTimes--;
220 }
221 return kvStorePtr_ != nullptr;
222 }
223
GetKvStore()224 Status DistributedDataStorage::GetKvStore()
225 {
226 Options options = {
227 .createIfMissing = true,
228 .encrypt = false,
229 .autoSync = true,
230 .securityLevel = SecurityLevel::S1,
231 .kvStoreType = KvStoreType::SINGLE_VERSION,
232 .area = EL1,
233 .baseDir = BMS_KV_BASE_DIR + appId_.appId
234 };
235 Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
236 if (status != Status::SUCCESS) {
237 APP_LOGE("return error: %{public}d", status);
238 } else {
239 APP_LOGI("get kvStore success");
240 }
241 return status;
242 }
243
TryTwice(const std::function<Status ()> & func) const244 void DistributedDataStorage::TryTwice(const std::function<Status()> &func) const
245 {
246 Status status = func();
247 if (status == Status::IPC_ERROR) {
248 status = func();
249 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
250 }
251 }
252
GetLocalUdid(std::string & udid)253 bool DistributedDataStorage::GetLocalUdid(std::string &udid)
254 {
255 char innerUdid[DEVICE_UDID_LENGTH] = {0};
256 int ret = GetDevUdid(innerUdid, DEVICE_UDID_LENGTH);
257 if (ret != 0) {
258 APP_LOGI("GetDevUdid failed ,ret:%{public}d", ret);
259 return false;
260 }
261 udid = std::string(innerUdid);
262 return true;
263 }
264
GetUdidByNetworkId(const std::string & networkId,std::string & udid)265 int32_t DistributedDataStorage::GetUdidByNetworkId(const std::string &networkId, std::string &udid)
266 {
267 auto bundleMgr = DelayedSingleton<DistributedBms>::GetInstance()->GetBundleMgr();
268 if (bundleMgr == nullptr) {
269 APP_LOGE("Get bundleMgr shared_ptr nullptr");
270 return -1;
271 }
272 return bundleMgr->GetUdidByNetworkId(networkId, udid);
273 }
274
ConvertToDistributedBundleInfo(const BundleInfo & bundleInfo)275 DistributedBundleInfo DistributedDataStorage::ConvertToDistributedBundleInfo(const BundleInfo &bundleInfo)
276 {
277 DistributedBundleInfo distributedBundleInfo;
278 distributedBundleInfo.bundleName = bundleInfo.name;
279 distributedBundleInfo.versionCode = bundleInfo.versionCode;
280 distributedBundleInfo.compatibleVersionCode = bundleInfo.compatibleVersion;
281 distributedBundleInfo.versionName = bundleInfo.versionName;
282 distributedBundleInfo.minCompatibleVersion = bundleInfo.minCompatibleVersionCode;
283 distributedBundleInfo.targetVersionCode = bundleInfo.targetVersion;
284 distributedBundleInfo.appId = bundleInfo.appId;
285 std::map<std::string, std::vector<DistributedAbilityInfo>> moduleAbilityInfos;
286 for (const auto &abilityInfo : bundleInfo.abilityInfos) {
287 DistributedAbilityInfo distributedAbilityInfo;
288 distributedAbilityInfo.abilityName = abilityInfo.name;
289 distributedAbilityInfo.permissions = abilityInfo.permissions;
290 distributedAbilityInfo.type = abilityInfo.type;
291 distributedAbilityInfo.enabled = abilityInfo.enabled;
292 auto infoItem = moduleAbilityInfos.find(abilityInfo.moduleName);
293 if (infoItem == moduleAbilityInfos.end()) {
294 std::vector<DistributedAbilityInfo> distributedAbilityInfos;
295 distributedAbilityInfos.emplace_back(distributedAbilityInfo);
296 moduleAbilityInfos.emplace(abilityInfo.moduleName, distributedAbilityInfos);
297 } else {
298 moduleAbilityInfos[abilityInfo.moduleName].emplace_back(distributedAbilityInfo);
299 }
300 }
301 for (const auto& moduleAbilityInfo : moduleAbilityInfos) {
302 DistributedModuleInfo distributedModuleInfo;
303 distributedModuleInfo.moduleName = moduleAbilityInfo.first;
304 distributedModuleInfo.abilities = moduleAbilityInfo.second;
305 distributedBundleInfo.moduleInfos.emplace_back(distributedModuleInfo);
306 }
307 distributedBundleInfo.enabled = bundleInfo.applicationInfo.enabled;
308 return distributedBundleInfo;
309 }
310
UpdateDistributedData(int32_t userId)311 void DistributedDataStorage::UpdateDistributedData(int32_t userId)
312 {
313 APP_LOGI("UpdateDistributedData");
314 if (kvStorePtr_ == nullptr) {
315 APP_LOGE("kvStorePtr_ is null");
316 return;
317 }
318 std::string udid;
319 if (!GetLocalUdid(udid)) {
320 APP_LOGE("GetLocalUdid failed");
321 return;
322 }
323 Key allEntryKeyPrefix("");
324 std::vector<Entry> allEntries;
325 Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
326 if (status != Status::SUCCESS) {
327 APP_LOGE("dataManager_ GetEntries error: %{public}d", status);
328 return;
329 }
330 for (auto entry : allEntries) {
331 std::string key = entry.key.ToString();
332 if (key.find(udid) == std::string::npos) {
333 continue;
334 }
335 status = kvStorePtr_->Delete(entry.key);
336 if (status != Status::SUCCESS) {
337 APP_LOGE("Delete key:%{public}s failed", key.c_str());
338 }
339 }
340 auto bundleMgr = DelayedSingleton<DistributedBms>::GetInstance()->GetBundleMgr();
341 if (bundleMgr == nullptr) {
342 APP_LOGE("Get bundleMgr shared_ptr nullptr");
343 return;
344 }
345 std::vector<BundleInfo> bundleInfos;
346 if (!bundleMgr->GetBundleInfos(FLAGS, bundleInfos, userId)) {
347 APP_LOGE("get bundleInfos failed");
348 return;
349 }
350 for (auto bundleInfo : bundleInfos) {
351 if (bundleInfo.singleton) {
352 continue;
353 }
354 if (!InnerSaveStorageDistributeInfo(ConvertToDistributedBundleInfo(bundleInfo))) {
355 APP_LOGW("UpdateDistributedData SaveStorageDistributeInfo:%{public}s failed", bundleInfo.name.c_str());
356 }
357 }
358 }
359 } // namespace AppExecFwk
360 } // namespace OHOS