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::mutex DistributedDataStorage::mutex_;
42
GetInstance()43 std::shared_ptr<DistributedDataStorage> DistributedDataStorage::GetInstance()
44 {
45 if (instance_ == nullptr) {
46 std::lock_guard<std::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
GetDistributedBundleName(const std::string & networkId,uint32_t accessTokenId,std::string & bundleName)199 int32_t DistributedDataStorage::GetDistributedBundleName(const std::string &networkId, uint32_t accessTokenId,
200 std::string &bundleName)
201 {
202 {
203 std::lock_guard<std::mutex> lock(kvStorePtrMutex_);
204 if (!CheckKvStore()) {
205 APP_LOGE("kvStore is nullptr");
206 return ERR_BUNDLE_MANAGER_INTERNAL_ERROR;
207 }
208 }
209 std::string udid;
210 int32_t ret = GetUdidByNetworkId(networkId, udid);
211 if (ret != 0) {
212 APP_LOGE("can not get udid by networkId error:%{public}d", ret);
213 return ret;
214 }
215 if (udid.size() == 0) {
216 APP_LOGE("get udid is Empty");
217 return ERR_BUNDLE_MANAGER_INTERNAL_ERROR;
218 }
219 Key allEntryKeyPrefix("");
220 std::vector<Entry> allEntries;
221 Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
222 if (status != Status::SUCCESS) {
223 APP_LOGE("dataManager_ GetEntries error: %{public}d", status);
224 return ERR_BUNDLE_MANAGER_INTERNAL_ERROR;
225 }
226 for (auto entry : allEntries) {
227 std::string key = entry.key.ToString();
228 std::string value = entry.value.ToString();
229 if (key.find(udid) == std::string::npos) {
230 continue;
231 }
232 DistributedBundleInfo distributedBundleInfo;
233 if (distributedBundleInfo.FromJsonString(value) && distributedBundleInfo.accessTokenId == accessTokenId) {
234 bundleName = distributedBundleInfo.bundleName;
235 return OHOS::NO_ERROR;
236 }
237 }
238 APP_LOGE("get distributed bundleName no matching data: %{private}s %{private}s %{private}d",
239 networkId.c_str(), udid.c_str(), accessTokenId);
240 return ERR_BUNDLE_MANAGER_BUNDLE_NOT_EXIST;
241 }
242
DeviceAndNameToKey(const std::string & udid,const std::string & bundleName) const243 std::string DistributedDataStorage::DeviceAndNameToKey(
244 const std::string &udid, const std::string &bundleName) const
245 {
246 std::string key = udid + Constants::FILE_UNDERLINE + bundleName;
247 return key;
248 }
249
CheckKvStore()250 bool DistributedDataStorage::CheckKvStore()
251 {
252 if (kvStorePtr_ != nullptr) {
253 return true;
254 }
255 int32_t tryTimes = MAX_TIMES;
256 while (tryTimes > 0) {
257 Status status = GetKvStore();
258 if (status == Status::SUCCESS && kvStorePtr_ != nullptr) {
259 return true;
260 }
261 APP_LOGI("CheckKvStore, Times: %{public}d", tryTimes);
262 usleep(SLEEP_INTERVAL);
263 tryTimes--;
264 }
265 return kvStorePtr_ != nullptr;
266 }
267
GetKvStore()268 Status DistributedDataStorage::GetKvStore()
269 {
270 Options options = {
271 .createIfMissing = true,
272 .encrypt = false,
273 .autoSync = true,
274 .securityLevel = SecurityLevel::S1,
275 .area = EL1,
276 .kvStoreType = KvStoreType::SINGLE_VERSION,
277 .baseDir = BMS_KV_BASE_DIR + appId_.appId
278 };
279 Status status = dataManager_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
280 if (status != Status::SUCCESS) {
281 APP_LOGE("return error: %{public}d", status);
282 } else {
283 APP_LOGI("get kvStore success");
284 }
285 return status;
286 }
287
TryTwice(const std::function<Status ()> & func) const288 void DistributedDataStorage::TryTwice(const std::function<Status()> &func) const
289 {
290 Status status = func();
291 if (status == Status::IPC_ERROR) {
292 status = func();
293 APP_LOGW("distribute database ipc error and try to call again, result = %{public}d", status);
294 }
295 }
296
GetLocalUdid(std::string & udid)297 bool DistributedDataStorage::GetLocalUdid(std::string &udid)
298 {
299 char innerUdid[DEVICE_UDID_LENGTH] = {0};
300 int ret = GetDevUdid(innerUdid, DEVICE_UDID_LENGTH);
301 if (ret != 0) {
302 APP_LOGI("GetDevUdid failed ,ret:%{public}d", ret);
303 return false;
304 }
305 udid = std::string(innerUdid);
306 return true;
307 }
308
GetUdidByNetworkId(const std::string & networkId,std::string & udid)309 int32_t DistributedDataStorage::GetUdidByNetworkId(const std::string &networkId, std::string &udid)
310 {
311 auto dbms = DelayedSingleton<DistributedBms>::GetInstance();
312 if (dbms == nullptr) {
313 APP_LOGE("dbms is null");
314 return Constants::INVALID_UDID;
315 }
316 return dbms->GetUdidByNetworkId(networkId, udid);
317 }
318
ConvertToDistributedBundleInfo(const BundleInfo & bundleInfo)319 DistributedBundleInfo DistributedDataStorage::ConvertToDistributedBundleInfo(const BundleInfo &bundleInfo)
320 {
321 DistributedBundleInfo distributedBundleInfo;
322 distributedBundleInfo.bundleName = bundleInfo.name;
323 distributedBundleInfo.versionCode = bundleInfo.versionCode;
324 distributedBundleInfo.compatibleVersionCode = bundleInfo.compatibleVersion;
325 distributedBundleInfo.versionName = bundleInfo.versionName;
326 distributedBundleInfo.minCompatibleVersion = bundleInfo.minCompatibleVersionCode;
327 distributedBundleInfo.targetVersionCode = bundleInfo.targetVersion;
328 distributedBundleInfo.appId = bundleInfo.appId;
329 std::map<std::string, std::vector<DistributedAbilityInfo>> moduleAbilityInfos;
330 for (const auto &abilityInfo : bundleInfo.abilityInfos) {
331 DistributedAbilityInfo distributedAbilityInfo;
332 distributedAbilityInfo.abilityName = abilityInfo.name;
333 distributedAbilityInfo.permissions = abilityInfo.permissions;
334 distributedAbilityInfo.type = abilityInfo.type;
335 distributedAbilityInfo.enabled = abilityInfo.enabled;
336 auto infoItem = moduleAbilityInfos.find(abilityInfo.moduleName);
337 if (infoItem == moduleAbilityInfos.end()) {
338 std::vector<DistributedAbilityInfo> distributedAbilityInfos;
339 distributedAbilityInfos.emplace_back(distributedAbilityInfo);
340 moduleAbilityInfos.emplace(abilityInfo.moduleName, distributedAbilityInfos);
341 } else {
342 moduleAbilityInfos[abilityInfo.moduleName].emplace_back(distributedAbilityInfo);
343 }
344 }
345 for (const auto& moduleAbilityInfo : moduleAbilityInfos) {
346 DistributedModuleInfo distributedModuleInfo;
347 distributedModuleInfo.moduleName = moduleAbilityInfo.first;
348 distributedModuleInfo.abilities = moduleAbilityInfo.second;
349 distributedBundleInfo.moduleInfos.emplace_back(distributedModuleInfo);
350 }
351 distributedBundleInfo.enabled = bundleInfo.applicationInfo.enabled;
352 distributedBundleInfo.accessTokenId = bundleInfo.applicationInfo.accessTokenId;
353 return distributedBundleInfo;
354 }
355
UpdateDistributedData(int32_t userId)356 void DistributedDataStorage::UpdateDistributedData(int32_t userId)
357 {
358 APP_LOGI("UpdateDistributedData");
359 if (kvStorePtr_ == nullptr) {
360 APP_LOGE("kvStorePtr_ is null");
361 return;
362 }
363 std::string udid;
364 if (!GetLocalUdid(udid)) {
365 APP_LOGE("GetLocalUdid failed");
366 return;
367 }
368 Key allEntryKeyPrefix("");
369 std::vector<Entry> allEntries;
370 Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
371 if (status != Status::SUCCESS) {
372 APP_LOGE("dataManager_ GetEntries error: %{public}d", status);
373 return;
374 }
375 for (auto entry : allEntries) {
376 std::string key = entry.key.ToString();
377 if (key.find(udid) == std::string::npos) {
378 continue;
379 }
380 status = kvStorePtr_->Delete(entry.key);
381 if (status != Status::SUCCESS) {
382 APP_LOGE("Delete key:%{public}s failed", key.c_str());
383 }
384 }
385 auto bundleMgr = DelayedSingleton<DistributedBms>::GetInstance()->GetBundleMgr();
386 if (bundleMgr == nullptr) {
387 APP_LOGE("Get bundleMgr shared_ptr nullptr");
388 return;
389 }
390 std::vector<BundleInfo> bundleInfos;
391 if (!bundleMgr->GetBundleInfos(FLAGS, bundleInfos, userId)) {
392 APP_LOGE("get bundleInfos failed");
393 return;
394 }
395 for (auto bundleInfo : bundleInfos) {
396 if (bundleInfo.singleton) {
397 continue;
398 }
399 if (!InnerSaveStorageDistributeInfo(ConvertToDistributedBundleInfo(bundleInfo))) {
400 APP_LOGW("UpdateDistributedData SaveStorageDistributeInfo:%{public}s failed", bundleInfo.name.c_str());
401 }
402 }
403 }
404 } // namespace AppExecFwk
405 } // namespace OHOS