1 /*
2 * Copyright (c) 2021 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 "KvStoreMetaManager"
16
17 #include "kvstore_meta_manager.h"
18
19 #include <ipc_skeleton.h>
20 #include <thread>
21 #include <unistd.h>
22
23 #include "account_delegate.h"
24 #include "bootstrap.h"
25 #include "communication_provider.h"
26 #include "communication_strategy.h"
27 #include "crypto_manager.h"
28 #include "device_manager_adapter.h"
29 #include "device_matrix.h"
30 #include "directory/directory_manager.h"
31 #include "dump_helper.h"
32 #include "eventcenter/event_center.h"
33 #include "kvstore_data_service.h"
34 #include "log_print.h"
35 #include "matrix_event.h"
36 #include "metadata/meta_data_manager.h"
37 #include "utils/anonymous.h"
38 #include "utils/block_integer.h"
39 #include "utils/crypto.h"
40 #include "utils/ref_count.h"
41
42 namespace OHOS {
43 namespace DistributedKv {
44 using Commu = AppDistributedKv::CommunicationProvider;
45 using DmAdapter = DistributedData::DeviceManagerAdapter;
46 using namespace std::chrono;
47 using namespace OHOS::DistributedData;
48 using namespace DistributedDB;
49 using namespace OHOS::AppDistributedKv;
50
51 KvStoreMetaManager::MetaDeviceChangeListenerImpl KvStoreMetaManager::listener_;
52
KvStoreMetaManager()53 KvStoreMetaManager::KvStoreMetaManager()
54 : metaDelegate_(nullptr), metaDBDirectory_(DirectoryManager::GetInstance().GetMetaStorePath()),
55 label_(Bootstrap::GetInstance().GetProcessLabel()),
56 delegateManager_(Bootstrap::GetInstance().GetProcessLabel(), "default")
57 {
58 ZLOGI("begin.");
59 CommunicationStrategy::GetInstance().RegGetSyncDataSize("meta_store", [this](const std::string &deviceId) {
60 return this->GetSyncDataSize(deviceId);
61 });
62 }
63
~KvStoreMetaManager()64 KvStoreMetaManager::~KvStoreMetaManager()
65 {
66 }
67
GetInstance()68 KvStoreMetaManager &KvStoreMetaManager::GetInstance()
69 {
70 static KvStoreMetaManager instance;
71 return instance;
72 }
73
SubscribeMeta(const std::string & keyPrefix,const ChangeObserver & observer)74 void KvStoreMetaManager::SubscribeMeta(const std::string &keyPrefix, const ChangeObserver &observer)
75 {
76 metaObserver_.handlerMap_[keyPrefix] = observer;
77 }
78
InitMetaListener()79 void KvStoreMetaManager::InitMetaListener()
80 {
81 InitMetaData();
82 auto status = DmAdapter::GetInstance().StartWatchDeviceChange(&listener_, { "metaMgr" });
83 if (status != AppDistributedKv::Status::SUCCESS) {
84 ZLOGW("register failed.");
85 return;
86 }
87 ZLOGI("register meta device change success.");
88 SubscribeMetaKvStore();
89 SyncMeta();
90 InitBroadcast();
91 InitDeviceOnline();
92 }
93
InitBroadcast()94 void KvStoreMetaManager::InitBroadcast()
95 {
96 auto pipe = Bootstrap::GetInstance().GetProcessLabel() + "-" + "default";
97 auto result = Commu::GetInstance().ListenBroadcastMsg({ pipe },
98 [](const std::string &device, uint16_t mask) { DeviceMatrix::GetInstance().OnBroadcast(device, mask); });
99
100 EventCenter::GetInstance().Subscribe(DeviceMatrix::MATRIX_BROADCAST, [pipe](const Event &event) {
101 auto &matrixEvent = static_cast<const MatrixEvent &>(event);
102 Commu::GetInstance().Broadcast({ pipe }, matrixEvent.GetMask());
103 });
104
105 ZLOGI("observer matrix broadcast %{public}d.", result);
106 }
107
InitDeviceOnline()108 void KvStoreMetaManager::InitDeviceOnline()
109 {
110 ZLOGI("observer matrix online event.");
111 using DBStatuses = std::map<std::string, DBStatus>;
112 EventCenter::GetInstance().Subscribe(DeviceMatrix::MATRIX_ONLINE, [this](const Event &event) {
113 auto &matrixEvent = static_cast<const MatrixEvent &>(event);
114 auto mask = matrixEvent.GetMask();
115 auto deviceId = matrixEvent.GetDeviceId();
116 auto store = GetMetaKvStore();
117 auto onComplete = [deviceId, mask, refCount = matrixEvent.StealRefCount()](const DBStatuses &) mutable {
118 ZLOGD("matrix 0x%{public}08x device:%{public}s online", mask, Anonymous::Change(deviceId).c_str());
119 auto finEvent = std::make_unique<MatrixEvent>(DeviceMatrix::MATRIX_META_FINISHED, deviceId, mask);
120 finEvent->SetRefCount(std::move(refCount));
121 DeviceMatrix::GetInstance().OnExchanged(deviceId, DeviceMatrix::META_STORE_MASK);
122 EventCenter::GetInstance().PostEvent(std::move(finEvent));
123 };
124 if (((mask & DeviceMatrix::META_STORE_MASK) != 0) && store != nullptr) {
125 auto status = store->Sync({ deviceId }, DistributedDB::SyncMode::SYNC_MODE_PUSH_PULL, onComplete);
126 if (status == OK) {
127 return;
128 }
129 ZLOGW("meta online sync error 0x%{public}08x device:%{public}s %{public}d", mask,
130 Anonymous::Change(deviceId).c_str(), status);
131 }
132 onComplete({ });
133 });
134 }
135
InitMetaData()136 void KvStoreMetaManager::InitMetaData()
137 {
138 ZLOGI("start.");
139 auto metaDelegate = GetMetaKvStore();
140 if (metaDelegate == nullptr) {
141 ZLOGI("get meta failed.");
142 return;
143 }
144 auto uid = getuid();
145 auto tokenId = IPCSkeleton::GetCallingTokenID();
146 const std::string accountId = AccountDelegate::GetInstance()->GetCurrentAccountId();
147 auto userId = AccountDelegate::GetInstance()->GetUserByToken(tokenId);
148 StoreMetaData data;
149 data.appId = label_;
150 data.appType = "default";
151 data.bundleName = label_;
152 data.dataDir = metaDBDirectory_;
153 data.user = std::to_string(userId);
154 data.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid;
155 data.isAutoSync = false;
156 data.isBackup = false;
157 data.isEncrypt = false;
158 data.storeType = KvStoreType::SINGLE_VERSION;
159 data.schema = "";
160 data.storeId = Bootstrap::GetInstance().GetMetaDBName();
161 data.account = accountId;
162 data.uid = static_cast<int32_t>(uid);
163 data.version = META_STORE_VERSION;
164 data.securityLevel = SecurityLevel::S1;
165 data.area = EL1;
166 data.tokenId = tokenId;
167 if (!MetaDataManager::GetInstance().SaveMeta(data.GetKey(), data)) {
168 ZLOGE("save meta fail");
169 }
170 ZLOGI("end.");
171 }
172
InitMetaParameter()173 void KvStoreMetaManager::InitMetaParameter()
174 {
175 ZLOGI("start.");
176 executors_->Execute(GetTask(0));
177 DistributedDB::KvStoreConfig kvStoreConfig{ metaDBDirectory_ };
178 delegateManager_.SetKvStoreConfig(kvStoreConfig);
179 }
180
GetTask(uint32_t retry)181 ExecutorPool::Task KvStoreMetaManager::GetTask(uint32_t retry)
182 {
183 return [this, retry] {
184 auto status = CryptoManager::GetInstance().CheckRootKey();
185 if (status == CryptoManager::ErrCode::SUCCESS) {
186 ZLOGI("root key exist.");
187 return;
188 }
189 if (status == CryptoManager::ErrCode::NOT_EXIST &&
190 CryptoManager::GetInstance().GenerateRootKey() == CryptoManager::ErrCode::SUCCESS) {
191 ZLOGI("GenerateRootKey success.");
192 return;
193 }
194 ZLOGW("GenerateRootKey failed, retry times:%{public}d.", static_cast<int>(retry));
195 if (retry + 1 > RETRY_MAX_TIMES) {
196 ZLOGE("fail to register subscriber!");
197 return;
198 }
199 executors_->Schedule(std::chrono::seconds(RETRY_INTERVAL), GetTask(retry + 1));
200 };
201 }
202
GetMetaKvStore()203 KvStoreMetaManager::NbDelegate KvStoreMetaManager::GetMetaKvStore()
204 {
205 if (metaDelegate_ != nullptr) {
206 return metaDelegate_;
207 }
208
209 std::lock_guard<decltype(mutex_)> lock(mutex_);
210 if (metaDelegate_ == nullptr) {
211 metaDelegate_ = CreateMetaKvStore();
212 }
213 ConfigMetaDataManager();
214 return metaDelegate_;
215 }
216
CreateMetaKvStore()217 KvStoreMetaManager::NbDelegate KvStoreMetaManager::CreateMetaKvStore()
218 {
219 DistributedDB::DBStatus dbStatusTmp = DistributedDB::DBStatus::NOT_SUPPORT;
220 DistributedDB::KvStoreNbDelegate::Option option;
221 option.createIfNecessary = true;
222 option.isMemoryDb = false;
223 option.createDirByStoreIdOnly = true;
224 option.isEncryptedDb = false;
225 option.isNeedRmCorruptedDb = true;
226 DistributedDB::KvStoreNbDelegate *delegate = nullptr;
227 delegateManager_.GetKvStore(Bootstrap::GetInstance().GetMetaDBName(), option,
228 [&delegate, &dbStatusTmp](DistributedDB::DBStatus dbStatus, DistributedDB::KvStoreNbDelegate *nbDelegate) {
229 delegate = nbDelegate;
230 dbStatusTmp = dbStatus;
231 });
232
233 if (dbStatusTmp != DistributedDB::DBStatus::OK) {
234 ZLOGE("GetKvStore return error status: %{public}d", static_cast<int>(dbStatusTmp));
235 return nullptr;
236 }
237 delegate->SetRemotePushFinishedNotify([](const RemotePushNotifyInfo &info) {
238 DeviceMatrix::GetInstance().OnExchanged(info.deviceId, DeviceMatrix::META_STORE_MASK);
239 });
240 auto release = [this](DistributedDB::KvStoreNbDelegate *delegate) {
241 ZLOGI("release meta data kv store");
242 if (delegate == nullptr) {
243 return;
244 }
245
246 auto result = delegateManager_.CloseKvStore(delegate);
247 if (result != DistributedDB::DBStatus::OK) {
248 ZLOGE("CloseMetaKvStore return error status: %{public}d", static_cast<int>(result));
249 }
250 };
251 return NbDelegate(delegate, release);
252 }
253
ConfigMetaDataManager()254 void KvStoreMetaManager::ConfigMetaDataManager()
255 {
256 auto fullName = GetBackupPath();
257 auto backup = [fullName](const auto &store) -> int32_t {
258 DistributedDB::CipherPassword password;
259 return store->Export(fullName, password);
260 };
261 auto syncer = [](const auto &store, int32_t status) {
262 ZLOGI("Syncer status: %{public}d", status);
263 DeviceMatrix::GetInstance().OnChanged(DeviceMatrix::META_STORE_MASK);
264 std::vector<std::string> devs;
265 auto devices = DmAdapter::GetInstance().GetRemoteDevices();
266 for (auto const &dev : devices) {
267 devs.push_back(dev.uuid);
268 }
269
270 if (devs.empty()) {
271 ZLOGW("no devices need sync meta data.");
272 return;
273 }
274
275 status = store->Sync(devs, DistributedDB::SyncMode::SYNC_MODE_PUSH_PULL, [](auto &results) {
276 ZLOGD("meta data sync completed.");
277 for (auto &[uuid, status] : results) {
278 if (status != DistributedDB::OK) {
279 continue;
280 }
281 DeviceMatrix::GetInstance().OnExchanged(uuid, DeviceMatrix::META_STORE_MASK);
282 }
283 });
284
285 if (status != DistributedDB::OK) {
286 ZLOGW("meta data sync error %{public}d.", status);
287 }
288 };
289 MetaDataManager::GetInstance().Initialize(metaDelegate_, backup, syncer);
290 }
291
SyncMeta()292 void KvStoreMetaManager::SyncMeta()
293 {
294 std::vector<std::string> devs;
295 auto deviceList = DmAdapter::GetInstance().GetRemoteDevices();
296 for (auto const &dev : deviceList) {
297 devs.push_back(dev.uuid);
298 }
299
300 if (devs.empty()) {
301 ZLOGW("meta db sync fail, devices is empty.");
302 return;
303 }
304
305 auto metaDelegate = GetMetaKvStore();
306 if (metaDelegate == nullptr) {
307 ZLOGW("meta db sync failed.");
308 return;
309 }
310 auto onComplete = [this](const std::map<std::string, DistributedDB::DBStatus> &) {
311 ZLOGD("meta db sync complete end.");
312 };
313 auto dbStatus = metaDelegate->Sync(devs, DistributedDB::SyncMode::SYNC_MODE_PUSH_PULL, onComplete);
314 if (dbStatus != DistributedDB::OK) {
315 ZLOGW("meta db sync failed, error is %{public}d.", dbStatus);
316 }
317 }
318
SubscribeMetaKvStore()319 void KvStoreMetaManager::SubscribeMetaKvStore()
320 {
321 auto metaDelegate = GetMetaKvStore();
322 if (metaDelegate == nullptr) {
323 ZLOGW("register meta observer failed.");
324 return;
325 }
326
327 int mode = DistributedDB::OBSERVER_CHANGES_NATIVE | DistributedDB::OBSERVER_CHANGES_FOREIGN;
328 auto dbStatus = metaDelegate->RegisterObserver(DistributedDB::Key(), mode, &metaObserver_);
329 if (dbStatus != DistributedDB::DBStatus::OK) {
330 ZLOGW("register meta observer failed :%{public}d.", dbStatus);
331 }
332 }
333
~KvStoreMetaObserver()334 KvStoreMetaManager::KvStoreMetaObserver::~KvStoreMetaObserver()
335 {
336 ZLOGW("meta observer destruct.");
337 }
338
OnChange(const DistributedDB::KvStoreChangedData & data)339 void KvStoreMetaManager::KvStoreMetaObserver::OnChange(const DistributedDB::KvStoreChangedData &data)
340 {
341 ZLOGD("on data change.");
342 HandleChanges(CHANGE_FLAG::INSERT, data.GetEntriesInserted());
343 HandleChanges(CHANGE_FLAG::UPDATE, data.GetEntriesUpdated());
344 HandleChanges(CHANGE_FLAG::DELETE, data.GetEntriesDeleted());
345 }
346
HandleChanges(CHANGE_FLAG flag,const std::list<DistributedDB::Entry> & entries)347 void KvStoreMetaManager::KvStoreMetaObserver::HandleChanges(CHANGE_FLAG flag,
348 const std::list<DistributedDB::Entry> &entries)
349 {
350 for (const auto &entry : entries) {
351 std::string key(entry.key.begin(), entry.key.end());
352 for (const auto &item : handlerMap_) {
353 ZLOGI("flag:%{public}d, key:%{public}s", flag, Anonymous::Change(key).c_str());
354 if (key.find(item.first) == 0) {
355 item.second(entry.key, entry.value, flag);
356 }
357 }
358 }
359 }
360
OnDeviceChanged(const AppDistributedKv::DeviceInfo & info,const AppDistributedKv::DeviceChangeType & type) const361 void KvStoreMetaManager::MetaDeviceChangeListenerImpl::OnDeviceChanged(const AppDistributedKv::DeviceInfo &info,
362 const AppDistributedKv::DeviceChangeType &type) const
363 {
364 if (info.uuid == DmAdapter::CLOUD_DEVICE_UUID) {
365 return;
366 }
367 EventCenter::Defer defer;
368 switch (type) {
369 case AppDistributedKv::DeviceChangeType::DEVICE_OFFLINE:
370 DeviceMatrix::GetInstance().Offline(info.uuid);
371 break;
372 case AppDistributedKv::DeviceChangeType::DEVICE_ONLINE:
373 DeviceMatrix::GetInstance().Online(info.uuid, RefCount([deviceId = info.uuid]() {
374 DmAdapter::GetInstance().NotifyReadyEvent(deviceId);
375 }));
376 break;
377 default:
378 ZLOGI("flag:%{public}d", type);
379 break;
380 }
381 }
382
GetChangeLevelType() const383 AppDistributedKv::ChangeLevelType KvStoreMetaManager::MetaDeviceChangeListenerImpl::GetChangeLevelType() const
384 {
385 return AppDistributedKv::ChangeLevelType::LOW;
386 }
387
GetBackupPath() const388 std::string KvStoreMetaManager::GetBackupPath() const
389 {
390 return (DirectoryManager::GetInstance().GetMetaBackupPath() + "/" +
391 Crypto::Sha256(label_ + "_" + Bootstrap::GetInstance().GetMetaDBName()));
392 }
393
GetSyncDataSize(const std::string & deviceId)394 size_t KvStoreMetaManager::GetSyncDataSize(const std::string &deviceId)
395 {
396 auto metaDelegate = GetMetaKvStore();
397 if (metaDelegate == nullptr) {
398 return 0;
399 }
400
401 return metaDelegate->GetSyncDataSize(deviceId);
402 }
403
BindExecutor(std::shared_ptr<ExecutorPool> executors)404 void KvStoreMetaManager::BindExecutor(std::shared_ptr<ExecutorPool> executors)
405 {
406 executors_ = executors;
407 }
408 } // namespace DistributedKv
409 } // namespace OHOS
410