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
16 #define LOG_TAG "BackupHandler"
17
18 #include "backup_handler.h"
19 #include <directory_ex.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <nlohmann/json.hpp>
23 #include "account_delegate.h"
24 #include "battery_info.h"
25 #include "battery_srv_client.h"
26 #include "constant.h"
27 #include "kv_store_delegate_manager.h"
28 #include "kv_scheduler.h"
29 #include "kvstore_data_service.h"
30 #include "log_print.h"
31 #include "kvstore_meta_manager.h"
32 #include "power_mgr_client.h"
33 #include "time_utils.h"
34 #include "utils/crypto.h"
35
36 namespace OHOS::DistributedKv {
37 using json = nlohmann::json;
38
BackupHandler(IKvStoreDataService * kvStoreDataService)39 BackupHandler::BackupHandler(IKvStoreDataService *kvStoreDataService)
40 {
41 }
42
BackupHandler()43 BackupHandler::BackupHandler()
44 {
45 }
~BackupHandler()46 BackupHandler::~BackupHandler()
47 {
48 }
BackSchedule()49 void BackupHandler::BackSchedule()
50 {
51 std::chrono::duration<int> delay(1800); // delay 30 minutes
52 std::chrono::duration<int> internal(1800); // duration is 30 minutes
53 ZLOGI("BackupHandler Schedule start.");
54 scheduler_.Every(delay, internal, [&]() {
55 if (!CheckNeedBackup()) {
56 ZLOGE("it is not meet the condition of backup.");
57 return;
58 }
59 std::map<std::string, MetaData> results;
60 ZLOGI("BackupHandler Schedule Every start.");
61 if (!KvStoreMetaManager::GetInstance().GetFullMetaData(results)) {
62 ZLOGE("GetFullMetaData failed.");
63 return;
64 }
65
66 for (auto const &entry : results) {
67 if (!entry.second.kvStoreMetaData.isBackup || entry.second.kvStoreMetaData.isDirty) {
68 continue;
69 }
70
71 KvStoreType type = entry.second.kvStoreMetaData.kvStoreType;
72 if (type == KvStoreType::MULTI_VERSION) {
73 MultiKvStoreBackup(entry.second);
74 } else if (type == KvStoreType::SINGLE_VERSION) {
75 SingleKvStoreBackup(entry.second);
76 }
77 }
78 backupSuccessTime_ = TimeUtils::CurrentTimeMicros();
79 });
80 }
81
SingleKvStoreBackup(const MetaData & metaData)82 void BackupHandler::SingleKvStoreBackup(const MetaData &metaData)
83 {
84 ZLOGI("SingleKvStoreBackup start.");
85 BackupPara backupPara;
86 auto initPara = InitBackupPara(metaData, backupPara);
87 if (!initPara) {
88 return;
89 }
90
91 DistributedDB::KvStoreNbDelegate::Option dbOption;
92 dbOption.createIfNecessary = false;
93 dbOption.isEncryptedDb = backupPara.password.GetSize() > 0;
94 dbOption.passwd = backupPara.password;
95 dbOption.createDirByStoreIdOnly = true;
96 dbOption.secOption = KvStoreAppManager::ConvertSecurity(metaData.kvStoreMetaData.securityLevel);
97
98 auto *delegateMgr = new DistributedDB::KvStoreDelegateManager(metaData.kvStoreMetaData.appId,
99 AccountDelegate::GetInstance()->GetCurrentAccountId(metaData.kvStoreMetaData.bundleName));
100
101 std::string appDataStoragePath = KvStoreAppManager::GetDataStoragePath(metaData.kvStoreMetaData.deviceAccountId,
102 metaData.kvStoreMetaData.bundleName, backupPara.pathType);
103 DistributedDB::KvStoreConfig kvStoreConfig = {appDataStoragePath};
104 delegateMgr->SetKvStoreConfig(kvStoreConfig);
105 std::function<void(DistributedDB::DBStatus, DistributedDB::KvStoreNbDelegate *)> fun =
106 [&](DistributedDB::DBStatus status, DistributedDB::KvStoreNbDelegate *delegate) {
107 auto del = std::shared_ptr<DistributedDB::KvStoreDelegateManager>(delegateMgr);
108 if (delegate == nullptr) {
109 ZLOGE("SingleKvStoreBackup delegate is null");
110 return;
111 }
112 if (metaData.kvStoreMetaData.isAutoSync) {
113 bool autoSync = true;
114 DistributedDB::PragmaData data = static_cast<DistributedDB::PragmaData>(&autoSync);
115 auto pragmaStatus = delegate->Pragma(DistributedDB::PragmaCmd::AUTO_SYNC, data);
116 if (pragmaStatus != DistributedDB::DBStatus::OK) {
117 ZLOGE("pragmaStatus: %d", static_cast<int>(pragmaStatus));
118 }
119 }
120 ZLOGW("SingleKvStoreBackup export");
121 if (status == DistributedDB::DBStatus::OK) {
122 auto backupFullName = backupPara.backupFullName;
123 auto backupBackFullName = backupPara.backupBackFullName;
124 RenameFile(backupFullName, backupBackFullName);
125 status = delegate->Export(backupFullName, dbOption.passwd);
126 if (status == DistributedDB::DBStatus::OK) {
127 ZLOGD("SingleKvStoreBackup export success.");
128 RemoveFile(backupBackFullName);
129 } else {
130 ZLOGE("SingleKvStoreBackup export failed, status is %d.", status);
131 RenameFile(backupBackFullName, backupFullName);
132 }
133 }
134 del->CloseKvStore(delegate);
135 };
136 delegateMgr->GetKvStore(metaData.kvStoreMetaData.storeId, dbOption, fun);
137 }
138
MultiKvStoreBackup(const MetaData & metaData)139 void BackupHandler::MultiKvStoreBackup(const MetaData &metaData)
140 {
141 ZLOGI("MultiKvStoreBackup start.");
142 BackupPara backupPara;
143 auto initPara = InitBackupPara(metaData, backupPara);
144 if (!initPara) {
145 return;
146 }
147
148 DistributedDB::KvStoreDelegate::Option option;
149 option.createIfNecessary = false;
150 option.isEncryptedDb = backupPara.password.GetSize() > 0;
151 option.passwd = backupPara.password;
152 option.createDirByStoreIdOnly = true;
153
154 auto *delegateMgr = new DistributedDB::KvStoreDelegateManager(metaData.kvStoreMetaData.appId,
155 AccountDelegate::GetInstance()->GetCurrentAccountId(metaData.kvStoreMetaData.bundleName));
156 std::string appDataStoragePath = KvStoreAppManager::GetDataStoragePath(metaData.kvStoreMetaData.deviceAccountId,
157 metaData.kvStoreMetaData.bundleName, backupPara.pathType);
158 DistributedDB::KvStoreConfig kvStoreConfig;
159 kvStoreConfig.dataDir = appDataStoragePath;
160 delegateMgr->SetKvStoreConfig(kvStoreConfig);
161 std::function<void(DistributedDB::DBStatus, DistributedDB::KvStoreDelegate *)> fun =
162 [&](DistributedDB::DBStatus status, DistributedDB::KvStoreDelegate *delegate) {
163 auto del = std::shared_ptr<DistributedDB::KvStoreDelegateManager>(delegateMgr);
164 if (delegate == nullptr) {
165 ZLOGE("MultiKvStoreBackup delegate is null");
166 return;
167 }
168 ZLOGW("MultiKvStoreBackup export");
169 if (status == DistributedDB::DBStatus::OK) {
170 auto backupFullName = backupPara.backupFullName;
171 auto backupBackFullName = backupPara.backupBackFullName;
172
173 RenameFile(backupFullName, backupBackFullName);
174 status = delegate->Export(backupFullName, option.passwd);
175 if (status == DistributedDB::DBStatus::OK) {
176 ZLOGD("MultiKvStoreBackup export success.");
177 RemoveFile(backupBackFullName);
178 ZLOGD("MultiKvStoreBackup export success.");
179 } else {
180 ZLOGE("MultiKvStoreBackup export failed.");
181 RenameFile(backupBackFullName, backupFullName);
182 }
183 }
184 del->CloseKvStore(delegate);
185 };
186 delegateMgr->GetKvStore(metaData.kvStoreMetaData.storeId, option, fun);
187 }
188
InitBackupPara(const MetaData & metaData,BackupPara & backupPara)189 bool BackupHandler::InitBackupPara(const MetaData &metaData, BackupPara &backupPara)
190 {
191 BackupPara backupParameter;
192 auto pathType = KvStoreAppManager::ConvertPathType(
193 metaData.kvStoreMetaData.uid, metaData.kvStoreMetaData.bundleName, metaData.kvStoreMetaData.securityLevel);
194 if (!ForceCreateDirectory(BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType))) {
195 ZLOGE("MultiKvStoreBackup backup create directory failed.");
196 return false;
197 }
198
199 DistributedDB::CipherPassword password;
200 const std::vector<uint8_t> &secretKey = metaData.secretKeyMetaData.secretKey;
201 if (password.SetValue(secretKey.data(), secretKey.size()) != DistributedDB::CipherPassword::OK) {
202 ZLOGE("Set secret key value failed. len is (%d)", int32_t(secretKey.size()));
203 return false;
204 }
205
206 std::initializer_list<std::string> backList = {metaData.kvStoreMetaData.userId, "_",
207 metaData.kvStoreMetaData.appId, "_", metaData.kvStoreMetaData.storeId};
208 std::string backupName = Constant::Concatenate(backList);
209 std::initializer_list<std::string> backFullList = {
210 BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType), "/",
211 GetHashedBackupName(backupName)};
212 auto backupFullName = Constant::Concatenate(backFullList);
213 std::initializer_list<std::string> backNameList = {backupFullName, ".", "backup"};
214 auto backupBackFullName = Constant::Concatenate(backNameList);
215
216 backupParameter.pathType = pathType;
217 backupParameter.password = password;
218 backupParameter.backupFullName = backupFullName;
219 backupParameter.backupBackFullName = backupBackFullName;
220 backupPara = backupParameter;
221
222 return true;
223 }
224
SingleKvStoreRecover(MetaData & metaData,DistributedDB::KvStoreNbDelegate * delegate)225 bool BackupHandler::SingleKvStoreRecover(MetaData &metaData, DistributedDB::KvStoreNbDelegate *delegate)
226 {
227 ZLOGI("start.");
228 if (delegate == nullptr) {
229 ZLOGE("SingleKvStoreRecover failed, delegate is null.");
230 return false;
231 }
232 auto pathType = KvStoreAppManager::ConvertPathType(
233 metaData.kvStoreMetaData.uid, metaData.kvStoreMetaData.bundleName, metaData.kvStoreMetaData.securityLevel);
234 if (!BackupHandler::FileExists(BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType))) {
235 ZLOGE("SingleKvStoreRecover failed, backupDir_ file is not exist.");
236 return false;
237 }
238
239 DistributedDB::CipherPassword password;
240 const std::vector<uint8_t> &secretKey = metaData.secretKeyMetaData.secretKey;
241 if (password.SetValue(secretKey.data(), secretKey.size()) != DistributedDB::CipherPassword::OK) {
242 ZLOGE("Set secret key failed.");
243 return false;
244 }
245
246 std::string backupName = Constant::Concatenate(
247 {metaData.kvStoreMetaData.userId, "_", metaData.kvStoreMetaData.appId, "_",
248 metaData.kvStoreMetaData.storeId});
249 auto backupFullName = Constant::Concatenate({
250 BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType), "/",
251 GetHashedBackupName(backupName)
252 });
253 DistributedDB::DBStatus dbStatus = delegate->Import(backupFullName, password);
254 if (dbStatus == DistributedDB::DBStatus::OK) {
255 ZLOGI("SingleKvStoreRecover success.");
256 return true;
257 }
258 ZLOGI("SingleKvStoreRecover failed.");
259 return false;
260 }
261
MultiKvStoreRecover(MetaData & metaData,DistributedDB::KvStoreDelegate * delegate)262 bool BackupHandler::MultiKvStoreRecover(MetaData &metaData,
263 DistributedDB::KvStoreDelegate *delegate)
264 {
265 ZLOGI("start.");
266 if (delegate == nullptr) {
267 ZLOGE("MultiKvStoreRecover failed, delegate is null.");
268 return false;
269 }
270 auto pathType = KvStoreAppManager::ConvertPathType(
271 metaData.kvStoreMetaData.uid, metaData.kvStoreMetaData.bundleName, metaData.kvStoreMetaData.securityLevel);
272 if (!BackupHandler::FileExists(BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType))) {
273 ZLOGE("MultiKvStoreRecover failed, backupDir_ file is not exist.");
274 return false;
275 }
276
277 ZLOGI("MultiKvStoreRecover start.");
278 DistributedDB::CipherPassword password;
279 const std::vector<uint8_t> &secretKey = metaData.secretKeyMetaData.secretKey;
280 if (password.SetValue(secretKey.data(), secretKey.size()) != DistributedDB::CipherPassword::OK) {
281 ZLOGE("Set secret key failed.");
282 return false;
283 }
284
285 std::string backupName = Constant::Concatenate(
286 {metaData.kvStoreMetaData.userId, "_", metaData.kvStoreMetaData.appId, "_",
287 metaData.kvStoreMetaData.storeId});
288 auto backupFullName = Constant::Concatenate({
289 BackupHandler::GetBackupPath(metaData.kvStoreMetaData.deviceAccountId, pathType), "/",
290 GetHashedBackupName(backupName)
291 });
292 DistributedDB::DBStatus dbStatus = delegate->Import(backupFullName, password);
293 if (dbStatus == DistributedDB::DBStatus::OK) {
294 ZLOGI("MultiKvStoreRecover success.");
295 return true;
296 }
297 ZLOGI("MultiKvStoreRecover failed.");
298 return false;
299 }
300
301 std::string BackupHandler::backupDirCe_;
302 std::string BackupHandler::backupDirDe_;
GetBackupPath(const std::string & deviceAccountId,int pathType)303 const std::string &BackupHandler::GetBackupPath(const std::string &deviceAccountId, int pathType)
304 {
305 if (pathType == KvStoreAppManager::PATH_DE) {
306 if (backupDirDe_.empty()) {
307 backupDirDe_ = Constant::Concatenate({ Constant::ROOT_PATH_DE, "/", Constant::SERVICE_NAME, "/",
308 deviceAccountId, "/", Constant::GetDefaultHarmonyAccountName(),
309 "/", "backup" });
310 }
311 return backupDirDe_;
312 } else {
313 if (backupDirCe_.empty()) {
314 backupDirCe_ = Constant::Concatenate({ Constant::ROOT_PATH_CE, "/", Constant::SERVICE_NAME, "/",
315 deviceAccountId, "/", Constant::GetDefaultHarmonyAccountName(),
316 "/", "backup" });
317 }
318 return backupDirCe_;
319 }
320 }
321
RenameFile(const std::string & oldPath,const std::string & newPath)322 bool BackupHandler::RenameFile(const std::string &oldPath, const std::string &newPath)
323 {
324 if (oldPath.empty() || newPath.empty()) {
325 ZLOGE("RenameFile failed: path is empty");
326 return false;
327 }
328 if (!RemoveFile(newPath)) {
329 ZLOGE("RenameFile failed: newPath file is already exist");
330 return false;
331 }
332 if (rename(oldPath.c_str(), newPath.c_str()) != 0) {
333 ZLOGE("RenameFile: rename error, errno[%d].", errno);
334 return false;
335 }
336 return true;
337 }
338
RemoveFile(const std::string & path)339 bool BackupHandler::RemoveFile(const std::string &path)
340 {
341 if (path.empty()) {
342 ZLOGI("RemoveFile: path is empty");
343 return true;
344 }
345
346 if (unlink(path.c_str()) != 0 && (errno != ENOENT)) {
347 ZLOGE("RemoveFile: failed to RemoveFile, errno[%d].", errno);
348 return false;
349 }
350 return true;
351 }
352
FileExists(const std::string & path)353 bool BackupHandler::FileExists(const std::string &path)
354 {
355 if (path.empty()) {
356 ZLOGI("FileExists: path is empty");
357 return false;
358 }
359
360 if (access(path.c_str(), F_OK) != 0) {
361 ZLOGI("FileExists: file is not exist");
362 return false;
363 }
364 return true;
365 }
366
CheckNeedBackup()367 bool BackupHandler::CheckNeedBackup()
368 {
369 auto &batterySrvClient = PowerMgr::BatterySrvClient::GetInstance();
370 auto chargingStatus = batterySrvClient.GetChargingStatus();
371 if (chargingStatus != PowerMgr::BatteryChargeState::CHARGE_STATE_ENABLE) {
372 if (chargingStatus != PowerMgr::BatteryChargeState::CHARGE_STATE_FULL) {
373 ZLOGE("the device is not in charge state, chargingStatus=%{public}d.", chargingStatus);
374 return false;
375 }
376 auto batteryPluggedType = batterySrvClient.GetPluggedType();
377 if (batteryPluggedType != PowerMgr::BatteryPluggedType::PLUGGED_TYPE_AC &&
378 batteryPluggedType != PowerMgr::BatteryPluggedType::PLUGGED_TYPE_USB &&
379 batteryPluggedType != PowerMgr::BatteryPluggedType::PLUGGED_TYPE_WIRELESS) {
380 ZLOGE("the device is not in charge full statue, the batteryPluggedType is %{public}d.", batteryPluggedType);
381 return false;
382 }
383 }
384 auto &powerMgrClient = PowerMgr::PowerMgrClient::GetInstance();
385 if (powerMgrClient.IsScreenOn()) {
386 ZLOGE("the device screen is on.");
387 return false;
388 }
389 int64_t currentTime = TimeUtils::CurrentTimeMicros();
390 if (currentTime - backupSuccessTime_ < 36000000 && backupSuccessTime_ > 0) { // 36000000 is 10 hours
391 ZLOGE("no more than 10 hours since the last backup success.");
392 return false;
393 }
394 return true;
395 }
396
GetHashedBackupName(const std::string & bundleName)397 std::string BackupHandler::GetHashedBackupName(const std::string &bundleName)
398 {
399 if (bundleName.empty()) {
400 return bundleName;
401 }
402 return DistributedData::Crypto::Sha256(bundleName);
403 }
404 } // namespace OHOS::DistributedKv
405