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