1 /*
2 * Copyright (c) 2023 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 "RuntimeStore"
16
17 #include "runtime_store.h"
18
19 #include <algorithm>
20 #include <vector>
21 #include <unistd.h>
22 #include <sys/stat.h>
23
24 #include "log_print.h"
25 #include "ipc_skeleton.h"
26 #include "file.h"
27 #include "udmf_conversion.h"
28 #include "udmf_radar_reporter.h"
29 #include "unified_meta.h"
30 #include "tlv_util.h"
31 #include "account/account_delegate.h"
32 #include "metadata/store_meta_data.h"
33 #include "metadata/meta_data_manager.h"
34 #include "metadata/appid_meta_data.h"
35 #include "device_manager_adapter.h"
36 #include "bootstrap.h"
37 #include "directory/directory_manager.h"
38 #include "utils/anonymous.h"
39
40 namespace OHOS {
41 namespace UDMF {
42 using namespace RadarReporter;
43 using namespace DistributedDB;
44 using Anonymous = OHOS::DistributedData::Anonymous;
45 using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter;
46
47 constexpr const char *TEMP_UNIFIED_DATA_FLAG = "temp_udmf_file_flag";
48 static constexpr size_t TEMP_UDATA_RECORD_SIZE = 1;
49
RuntimeStore(const std::string & storeId)50 RuntimeStore::RuntimeStore(const std::string &storeId) : storeId_(storeId)
51 {
52 UpdateTime();
53 ZLOGD("Construct runtimeStore: %{public}s.", Anonymous::Change(storeId_).c_str());
54 }
55
~RuntimeStore()56 RuntimeStore::~RuntimeStore()
57 {
58 ZLOGD("Destruct runtimeStore: %{public}s.", Anonymous::Change(storeId_).c_str());
59 }
60
PutLocal(const std::string & key,const std::string & value)61 Status RuntimeStore::PutLocal(const std::string &key, const std::string &value)
62 {
63 UpdateTime();
64 std::vector<uint8_t> keyBytes = {key.begin(), key.end()};
65 std::vector<uint8_t> valueBytes = {value.begin(), value.end()};
66
67 auto status = kvStore_->PutLocal(keyBytes, valueBytes);
68 if (status != DBStatus::OK) {
69 ZLOGE("KvStore PutLocal failed, status: %{public}d.", status);
70 return E_DB_ERROR;
71 }
72 return E_OK;
73 }
74
GetLocal(const std::string & key,std::string & value)75 Status RuntimeStore::GetLocal(const std::string &key, std::string &value)
76 {
77 UpdateTime();
78 std::vector<uint8_t> valueBytes;
79 std::vector<uint8_t> keyBytes = {key.begin(), key.end()};
80 DBStatus status = kvStore_->GetLocal(keyBytes, valueBytes);
81 if (status != DBStatus::OK && status != DBStatus::NOT_FOUND) {
82 ZLOGE("GetLocal entry failed, key: %{public}s.", key.c_str());
83 return E_DB_ERROR;
84 }
85 if (valueBytes.empty()) {
86 ZLOGW("GetLocal entry is empty, key: %{public}s", key.c_str());
87 return E_NOT_FOUND;
88 }
89 value = {valueBytes.begin(), valueBytes.end()};
90 return E_OK;
91 }
92
DeleteLocal(const std::string & key)93 Status RuntimeStore::DeleteLocal(const std::string &key)
94 {
95 UpdateTime();
96 std::vector<uint8_t> valueBytes;
97 std::vector<uint8_t> keyBytes = {key.begin(), key.end()};
98 DBStatus status = kvStore_->DeleteLocal(keyBytes);
99 if (status != DBStatus::OK && status != DBStatus::NOT_FOUND) {
100 ZLOGE("DeleteLocal failed, key: %{public}s.", key.c_str());
101 return E_DB_ERROR;
102 }
103 return E_OK;
104 }
105
Put(const UnifiedData & unifiedData)106 Status RuntimeStore::Put(const UnifiedData &unifiedData)
107 {
108 UpdateTime();
109 std::vector<Entry> entries;
110 std::string unifiedKey = unifiedData.GetRuntime()->key.GetUnifiedKey();
111 // add runtime info
112 std::vector<uint8_t> runtimeBytes;
113 auto runtimeTlv = TLVObject(runtimeBytes);
114 if (!TLVUtil::Writing(*unifiedData.GetRuntime(), runtimeTlv, TAG::TAG_RUNTIME)) {
115 ZLOGE("Marshall runtime info failed, dataPrefix: %{public}s.", unifiedKey.c_str());
116 return E_WRITE_PARCEL_ERROR;
117 }
118 std::vector<uint8_t> udKeyBytes = {unifiedKey.begin(), unifiedKey.end()};
119 Entry entry = {udKeyBytes, runtimeBytes};
120 entries.push_back(entry);
121
122 // add unified record
123 for (const auto &record : unifiedData.GetRecords()) {
124 std::vector<uint8_t> recordBytes;
125 auto recordTlv = TLVObject(recordBytes);
126 if (!TLVUtil::Writing(record, recordTlv, TAG::TAG_UNIFIED_RECORD)) {
127 ZLOGI("Marshall unified record failed.");
128 return E_WRITE_PARCEL_ERROR;
129 }
130 std::string recordKey = unifiedKey + "/" + record->GetUid();
131 std::vector<uint8_t> keyBytes = {recordKey.begin(), recordKey.end() };
132 Entry entry = { keyBytes, recordBytes };
133 entries.push_back(entry);
134 }
135 auto status = PutEntries(entries);
136 return status;
137 }
138
Get(const std::string & key,UnifiedData & unifiedData)139 Status RuntimeStore::Get(const std::string &key, UnifiedData &unifiedData)
140 {
141 UpdateTime();
142 std::vector<Entry> entries;
143 if (GetEntries(key, entries) != E_OK) {
144 ZLOGE("GetEntries failed, dataPrefix: %{public}s.", key.c_str());
145 return E_DB_ERROR;
146 }
147 if (entries.empty()) {
148 ZLOGW("entries is empty, dataPrefix: %{public}s", key.c_str());
149 return E_NOT_FOUND;
150 }
151 return UnmarshalEntries(key, entries, unifiedData);
152 }
153
GetDetailsFromUData(UnifiedData & data,UDDetails & details)154 bool RuntimeStore::GetDetailsFromUData(UnifiedData &data, UDDetails &details)
155 {
156 auto records = data.GetRecords();
157 if (records.size() != TEMP_UDATA_RECORD_SIZE) {
158 return false;
159 }
160 if (records[0] == nullptr || records[0]->GetType() != UDType::FILE) {
161 return false;
162 }
163 auto file = static_cast<File*>(records[0].get());
164 if (file == nullptr) {
165 return false;
166 }
167 auto result = file->GetDetails();
168 if (result.find(TEMP_UNIFIED_DATA_FLAG) == result.end()) {
169 return false;
170 }
171 details = result;
172 return true;
173 }
174
GetSummaryFromDetails(const UDDetails & details,Summary & summary)175 Status RuntimeStore::GetSummaryFromDetails(const UDDetails &details, Summary &summary)
176 {
177 for (auto &item : details) {
178 if (item.first != TEMP_UNIFIED_DATA_FLAG) {
179 auto int64Value = std::get_if<int64_t>(&item.second);
180 if (int64Value != nullptr) {
181 auto size = std::get<int64_t>(item.second);
182 summary.summary[item.first] = size;
183 summary.totalSize += size;
184 }
185 }
186 }
187 return E_OK;
188 }
189
GetSummary(const std::string & key,Summary & summary)190 Status RuntimeStore::GetSummary(const std::string &key, Summary &summary)
191 {
192 UpdateTime();
193 UnifiedData unifiedData;
194 if (Get(key, unifiedData) != E_OK) {
195 ZLOGE("Get unified data failed, dataPrefix: %{public}s", key.c_str());
196 return E_DB_ERROR;
197 }
198
199 UDDetails details {};
200 if (GetDetailsFromUData(unifiedData, details)) {
201 return GetSummaryFromDetails(details, summary);
202 }
203 for (const auto &record : unifiedData.GetRecords()) {
204 int64_t recordSize = record->GetSize();
205 auto udType = UtdUtils::GetUtdIdFromUtdEnum(record->GetType());
206 auto it = summary.summary.find(udType);
207 if (it == summary.summary.end()) {
208 summary.summary[udType] = recordSize;
209 } else {
210 summary.summary[udType] += recordSize;
211 }
212 summary.totalSize += recordSize;
213 }
214 return E_OK;
215 }
216
Update(const UnifiedData & unifiedData)217 Status RuntimeStore::Update(const UnifiedData &unifiedData)
218 {
219 std::string key = unifiedData.GetRuntime()->key.key;
220 if (Delete(key) != E_OK) {
221 UpdateTime();
222 ZLOGE("Delete unified data failed, dataPrefix: %{public}s.", key.c_str());
223 return E_DB_ERROR;
224 }
225 if (Put(unifiedData) != E_OK) {
226 ZLOGE("Update unified data failed, dataPrefix: %{public}s.", key.c_str());
227 return E_DB_ERROR;
228 }
229 return E_OK;
230 }
231
Delete(const std::string & key)232 Status RuntimeStore::Delete(const std::string &key)
233 {
234 std::vector<Entry> entries;
235 if (GetEntries(key, entries) != E_OK) {
236 ZLOGE("GetEntries failed, dataPrefix: %{public}s.", key.c_str());
237 return E_DB_ERROR;
238 }
239 if (entries.empty()) {
240 ZLOGD("entries is empty.");
241 return E_OK;
242 }
243 std::vector<Key> keys;
244 for (const auto &entry : entries) {
245 keys.push_back(entry.key);
246 }
247 return DeleteEntries(keys);
248 }
249
DeleteBatch(const std::vector<std::string> & unifiedKeys)250 Status RuntimeStore::DeleteBatch(const std::vector<std::string> &unifiedKeys)
251 {
252 UpdateTime();
253 ZLOGD("called!");
254 if (unifiedKeys.empty()) {
255 ZLOGD("No need to delete!");
256 return E_OK;
257 }
258 for (const std::string &unifiedKey : unifiedKeys) {
259 if (Delete(unifiedKey) != E_OK) {
260 ZLOGE("Delete failed, key: %{public}s.", unifiedKey.c_str());
261 return E_DB_ERROR;
262 }
263 }
264 return E_OK;
265 }
266
Sync(const std::vector<std::string> & devices)267 Status RuntimeStore::Sync(const std::vector<std::string> &devices)
268 {
269 UpdateTime();
270 if (devices.empty()) {
271 ZLOGE("devices empty, no need sync.");
272 return E_INVALID_PARAMETERS;
273 }
274 std::vector<std::string> syncDevices = DmAdapter::ToUUID(devices);
275 auto onComplete = [this](const std::map<std::string, DBStatus> &devsSyncStatus) {
276 DBStatus dbStatus = DBStatus::OK;
277 for (const auto &[originDeviceId, status] : devsSyncStatus) { // only one device.
278 if (status != DBStatus::OK) {
279 dbStatus = status;
280 break;
281 }
282 }
283 if (dbStatus != DBStatus::OK) {
284 RadarReporterAdapter::ReportFail(std::string(__FUNCTION__),
285 BizScene::SYNC_DATA, SyncDataStage::SYNC_END, StageRes::FAILED, dbStatus);
286 } else {
287 RadarReporterAdapter::ReportNormal(std::string(__FUNCTION__),
288 BizScene::SYNC_DATA, SyncDataStage::SYNC_END, StageRes::SUCCESS, BizState::DFX_NORMAL_END);
289 }
290
291 ZLOGI("sync complete, %{public}s, status:%{public}d.", Anonymous::Change(storeId_).c_str(), dbStatus);
292 };
293 DBStatus status = kvStore_->Sync(syncDevices, SyncMode::SYNC_MODE_PULL_ONLY, onComplete);
294 if (status != DBStatus::OK) {
295 RadarReporterAdapter::ReportFail(std::string(__FUNCTION__),
296 BizScene::SYNC_DATA, SyncDataStage::SYNC_END, StageRes::FAILED, status);
297 ZLOGE("Sync kvStore failed, status: %{public}d.", status);
298 return E_DB_ERROR;
299 }
300 return E_OK;
301 }
302
Clear()303 Status RuntimeStore::Clear()
304 {
305 UpdateTime();
306 return Delete(DATA_PREFIX);
307 }
308
GetBatchData(const std::string & dataPrefix,std::vector<UnifiedData> & unifiedDataSet)309 Status RuntimeStore::GetBatchData(const std::string &dataPrefix, std::vector<UnifiedData> &unifiedDataSet)
310 {
311 UpdateTime();
312 std::vector<Entry> entries;
313 auto status = GetEntries(dataPrefix, entries);
314 if (status != E_OK) {
315 ZLOGE("GetEntries failed, dataPrefix: %{public}s.", dataPrefix.c_str());
316 return E_DB_ERROR;
317 }
318 if (entries.empty()) {
319 ZLOGD("entries is empty.");
320 return E_OK;
321 }
322 std::vector<std::string> keySet;
323 for (const auto &entry : entries) {
324 std::string keyStr = {entry.key.begin(), entry.key.end()};
325 if (std::count(keyStr.begin(), keyStr.end(), '/') == SLASH_COUNT_IN_KEY) {
326 keySet.emplace_back(keyStr);
327 }
328 }
329
330 for (const std::string &key : keySet) {
331 UnifiedData data;
332 if (UnmarshalEntries(key, entries, data) != E_OK) {
333 return E_READ_PARCEL_ERROR;
334 }
335 unifiedDataSet.emplace_back(data);
336 }
337 return E_OK;
338 }
339
Close()340 void RuntimeStore::Close()
341 {
342 delegateManager_->CloseKvStore(kvStore_.get());
343 }
344
Init()345 bool RuntimeStore::Init()
346 {
347 if (!SaveMetaData()) { // get keyinfo about create db fail.
348 ZLOGW("Save meta data fail.");
349 return false;
350 }
351 DistributedDB::KvStoreNbDelegate::Option option;
352 option.createIfNecessary = true;
353 option.isMemoryDb = false;
354 option.createDirByStoreIdOnly = true;
355 option.isEncryptedDb = false;
356 option.isNeedRmCorruptedDb = true;
357 option.syncDualTupleMode = true;
358 option.secOption = {DistributedKv::SecurityLevel::S1, DistributedDB::ECE};
359 DistributedDB::KvStoreNbDelegate *delegate = nullptr;
360 DBStatus status = DBStatus::NOT_SUPPORT;
361 delegateManager_->GetKvStore(storeId_, option,
362 [&delegate, &status](DBStatus dbStatus, KvStoreNbDelegate *nbDelegate) {
363 delegate = nbDelegate;
364 status = dbStatus;
365 });
366 if (status != DBStatus::OK) {
367 ZLOGE("GetKvStore fail, status: %{public}d.", static_cast<int>(status));
368 return false;
369 }
370
371 auto release = [this](KvStoreNbDelegate *delegate) {
372 ZLOGI("Release runtime kvStore.");
373 if (delegate == nullptr) {
374 return;
375 }
376 auto retStatus = delegateManager_->CloseKvStore(delegate);
377 if (retStatus != DBStatus::OK) {
378 ZLOGE("CloseKvStore fail, status: %{public}d.", static_cast<int>(retStatus));
379 }
380 };
381 kvStore_ = std::shared_ptr<KvStoreNbDelegate>(delegate, release);
382 return true;
383 }
384
BuildMetaDataParam(DistributedData::StoreMetaData & metaData)385 bool RuntimeStore::BuildMetaDataParam(DistributedData::StoreMetaData &metaData)
386 {
387 auto localDeviceId = DmAdapter::GetInstance().GetLocalDevice().uuid;
388 if (localDeviceId.empty()) {
389 ZLOGE("failed to get local device id");
390 return false;
391 }
392
393 uint32_t token = IPCSkeleton::GetSelfTokenID();
394 const std::string userId = std::to_string(DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(token));
395 metaData.appType = "harmony";
396 metaData.deviceId = localDeviceId;
397 metaData.storeId = storeId_;
398 metaData.isAutoSync = false;
399 metaData.isBackup = false;
400 metaData.isEncrypt = false;
401 metaData.bundleName = DistributedData::Bootstrap::GetInstance().GetProcessLabel();
402 metaData.appId = DistributedData::Bootstrap::GetInstance().GetProcessLabel();
403 metaData.user = userId;
404 metaData.account = DistributedKv::AccountDelegate::GetInstance()->GetCurrentAccountId();
405 metaData.tokenId = token;
406 metaData.securityLevel = DistributedKv::SecurityLevel::S1;
407 metaData.area = DistributedKv::Area::EL1;
408 metaData.uid = static_cast<int32_t>(getuid());
409 metaData.storeType = DistributedKv::KvStoreType::SINGLE_VERSION;
410 metaData.dataType = DistributedKv::DataType::TYPE_DYNAMICAL;
411 metaData.dataDir = DistributedData::DirectoryManager::GetInstance().GetStorePath(metaData);
412
413 return true;
414 }
415
SaveMetaData()416 bool RuntimeStore::SaveMetaData()
417 {
418 DistributedData::StoreMetaData saveMeta;
419 if (!BuildMetaDataParam(saveMeta)) {
420 return false;
421 }
422
423 int foregroundUserId = 0;
424 bool ret = DistributedKv::AccountDelegate::GetInstance()->QueryForegroundUserId(foregroundUserId);
425 if (!ret) {
426 ZLOGE("QueryForegroundUserId failed.");
427 return false;
428 }
429
430 saveMeta.dataDir.append("/").append(std::to_string(foregroundUserId));
431 if (!DistributedData::DirectoryManager::GetInstance().CreateDirectory(saveMeta.dataDir)) {
432 ZLOGE("Create directory error");
433 return false;
434 }
435
436 SetDelegateManager(saveMeta.dataDir, saveMeta.appId, saveMeta.user, std::to_string(foregroundUserId));
437
438 DistributedData::StoreMetaData loadLocal;
439 DistributedData::StoreMetaData syncMeta;
440 if (DistributedData::MetaDataManager::GetInstance().LoadMeta(saveMeta.GetKey(), loadLocal, true) &&
441 DistributedData::MetaDataManager::GetInstance().LoadMeta(saveMeta.GetKey(), syncMeta, false)) {
442 ZLOGD("Meta data is already saved.");
443 return true;
444 }
445
446 auto saved = DistributedData::MetaDataManager::GetInstance().SaveMeta(saveMeta.GetKey(), saveMeta) &&
447 DistributedData::MetaDataManager::GetInstance().SaveMeta(saveMeta.GetKey(), saveMeta, true);
448 if (!saved) {
449 ZLOGE("SaveMeta failed, saveMeta.key:%{public}s", saveMeta.GetKey().c_str());
450 return false;
451 }
452 DistributedData::AppIDMetaData appIdMeta;
453 appIdMeta.bundleName = saveMeta.bundleName;
454 appIdMeta.appId = saveMeta.appId;
455 saved = DistributedData::MetaDataManager::GetInstance().SaveMeta(appIdMeta.GetKey(), appIdMeta, true);
456 if (!saved) {
457 ZLOGE("Save appIdMeta failed, appIdMeta.key:%{public}s", appIdMeta.GetKey().c_str());
458 return false;
459 }
460 return true;
461 }
462
SetDelegateManager(const std::string & dataDir,const std::string & appId,const std::string & userId,const std::string & subUser)463 void RuntimeStore::SetDelegateManager(const std::string &dataDir, const std::string &appId, const std::string &userId,
464 const std::string &subUser)
465 {
466 delegateManager_ = std::make_shared<DistributedDB::KvStoreDelegateManager>(appId, userId, subUser);
467 DistributedDB::KvStoreConfig kvStoreConfig { dataDir };
468 delegateManager_->SetKvStoreConfig(kvStoreConfig);
469 }
470
GetEntries(const std::string & dataPrefix,std::vector<Entry> & entries)471 Status RuntimeStore::GetEntries(const std::string &dataPrefix, std::vector<Entry> &entries)
472 {
473 Query dbQuery = Query::Select();
474 std::vector<uint8_t> prefix = {dataPrefix.begin(), dataPrefix.end()};
475 dbQuery.PrefixKey(prefix);
476 dbQuery.OrderByWriteTime(true);
477 DBStatus status = kvStore_->GetEntries(dbQuery, entries);
478 if (status != DBStatus::OK && status != DBStatus::NOT_FOUND) {
479 ZLOGE("KvStore getEntries failed, status: %{public}d.", static_cast<int>(status));
480 return E_DB_ERROR;
481 }
482 return E_OK;
483 }
484
PutEntries(const std::vector<Entry> & entries)485 Status RuntimeStore::PutEntries(const std::vector<Entry> &entries)
486 {
487 DBStatus status = kvStore_->StartTransaction();
488 if (status != DBStatus::OK) {
489 ZLOGE("start transaction failed, status: %{public}d.", status);
490 return E_DB_ERROR;
491 }
492 status = kvStore_->PutBatch(entries);
493 if (status != DBStatus::OK) {
494 ZLOGE("putBatch failed, status: %{public}d.", status);
495 status = kvStore_->Rollback();
496 if (status != DBStatus::OK) {
497 ZLOGE("rollback failed, status: %{public}d.", status);
498 }
499 return E_DB_ERROR;
500 }
501 status = kvStore_->Commit();
502 if (status != DBStatus::OK) {
503 ZLOGE("commit failed, status: %{public}d.", status);
504 return E_DB_ERROR;
505 }
506 return E_OK;
507 }
508
DeleteEntries(const std::vector<Key> & keys)509 Status RuntimeStore::DeleteEntries(const std::vector<Key> &keys)
510 {
511 DBStatus status = kvStore_->StartTransaction();
512 if (status != DBStatus::OK) {
513 ZLOGE("start transaction failed, status: %{public}d.", status);
514 return E_DB_ERROR;
515 }
516 status = kvStore_->DeleteBatch(keys);
517 if (status != DBStatus::OK) {
518 ZLOGE("deleteBatch failed, status: %{public}d.", status);
519 status = kvStore_->Rollback();
520 if (status != DBStatus::OK) {
521 ZLOGE("rollback failed, status: %{public}d.", status);
522 }
523 return E_DB_ERROR;
524 }
525 status = kvStore_->Commit();
526 if (status != DBStatus::OK) {
527 ZLOGE("commit failed, status: %{public}d.", status);
528 return E_DB_ERROR;
529 }
530 return E_OK;
531 }
532
UnmarshalEntries(const std::string & key,std::vector<Entry> & entries,UnifiedData & unifiedData)533 Status RuntimeStore::UnmarshalEntries(const std::string &key, std::vector<Entry> &entries, UnifiedData &unifiedData)
534 {
535 for (const auto &entry : entries) {
536 std::string keyStr = {entry.key.begin(), entry.key.end()};
537 if (keyStr == key) {
538 Runtime runtime;
539 auto runtimeTlv = TLVObject(const_cast<std::vector<uint8_t> &>(entry.value));
540 if (!TLVUtil::ReadTlv(runtime, runtimeTlv, TAG::TAG_RUNTIME)) {
541 ZLOGE("Unmarshall runtime info failed.");
542 return E_READ_PARCEL_ERROR;
543 }
544 unifiedData.SetRuntime(runtime);
545 } else if (keyStr.find(key) == 0) {
546 std::shared_ptr<UnifiedRecord> record;
547 auto recordTlv = TLVObject(const_cast<std::vector<uint8_t> &>(entry.value));
548 if (!TLVUtil::ReadTlv(record, recordTlv, TAG::TAG_UNIFIED_RECORD)) {
549 ZLOGE("Unmarshall unified record failed.");
550 return E_READ_PARCEL_ERROR;
551 }
552 unifiedData.AddRecord(record);
553 }
554 }
555 UdmfConversion::ConvertRecordToSubclass(unifiedData);
556 return E_OK;
557 }
558 } // namespace UDMF
559 } // namespace OHOS