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