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