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