• 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 #define LOG_TAG "RdbSyncer"
16 #include "rdb_syncer.h"
17 
18 #include <chrono>
19 
20 #include "accesstoken_kit.h"
21 #include "account/account_delegate.h"
22 #include "checker/checker_manager.h"
23 #include "crypto_manager.h"
24 #include "directory_manager.h"
25 #include "kvstore_utils.h"
26 #include "log_print.h"
27 #include "metadata/appid_meta_data.h"
28 #include "metadata/meta_data_manager.h"
29 #include "metadata/store_meta_data.h"
30 #include "rdb_result_set_impl.h"
31 #include "types.h"
32 #include "utils/constant.h"
33 #include "utils/converter.h"
34 #include "types_export.h"
35 
36 using OHOS::DistributedKv::KvStoreUtils;
37 using OHOS::DistributedKv::AccountDelegate;
38 using OHOS::AppDistributedKv::CommunicationProvider;
39 using namespace OHOS::Security::AccessToken;
40 using namespace OHOS::DistributedData;
41 using system_clock = std::chrono::system_clock;
42 
43 constexpr uint32_t ITERATE_TIMES = 10000;
44 namespace OHOS::DistributedRdb {
RdbSyncer(const RdbSyncerParam & param,RdbStoreObserverImpl * observer)45 RdbSyncer::RdbSyncer(const RdbSyncerParam& param, RdbStoreObserverImpl* observer)
46     : param_(param), observer_(observer)
47 {
48     ZLOGI("construct %{public}s", param_.storeName_.c_str());
49 }
50 
~RdbSyncer()51 RdbSyncer::~RdbSyncer() noexcept
52 {
53     param_.password_.assign(param_.password_.size(), 0);
54     ZLOGI("destroy %{public}s", param_.storeName_.c_str());
55     if ((manager_ != nullptr) && (delegate_ != nullptr)) {
56         manager_->CloseStore(delegate_);
57     }
58     delete manager_;
59     if (observer_ != nullptr) {
60         delete observer_;
61     }
62 }
63 
SetTimerId(uint32_t timerId)64 void RdbSyncer::SetTimerId(uint32_t timerId)
65 {
66     timerId_ = timerId;
67 }
68 
GetTimerId() const69 uint32_t RdbSyncer::GetTimerId() const
70 {
71     return timerId_;
72 }
73 
GetPid() const74 pid_t RdbSyncer::GetPid() const
75 {
76     return pid_;
77 }
78 
GetIdentifier() const79 std::string RdbSyncer::GetIdentifier() const
80 {
81     return DistributedDB::RelationalStoreManager::GetRelationalStoreIdentifier(GetUserId(), GetAppId(), GetStoreId());
82 }
83 
GetUserId() const84 std::string RdbSyncer::GetUserId() const
85 {
86     return AccountDelegate::GetInstance()->GetDeviceAccountIdByUID(uid_);
87 }
88 
GetBundleName() const89 std::string RdbSyncer::GetBundleName() const
90 {
91     return param_.bundleName_;
92 }
93 
GetAppId() const94 std::string RdbSyncer::GetAppId() const
95 {
96     return DistributedData::CheckerManager::GetInstance().GetAppId({ uid_, token_, param_.bundleName_ });
97 }
98 
GetStoreId() const99 std::string RdbSyncer::GetStoreId() const
100 {
101     return RemoveSuffix(param_.storeName_);
102 }
103 
Init(pid_t pid,pid_t uid,uint32_t token,const std::string & writePermission,const std::string & readPermission)104 int32_t RdbSyncer::Init(
105     pid_t pid, pid_t uid, uint32_t token, const std::string &writePermission, const std::string &readPermission)
106 {
107     ZLOGI("enter");
108     pid_ = pid;
109     uid_ = uid;
110     token_ = token;
111     StoreMetaData oldMeta;
112     StoreMetaData meta;
113 
114     if (CreateMetaData(meta, oldMeta) != RDB_OK) {
115         ZLOGE("create meta data failed");
116         return RDB_ERROR;
117     }
118     if (InitDBDelegate(meta) != RDB_OK) {
119         ZLOGE("delegate is nullptr");
120         return RDB_ERROR;
121     }
122 
123     if (oldMeta.storeType == RDB_DEVICE_COLLABORATION && oldMeta.version < StoreMetaData::UUID_CHANGED_TAG) {
124         delegate_->RemoveDeviceData();
125     }
126 
127     ZLOGI("success");
128     return RDB_OK;
129 }
130 
DestroyMetaData(StoreMetaData & meta)131 int32_t RdbSyncer::DestroyMetaData(StoreMetaData &meta)
132 {
133     FillMetaData(meta);
134     auto deleted = MetaDataManager::GetInstance().DelMeta(meta.GetKey(), true);
135     return deleted ? RDB_OK : RDB_ERROR;
136 }
137 
FillMetaData(StoreMetaData & meta)138 void RdbSyncer::FillMetaData(StoreMetaData &meta)
139 {
140     meta.uid = uid_;
141     meta.tokenId = token_;
142     meta.instanceId = GetInstIndex(token_, param_.bundleName_);
143     meta.bundleName = param_.bundleName_;
144     meta.deviceId = CommunicationProvider::GetInstance().GetLocalDevice().uuid;
145     meta.storeId = RemoveSuffix(param_.storeName_);
146     meta.user = AccountDelegate::GetInstance()->GetDeviceAccountIdByUID(uid_);
147     meta.storeType = param_.type_;
148     meta.securityLevel = param_.level_;
149     meta.area = param_.area_;
150     meta.appId = CheckerManager::GetInstance().GetAppId(Converter::ConvertToStoreInfo(meta));
151     meta.appType = "harmony";
152     meta.hapName = param_.hapName_;
153     meta.dataDir = DirectoryManager::GetInstance().GetStorePath(meta) + "/" + param_.storeName_;
154     meta.account = AccountDelegate::GetInstance()->GetCurrentAccountId();
155     meta.isEncrypt = param_.isEncrypt_;
156 }
157 
CreateMetaData(StoreMetaData & meta,StoreMetaData & old)158 int32_t RdbSyncer::CreateMetaData(StoreMetaData &meta, StoreMetaData &old)
159 {
160     FillMetaData(meta);
161     bool isCreated = MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), old);
162     if (isCreated && (old.storeType != meta.storeType || Constant::NotEqual(old.isEncrypt, meta.isEncrypt) ||
163                          old.area != meta.area)) {
164         ZLOGE("meta bundle:%{public}s store:%{public}s type:%{public}d->%{public}d encrypt:%{public}d->%{public}d "
165               "area:%{public}d->%{public}d",
166             meta.bundleName.c_str(), meta.storeId.c_str(), old.storeType, meta.storeType, old.isEncrypt,
167             meta.isEncrypt, old.area, meta.area);
168         return RDB_ERROR;
169     }
170 
171     auto saved = MetaDataManager::GetInstance().SaveMeta(meta.GetKey(), meta);
172     AppIDMetaData appIdMeta;
173     appIdMeta.bundleName = meta.bundleName;
174     appIdMeta.appId = meta.appId;
175     saved = MetaDataManager::GetInstance().SaveMeta(appIdMeta.GetKey(), appIdMeta, true);
176     if (!saved) {
177         return RDB_ERROR;
178     }
179     if (!param_.isEncrypt_ || param_.password_.empty()) {
180         return RDB_OK;
181     }
182     return SetSecretKey(meta);
183 }
184 
SetSecretKey(const StoreMetaData & meta)185 bool RdbSyncer::SetSecretKey(const StoreMetaData &meta)
186 {
187     SecretKeyMetaData newSecretKey;
188     newSecretKey.storeType = meta.storeType;
189     newSecretKey.sKey = CryptoManager::GetInstance().Encrypt(param_.password_);
190     if (newSecretKey.sKey.empty()) {
191         ZLOGE("encrypt work key error.");
192         return RDB_ERROR;
193     }
194     param_.password_.assign(param_.password_.size(), 0);
195     auto time = system_clock::to_time_t(system_clock::now());
196     newSecretKey.time = { reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time) };
197     return MetaDataManager::GetInstance().SaveMeta(meta.GetSecretKey(), newSecretKey, true) ? RDB_OK : RDB_ERROR;
198 }
199 
GetPassword(const StoreMetaData & metaData,DistributedDB::CipherPassword & password)200 bool RdbSyncer::GetPassword(const StoreMetaData &metaData, DistributedDB::CipherPassword &password)
201 {
202     if (!metaData.isEncrypt) {
203         return true;
204     }
205 
206     std::string key = metaData.GetSecretKey();
207     DistributedData::SecretKeyMetaData secretKeyMeta;
208     MetaDataManager::GetInstance().LoadMeta(key, secretKeyMeta, true);
209     std::vector<uint8_t> decryptKey;
210     CryptoManager::GetInstance().Decrypt(secretKeyMeta.sKey, decryptKey);
211     if (password.SetValue(decryptKey.data(), decryptKey.size()) != DistributedDB::CipherPassword::OK) {
212         std::fill(decryptKey.begin(), decryptKey.end(), 0);
213         ZLOGE("Set secret key value failed. len is (%d)", int32_t(decryptKey.size()));
214         return false;
215     }
216     std::fill(decryptKey.begin(), decryptKey.end(), 0);
217     return true;
218 }
219 
RemoveSuffix(const std::string & name)220 std::string RdbSyncer::RemoveSuffix(const std::string& name)
221 {
222     std::string suffix(".db");
223     auto pos = name.rfind(suffix);
224     if (pos == std::string::npos || pos < name.length() - suffix.length()) {
225         return name;
226     }
227     return std::string(name, 0, pos);
228 }
229 
InitDBDelegate(const StoreMetaData & meta)230 int32_t RdbSyncer::InitDBDelegate(const StoreMetaData &meta)
231 {
232     std::lock_guard<std::mutex> lock(mutex_);
233     if (manager_ == nullptr) {
234         manager_ = new(std::nothrow) DistributedDB::RelationalStoreManager(meta.appId, meta.user, meta.instanceId);
235     }
236     if (manager_ == nullptr) {
237         ZLOGE("malloc manager failed");
238         return RDB_ERROR;
239     }
240 
241     if (delegate_ == nullptr) {
242         DistributedDB::RelationalStoreDelegate::Option option;
243         if (meta.isEncrypt) {
244             GetPassword(meta, option.passwd);
245             option.isEncryptedDb = param_.isEncrypt_;
246             option.iterateTimes = ITERATE_TIMES;
247             option.cipher = DistributedDB::CipherType::AES_256_GCM;
248         }
249         option.observer = observer_;
250         std::string fileName = meta.dataDir;
251         ZLOGI("path=%{public}s storeId=%{public}s", fileName.c_str(), meta.storeId.c_str());
252         auto status = manager_->OpenStore(fileName, meta.storeId, option, delegate_);
253         if (status != DistributedDB::DBStatus::OK) {
254             ZLOGE("open store failed status=%{public}d", status);
255             return RDB_ERROR;
256         }
257         ZLOGI("open store success");
258     }
259 
260     return RDB_OK;
261 }
262 
GetInstIndex(uint32_t tokenId,const std::string & bundleName)263 int32_t RdbSyncer::GetInstIndex(uint32_t tokenId, const std::string &bundleName)
264 {
265     if (AccessTokenKit::GetTokenTypeFlag(tokenId) != TOKEN_HAP) {
266         return 0;
267     }
268 
269     HapTokenInfo tokenInfo;
270     tokenInfo.instIndex = -1;
271     int errCode = AccessTokenKit::GetHapTokenInfo(tokenId, tokenInfo);
272     if (errCode != RET_SUCCESS) {
273         ZLOGE("GetHapTokenInfo error:%{public}d, tokenId:0x%{public}x appId:%{public}s", errCode, tokenId,
274             bundleName.c_str());
275         return -1;
276     }
277     return tokenInfo.instIndex;
278 }
279 
GetDelegate()280 DistributedDB::RelationalStoreDelegate* RdbSyncer::GetDelegate()
281 {
282     std::lock_guard<std::mutex> lock(mutex_);
283     return delegate_;
284 }
285 
SetDistributedTables(const std::vector<std::string> & tables)286 int32_t RdbSyncer::SetDistributedTables(const std::vector<std::string> &tables)
287 {
288     auto* delegate = GetDelegate();
289     if (delegate == nullptr) {
290         ZLOGE("delegate is nullptr");
291         return RDB_ERROR;
292     }
293 
294     for (const auto& table : tables) {
295         ZLOGI("%{public}s", table.c_str());
296         if (delegate->CreateDistributedTable(table) != DistributedDB::DBStatus::OK) {
297             ZLOGE("create distributed table failed");
298             return RDB_ERROR;
299         }
300     }
301     ZLOGE("create distributed table success");
302     return RDB_OK;
303 }
304 
GetConnectDevices()305 std::vector<std::string> RdbSyncer::GetConnectDevices()
306 {
307     auto deviceInfos = AppDistributedKv::CommunicationProvider::GetInstance().GetRemoteDevices();
308     std::vector<std::string> devices;
309     for (const auto& deviceInfo : deviceInfos) {
310         devices.push_back(deviceInfo.networkId);
311     }
312     ZLOGI("size=%{public}u", static_cast<uint32_t>(devices.size()));
313     for (const auto& device: devices) {
314         ZLOGI("%{public}s", KvStoreUtils::ToBeAnonymous(device).c_str());
315     }
316     return devices;
317 }
318 
NetworkIdToUUID(const std::vector<std::string> & networkIds)319 std::vector<std::string> RdbSyncer::NetworkIdToUUID(const std::vector<std::string> &networkIds)
320 {
321     std::vector<std::string> uuids;
322     for (const auto& networkId : networkIds) {
323         auto uuid = CommunicationProvider::GetInstance().GetUuidByNodeId(networkId);
324         if (uuid.empty()) {
325             ZLOGE("%{public}s failed", KvStoreUtils::ToBeAnonymous(networkId).c_str());
326             continue;
327         }
328         uuids.push_back(uuid);
329         ZLOGI("%{public}s <--> %{public}s", KvStoreUtils::ToBeAnonymous(networkId).c_str(),
330               KvStoreUtils::ToBeAnonymous(uuid).c_str());
331     }
332     return uuids;
333 }
334 
HandleSyncStatus(const std::map<std::string,std::vector<DistributedDB::TableStatus>> & syncStatus,SyncResult & result)335 void RdbSyncer::HandleSyncStatus(const std::map<std::string, std::vector<DistributedDB::TableStatus>> &syncStatus,
336                                  SyncResult &result)
337 {
338     for (const auto& status : syncStatus) {
339         auto res = DistributedDB::DBStatus::OK;
340         for (const auto& tableStatus : status.second) {
341             if (tableStatus.status != DistributedDB::DBStatus::OK) {
342                 res = tableStatus.status;
343                 break;
344             }
345         }
346         std::string uuid = CommunicationProvider::GetInstance().ToNodeId(status.first);
347         if (uuid.empty()) {
348             ZLOGE("%{public}.6s failed", status.first.c_str());
349             continue;
350         }
351         ZLOGI("%{public}.6s=%{public}d", uuid.c_str(), res);
352         result[uuid] = res;
353     }
354 }
EqualTo(const RdbPredicateOperation & operation,DistributedDB::Query & query)355 void RdbSyncer::EqualTo(const RdbPredicateOperation &operation, DistributedDB::Query &query)
356 {
357     query.EqualTo(operation.field_, operation.values_[0]);
358     ZLOGI("field=%{public}s value=%{public}s", operation.field_.c_str(), operation.values_[0].c_str());
359 }
360 
NotEqualTo(const RdbPredicateOperation & operation,DistributedDB::Query & query)361 void RdbSyncer::NotEqualTo(const RdbPredicateOperation &operation, DistributedDB::Query &query)
362 {
363     query.NotEqualTo(operation.field_, operation.values_[0]);
364     ZLOGI("field=%{public}s value=%{public}s", operation.field_.c_str(), operation.values_[0].c_str());
365 }
366 
And(const RdbPredicateOperation & operation,DistributedDB::Query & query)367 void RdbSyncer::And(const RdbPredicateOperation &operation, DistributedDB::Query &query)
368 {
369     query.And();
370     ZLOGI("");
371 }
372 
Or(const RdbPredicateOperation & operation,DistributedDB::Query & query)373 void RdbSyncer::Or(const RdbPredicateOperation &operation, DistributedDB::Query &query)
374 {
375     query.Or();
376     ZLOGI("");
377 }
378 
OrderBy(const RdbPredicateOperation & operation,DistributedDB::Query & query)379 void RdbSyncer::OrderBy(const RdbPredicateOperation &operation, DistributedDB::Query &query)
380 {
381     bool isAsc = operation.values_[0] == "true";
382     query.OrderBy(operation.field_, isAsc);
383     ZLOGI("field=%{public}s isAsc=%{public}s", operation.field_.c_str(), operation.values_[0].c_str());
384 }
385 
Limit(const RdbPredicateOperation & operation,DistributedDB::Query & query)386 void RdbSyncer::Limit(const RdbPredicateOperation &operation, DistributedDB::Query &query)
387 {
388     char *end = nullptr;
389     int limit = static_cast<int>(strtol(operation.field_.c_str(), &end, DECIMAL_BASE));
390     int offset = static_cast<int>(strtol(operation.values_[0].c_str(), &end, DECIMAL_BASE));
391     if (limit < 0) {
392         limit = 0;
393     }
394     if (offset < 0) {
395         offset = 0;
396     }
397     query.Limit(limit, offset);
398     ZLOGI("limit=%{public}d offset=%{public}d", limit, offset);
399 }
400 
MakeQuery(const RdbPredicates & predicates)401 DistributedDB::Query RdbSyncer::MakeQuery(const RdbPredicates &predicates)
402 {
403     ZLOGI("table=%{public}s", predicates.table_.c_str());
404     auto query = DistributedDB::Query::Select(predicates.table_);
405     for (const auto& operation : predicates.operations_) {
406         if (operation.operator_ >= 0 && operation.operator_ < OPERATOR_MAX) {
407             HANDLES[operation.operator_](operation, query);
408         }
409     }
410     return query;
411 }
412 
DoSync(const SyncOption & option,const RdbPredicates & predicates,SyncResult & result)413 int32_t RdbSyncer::DoSync(const SyncOption &option, const RdbPredicates &predicates, SyncResult &result)
414 {
415     ZLOGI("enter");
416     auto* delegate = GetDelegate();
417     if (delegate == nullptr) {
418         ZLOGE("delegate is nullptr");
419         return RDB_ERROR;
420     }
421 
422     std::vector<std::string> devices;
423     if (predicates.devices_.empty()) {
424         devices = NetworkIdToUUID(GetConnectDevices());
425     } else {
426         devices = NetworkIdToUUID(predicates.devices_);
427     }
428 
429     ZLOGI("delegate sync");
430     return delegate->Sync(devices, static_cast<DistributedDB::SyncMode>(option.mode),
431                           MakeQuery(predicates), [&result] (const auto& syncStatus) {
432                               HandleSyncStatus(syncStatus, result);
433                           }, true);
434 }
435 
DoAsync(const SyncOption & option,const RdbPredicates & predicates,const SyncCallback & callback)436 int32_t RdbSyncer::DoAsync(const SyncOption &option, const RdbPredicates &predicates, const SyncCallback& callback)
437 {
438     auto* delegate = GetDelegate();
439     if (delegate == nullptr) {
440         ZLOGE("delegate is nullptr");
441         return RDB_ERROR;
442     }
443 
444     std::vector<std::string> devices;
445     if (predicates.devices_.empty()) {
446         devices = NetworkIdToUUID(GetConnectDevices());
447     } else {
448         devices = NetworkIdToUUID(predicates.devices_);
449     }
450 
451     ZLOGI("delegate sync");
452     return delegate->Sync(devices, static_cast<DistributedDB::SyncMode>(option.mode),
453                           MakeQuery(predicates), [callback] (const auto& syncStatus) {
454                               SyncResult result;
455                               HandleSyncStatus(syncStatus, result);
456                               callback(result);
457                           }, false);
458 }
459 
RemoteQuery(const std::string & device,const std::string & sql,const std::vector<std::string> & selectionArgs,sptr<IRemoteObject> & resultSet)460 int32_t RdbSyncer::RemoteQuery(const std::string& device, const std::string& sql,
461                                const std::vector<std::string>& selectionArgs, sptr<IRemoteObject>& resultSet)
462 {
463     ZLOGI("enter");
464     auto* delegate = GetDelegate();
465     if (delegate == nullptr) {
466         ZLOGE("delegate is nullptr");
467         return RDB_ERROR;
468     }
469 
470     ZLOGI("delegate remote query");
471     std::shared_ptr<DistributedDB::ResultSet> dbResultSet;
472     DistributedDB::DBStatus status = delegate->RemoteQuery(device, {sql, selectionArgs},
473                                                            REMOTE_QUERY_TIME_OUT, dbResultSet);
474     if (status != DistributedDB::DBStatus::OK) {
475         ZLOGE("DistributedDB remote query failed, status is  %{public}d.", status);
476         return RDB_ERROR;
477     }
478     resultSet = (new (std::nothrow) RdbResultSetImpl(dbResultSet))->AsObject().GetRefPtr();
479     return RDB_OK;
480 }
481 } // namespace OHOS::DistributedRdb
482