• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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