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
16 #define LOG_TAG "CloudServiceImpl"
17
18 #include "cloud_service_impl.h"
19 #include "accesstoken_kit.h"
20 #include "account/account_delegate.h"
21 #include "checker/checker_manager.h"
22 #include "cloud/cloud_server.h"
23 #include "communicator/device_manager_adapter.h"
24 #include "device_manager_adapter.h"
25 #include "eventcenter/event_center.h"
26 #include "ipc_skeleton.h"
27 #include "log_print.h"
28 #include "metadata/meta_data_manager.h"
29 #include "rdb_cloud_data_translate.h"
30 #include "runtime_config.h"
31 #include "store/auto_cache.h"
32 #include "store/general_store.h"
33 #include "utils/anonymous.h"
34 #include "sync_manager.h"
35 namespace OHOS::CloudData {
36 using namespace DistributedData;
37 using namespace std::chrono;
38 using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter;
39 using Account = OHOS::DistributedKv::AccountDelegate;
40 using AccessTokenKit = Security::AccessToken::AccessTokenKit;
41 __attribute__((used)) CloudServiceImpl::Factory CloudServiceImpl::factory_;
42
Factory()43 CloudServiceImpl::Factory::Factory() noexcept
44 {
45 FeatureSystem::GetInstance().RegisterCreator(
46 CloudServiceImpl::SERVICE_NAME,
47 [this]() {
48 if (product_ == nullptr) {
49 product_ = std::make_shared<CloudServiceImpl>();
50 }
51 return product_;
52 },
53 FeatureSystem::BIND_NOW);
54 }
55
~Factory()56 CloudServiceImpl::Factory::~Factory() {}
57
CloudServiceImpl()58 CloudServiceImpl::CloudServiceImpl()
59 {
60 EventCenter::GetInstance().Subscribe(CloudEvent::GET_SCHEMA, [this](const Event &event) {
61 GetSchema(event);
62 });
63 }
64
EnableCloud(const std::string & id,const std::map<std::string,int32_t> & switches)65 int32_t CloudServiceImpl::EnableCloud(const std::string &id, const std::map<std::string, int32_t> &switches)
66 {
67 CloudInfo cloudInfo;
68 auto status = GetCloudInfo(IPCSkeleton::GetCallingTokenID(), id, cloudInfo);
69 if (status != SUCCESS) {
70 return status;
71 }
72 cloudInfo.enableCloud = true;
73 for (const auto &[bundle, value] : switches) {
74 if (!cloudInfo.Exist(bundle)) {
75 continue;
76 }
77 cloudInfo.apps[bundle].cloudSwitch = (value == SWITCH_ON);
78 }
79 if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) {
80 return ERROR;
81 }
82 Execute(GenTask(0, cloudInfo.user));
83 syncManager_.DoCloudSync({ cloudInfo.user });
84 return SUCCESS;
85 }
86
DisableCloud(const std::string & id)87 int32_t CloudServiceImpl::DisableCloud(const std::string &id)
88 {
89 CloudInfo cloudInfo;
90 auto status = GetCloudInfo(IPCSkeleton::GetCallingTokenID(), id, cloudInfo);
91 if (status != SUCCESS) {
92 return status;
93 }
94 cloudInfo.enableCloud = false;
95 if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) {
96 return ERROR;
97 }
98 Execute(GenTask(0, cloudInfo.user));
99 syncManager_.StopCloudSync(cloudInfo.user);
100 return SUCCESS;
101 }
102
ChangeAppSwitch(const std::string & id,const std::string & bundleName,int32_t appSwitch)103 int32_t CloudServiceImpl::ChangeAppSwitch(const std::string &id, const std::string &bundleName, int32_t appSwitch)
104 {
105 CloudInfo cloudInfo;
106 auto status = GetCloudInfo(IPCSkeleton::GetCallingTokenID(), id, cloudInfo);
107 if (status != SUCCESS) {
108 return status;
109 }
110 if (!cloudInfo.Exist(bundleName)) {
111 ZLOGE("bundleName:%{public}s", bundleName.c_str());
112 return INVALID_ARGUMENT;
113 }
114 cloudInfo.apps[bundleName].cloudSwitch = (appSwitch == SWITCH_ON);
115 if (!MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true)) {
116 return ERROR;
117 }
118 Execute(GenTask(0, cloudInfo.user, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB }));
119 if (cloudInfo.enableCloud && appSwitch == SWITCH_ON) {
120 syncManager_.DoCloudSync({ cloudInfo.user, bundleName });
121 }
122 return SUCCESS;
123 }
124
DoClean(CloudInfo & cloudInfo,const std::map<std::string,int32_t> & actions)125 int32_t CloudServiceImpl::DoClean(CloudInfo &cloudInfo, const std::map<std::string, int32_t> &actions)
126 {
127 syncManager_.StopCloudSync(cloudInfo.user);
128 auto keys = cloudInfo.GetSchemaKey();
129 for (const auto &[bundle, action] : actions) {
130 if (!cloudInfo.Exist(bundle)) {
131 continue;
132 }
133 SchemaMeta schemaMeta;
134 if (!MetaDataManager::GetInstance().LoadMeta(keys[bundle], schemaMeta, true)) {
135 ZLOGE("failed, no schema meta:bundleName:%{public}s", bundle.c_str());
136 return ERROR;
137 }
138 for (const auto &database : schemaMeta.databases) {
139 // action
140 StoreMetaData meta;
141 meta.bundleName = schemaMeta.bundleName;
142 meta.storeId = database.name;
143 meta.user = std::to_string(cloudInfo.user);
144 meta.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid;
145 meta.instanceId = cloudInfo.apps[bundle].instanceId;
146 if (!MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), meta)) {
147 ZLOGE("failed, no store meta bundleName:%{public}s, storeId:%{public}s", meta.bundleName.c_str(),
148 meta.GetStoreAlias().c_str());
149 continue;
150 }
151 AutoCache::Store store = SyncManager::GetStore(meta, cloudInfo.user, false);
152 if (store == nullptr) {
153 ZLOGE("store null, storeId:%{public}s", meta.GetStoreAlias().c_str());
154 return ERROR;
155 }
156 auto status = store->Clean({}, action, "");
157 if (status != E_OK) {
158 ZLOGW("remove device data status:%{public}d, user:%{pubilc}d, bundleName:%{public}s, "
159 "storeId:%{public}s",
160 status, static_cast<int>(cloudInfo.user), meta.bundleName.c_str(), meta.GetStoreAlias().c_str());
161 continue;
162 }
163 }
164 }
165 return SUCCESS;
166 }
167
Clean(const std::string & id,const std::map<std::string,int32_t> & actions)168 int32_t CloudServiceImpl::Clean(const std::string &id, const std::map<std::string, int32_t> &actions)
169 {
170 CloudInfo cloudInfo;
171 auto tokenId = IPCSkeleton::GetCallingTokenID();
172 cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId);
173 if (GetCloudInfoFromMeta(cloudInfo) != SUCCESS) {
174 ZLOGE("get cloud meta failed user:%{public}d", static_cast<int>(cloudInfo.user));
175 return ERROR;
176 }
177 if (id != cloudInfo.id) {
178 ZLOGE("different id, [server] id:%{public}s, [meta] id:%{public}s", Anonymous::Change(cloudInfo.id).c_str(),
179 Anonymous::Change(id).c_str());
180 }
181 return DoClean(cloudInfo, actions);
182 }
183
NotifyDataChange(const std::string & id,const std::string & bundleName)184 int32_t CloudServiceImpl::NotifyDataChange(const std::string &id, const std::string &bundleName)
185 {
186 CloudInfo cloudInfo;
187 auto tokenId = IPCSkeleton::GetCallingTokenID();
188 cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId);
189 if (GetCloudInfoFromMeta(cloudInfo) != SUCCESS) {
190 return ERROR;
191 }
192 if (cloudInfo.id != id) {
193 ZLOGE("invalid args, [input] id:%{public}s, [meta] id:%{public}s", Anonymous::Change(id).c_str(),
194 Anonymous::Change(cloudInfo.id).c_str());
195 return INVALID_ARGUMENT;
196 }
197 if (!cloudInfo.enableCloud) {
198 return CLOUD_DISABLE;
199 }
200 if (!cloudInfo.Exist(bundleName)) {
201 ZLOGE("bundleName:%{public}s", bundleName.c_str());
202 return INVALID_ARGUMENT;
203 }
204 if (!cloudInfo.apps[bundleName].cloudSwitch) {
205 return CLOUD_DISABLE_SWITCH;
206 }
207 syncManager_.DoCloudSync(SyncManager::SyncInfo(cloudInfo.user, bundleName));
208 return SUCCESS;
209 }
210
OnInitialize()211 int32_t CloudServiceImpl::OnInitialize()
212 {
213 DistributedDB::RuntimeConfig::SetCloudTranslate(std::make_shared<DistributedRdb::RdbCloudDataTranslate>());
214 Execute(GenTask(0, 0, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB }));
215 return E_OK;
216 }
217
OnBind(const BindInfo & info)218 int32_t CloudServiceImpl::OnBind(const BindInfo &info)
219 {
220 if (executor_ != nullptr || info.executors == nullptr) {
221 return E_INVALID_ARGS;
222 }
223
224 executor_ = std::move(info.executors);
225 syncManager_.Bind(executor_);
226 return E_OK;
227 }
228
OnUserChange(uint32_t code,const std::string & user,const std::string & account)229 int32_t CloudServiceImpl::OnUserChange(uint32_t code, const std::string &user, const std::string &account)
230 {
231 int32_t userId = atoi(user.c_str());
232 if (code == static_cast<uint32_t>(DistributedKv::AccountStatus::DEVICE_ACCOUNT_SWITCHED)) {
233 Execute(GenTask(0, userId, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB }));
234 }
235 syncManager_.StopCloudSync(userId);
236 return E_OK;
237 }
238
Online(const std::string & device)239 int32_t CloudServiceImpl::Online(const std::string &device)
240 {
241 if (device != DeviceManagerAdapter::CLOUD_DEVICE_UUID) {
242 ZLOGI("Not network online");
243 return SUCCESS;
244 }
245 std::vector<int32_t> users;
246 Account::GetInstance()->QueryUsers(users);
247 if (users.empty()) {
248 return SUCCESS;
249 }
250 auto it = users.begin();
251 syncManager_.DoCloudSync({ *it });
252 Execute(GenTask(0, *it, { WORK_CLOUD_INFO_UPDATE, WORK_SCHEMA_UPDATE, WORK_SUB }));
253 return SUCCESS;
254 }
255
Offline(const std::string & device)256 int32_t CloudServiceImpl::Offline(const std::string &device)
257 {
258 if (device != DeviceManagerAdapter::CLOUD_DEVICE_UUID) {
259 ZLOGI("Not network offline");
260 return SUCCESS;
261 }
262 std::vector<int32_t> users;
263 Account::GetInstance()->QueryUsers(users);
264 if (users.empty()) {
265 return SUCCESS;
266 }
267 auto it = users.begin();
268 syncManager_.StopCloudSync(*it);
269 return SUCCESS;
270 }
271
GetCloudInfo(uint32_t tokenId,const std::string & id,CloudInfo & cloudInfo)272 int32_t CloudServiceImpl::GetCloudInfo(uint32_t tokenId, const std::string &id, CloudInfo &cloudInfo)
273 {
274 cloudInfo.user = DistributedKv::AccountDelegate::GetInstance()->GetUserByToken(tokenId);
275 if (GetCloudInfoFromMeta(cloudInfo) != SUCCESS) {
276 auto status = GetCloudInfoFromServer(cloudInfo);
277 if (status != SUCCESS) {
278 ZLOGE("user:%{public}d", cloudInfo.user);
279 return status;
280 }
281 }
282 if (cloudInfo.id != id) {
283 ZLOGE("invalid args, [input] id:%{public}s, [exist] id:%{public}s", Anonymous::Change(id).c_str(),
284 Anonymous::Change(cloudInfo.id).c_str());
285 return INVALID_ARGUMENT;
286 }
287 return SUCCESS;
288 }
289
GetCloudInfoFromMeta(CloudInfo & cloudInfo)290 int32_t CloudServiceImpl::GetCloudInfoFromMeta(CloudInfo &cloudInfo)
291 {
292 if (!MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), cloudInfo, true)) {
293 ZLOGE("no exist meta, user:%{public}d", cloudInfo.user);
294 return ERROR;
295 }
296 return SUCCESS;
297 }
298
GetCloudInfoFromServer(CloudInfo & cloudInfo)299 int32_t CloudServiceImpl::GetCloudInfoFromServer(CloudInfo &cloudInfo)
300 {
301 auto instance = CloudServer::GetInstance();
302 if (instance == nullptr) {
303 return NOT_SUPPORT;
304 }
305 cloudInfo = instance->GetServerInfo(cloudInfo.user);
306 if (!cloudInfo.IsValid()) {
307 ZLOGE("cloud is empty, user%{public}d", cloudInfo.user);
308 return ERROR;
309 }
310 return SUCCESS;
311 }
312
UpdateCloudInfo(int32_t user)313 bool CloudServiceImpl::UpdateCloudInfo(int32_t user)
314 {
315 CloudInfo cloudInfo;
316 cloudInfo.user = user;
317 if (GetCloudInfoFromServer(cloudInfo) != SUCCESS) {
318 ZLOGE("failed, user:%{public}d", user);
319 return false;
320 }
321 CloudInfo oldInfo;
322 if (!MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), oldInfo, true)) {
323 MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true);
324 return true;
325 }
326 if (oldInfo.id != cloudInfo.id) {
327 ZLOGE("different id, [server] id:%{public}s, [meta] id:%{public}s", Anonymous::Change(cloudInfo.id).c_str(),
328 Anonymous::Change(oldInfo.id).c_str());
329 std::map<std::string, int32_t> actions;
330 for (auto &[bundle, app] : cloudInfo.apps) {
331 actions[bundle] = GeneralStore::CleanMode::CLOUD_INFO;
332 }
333 DoClean(oldInfo, actions);
334 }
335 if (cloudInfo.enableCloud) {
336 for (auto &[bundle, app] : cloudInfo.apps) {
337 if (app.cloudSwitch && !oldInfo.apps[bundle].cloudSwitch) {
338 syncManager_.DoCloudSync({ cloudInfo.user, bundle });
339 }
340 }
341 }
342 MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true);
343 return true;
344 }
345
UpdateSchema(int32_t user)346 bool CloudServiceImpl::UpdateSchema(int32_t user)
347 {
348 CloudInfo cloudInfo;
349 cloudInfo.user = user;
350 if (GetCloudInfoFromServer(cloudInfo) != SUCCESS) {
351 ZLOGE("failed, user:%{public}d", user);
352 return false;
353 }
354 auto keys = cloudInfo.GetSchemaKey();
355 for (const auto &[bundle, key] : keys) {
356 SchemaMeta schemaMeta;
357 if (MetaDataManager::GetInstance().LoadMeta(key, schemaMeta, true)) {
358 continue;
359 }
360 if (GetAppSchema(cloudInfo.user, bundle, schemaMeta) != SUCCESS) {
361 return false;
362 }
363 MetaDataManager::GetInstance().SaveMeta(key, schemaMeta, true);
364 }
365 return true;
366 }
367
GetAppSchema(int32_t user,const std::string & bundleName,SchemaMeta & schemaMeta)368 int32_t CloudServiceImpl::GetAppSchema(int32_t user, const std::string &bundleName, SchemaMeta &schemaMeta)
369 {
370 auto instance = CloudServer::GetInstance();
371 if (instance == nullptr) {
372 return SERVER_UNAVAILABLE;
373 }
374 schemaMeta = instance->GetAppSchema(user, bundleName);
375 return SUCCESS;
376 }
377
GenTask(int32_t retry,int32_t user,Handles handles)378 ExecutorPool::Task CloudServiceImpl::GenTask(int32_t retry, int32_t user, Handles handles)
379 {
380 return [this, retry, user, works = std::move(handles)]() mutable {
381 auto executor = executor_;
382 if (retry >= RETRY_TIMES || executor == nullptr || works.empty()) {
383 return;
384 }
385 if (!DmAdapter::GetInstance().IsNetworkAvailable()) {
386 return;
387 }
388 bool finished = true;
389 std::vector<int32_t> users;
390 if (user == 0) {
391 auto account = Account::GetInstance();
392 finished = !(account == nullptr) && account->QueryUsers(users);
393 } else {
394 users.push_back(user);
395 }
396
397 auto handle = works.front();
398 for (auto user : users) {
399 finished = (this->*handle)(user) && finished;
400 }
401 if (!finished || users.empty()) {
402 executor->Schedule(std::chrono::seconds(RETRY_INTERVAL), GenTask(retry + 1, user, std::move(works)));
403 return;
404 }
405 works.pop_front();
406 if (!works.empty()) {
407 executor->Execute(GenTask(retry, user, std::move(works)));
408 }
409 };
410 }
411
GetSchemaMeta(int32_t userId,const std::string & bundleName,int32_t instanceId)412 SchemaMeta CloudServiceImpl::GetSchemaMeta(int32_t userId, const std::string &bundleName, int32_t instanceId)
413 {
414 SchemaMeta schemaMeta;
415 CloudInfo cloudInfo = GetCloudInfo(userId);
416 if (!cloudInfo.IsValid()) {
417 // GetCloudInfo has print the log info. so we don`t need print again.
418 return schemaMeta;
419 }
420
421 if (!bundleName.empty() && !cloudInfo.Exist(bundleName, instanceId)) {
422 ZLOGD("bundleName:%{public}s instanceId:%{public}d is not exist", bundleName.c_str(), instanceId);
423 return schemaMeta;
424 }
425 std::string schemaKey = cloudInfo.GetSchemaKey(bundleName, instanceId);
426 if (MetaDataManager::GetInstance().LoadMeta(schemaKey, schemaMeta, true)) {
427 return schemaMeta;
428 }
429
430 auto instance = CloudServer::GetInstance();
431 if (instance == nullptr) {
432 return schemaMeta;
433 }
434 schemaMeta = instance->GetAppSchema(userId, bundleName);
435 if (!schemaMeta.IsValid()) {
436 ZLOGE("download schema from cloud failed, user:%{public}d, bundleName:%{public}s", userId, bundleName.c_str());
437 }
438 MetaDataManager::GetInstance().SaveMeta(schemaKey, schemaMeta, true);
439 return schemaMeta;
440 }
441
GetCloudInfo(int32_t userId)442 CloudInfo CloudServiceImpl::GetCloudInfo(int32_t userId)
443 {
444 CloudInfo cloudInfo;
445 cloudInfo.user = userId;
446 if (MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), cloudInfo, true)) {
447 return cloudInfo;
448 }
449 auto instance = CloudServer::GetInstance();
450 if (instance == nullptr) {
451 return cloudInfo;
452 }
453
454 cloudInfo = instance->GetServerInfo(userId);
455 if (!cloudInfo.IsValid()) {
456 ZLOGE("no cloud info %{public}d", userId);
457 return cloudInfo;
458 }
459
460 MetaDataManager::GetInstance().SaveMeta(cloudInfo.GetKey(), cloudInfo, true);
461 return cloudInfo;
462 }
463
OnAppUninstall(const std::string & bundleName,int32_t user,int32_t index)464 int32_t CloudServiceImpl::OnAppUninstall(
465 const std::string &bundleName, int32_t user, int32_t index)
466 {
467 MetaDataManager::GetInstance().DelMeta(Subscription::GetRelationKey(user, bundleName), true);
468 MetaDataManager::GetInstance().DelMeta(CloudInfo::GetSchemaKey(user, bundleName, index), true);
469 return E_OK;
470 }
471
GetSchema(const Event & event)472 void CloudServiceImpl::GetSchema(const Event &event)
473 {
474 auto &rdbEvent = static_cast<const CloudEvent &>(event);
475 auto &storeInfo = rdbEvent.GetStoreInfo();
476 ZLOGD("Start GetSchema, bundleName:%{public}s, storeName:%{public}s, instanceId:%{public}d",
477 storeInfo.bundleName.c_str(), Anonymous::Change(storeInfo.storeName).c_str(), storeInfo.instanceId);
478 GetSchemaMeta(storeInfo.user, storeInfo.bundleName, storeInfo.instanceId);
479 }
480
DoSubscribe(int32_t user)481 bool CloudServiceImpl::DoSubscribe(int32_t user)
482 {
483 Subscription sub;
484 sub.userId = user;
485 MetaDataManager::GetInstance().LoadMeta(sub.GetKey(), sub, true);
486 if (CloudServer::GetInstance() == nullptr) {
487 ZLOGI("not support cloud server");
488 return true;
489 }
490
491 CloudInfo cloudInfo;
492 cloudInfo.user = sub.userId;
493 auto exits = MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetKey(), cloudInfo, true);
494 if (!exits) {
495 ZLOGW("error, there is no cloud info for user(%{public}d)", sub.userId);
496 return false;
497 }
498
499 ZLOGD("begin cloud:%{public}d user:%{public}d apps:%{public}zu", cloudInfo.enableCloud, sub.userId,
500 cloudInfo.apps.size());
501 auto onThreshold = duration_cast<milliseconds>((system_clock::now() + hours(EXPIRE_INTERVAL)).time_since_epoch());
502 auto offThreshold = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
503 std::map<std::string, std::vector<SchemaMeta::Database>> subDbs;
504 std::map<std::string, std::vector<SchemaMeta::Database>> unsubDbs;
505 for (auto &[bundle, app] : cloudInfo.apps) {
506 auto enabled = cloudInfo.enableCloud && app.cloudSwitch;
507 auto &dbs = enabled ? subDbs : unsubDbs;
508 auto it = sub.expiresTime.find(bundle);
509 // cloud is enabled, but the subscription won't expire
510 if (enabled && (it != sub.expiresTime.end() && it->second >= static_cast<uint64_t>(onThreshold.count()))) {
511 continue;
512 }
513 // cloud is disabled, we don't care the subscription which was expired or didn't subscribe.
514 if (!enabled && (it == sub.expiresTime.end() || it->second <= static_cast<uint64_t>(offThreshold.count()))) {
515 continue;
516 }
517
518 SchemaMeta schemaMeta;
519 exits = MetaDataManager::GetInstance().LoadMeta(cloudInfo.GetSchemaKey(bundle), schemaMeta, true);
520 if (exits) {
521 dbs.insert_or_assign(bundle, std::move(schemaMeta.databases));
522 }
523 }
524
525 ZLOGI("cloud switch:%{public}d user%{public}d, sub:%{public}zu, unsub:%{public}zu", cloudInfo.enableCloud,
526 sub.userId, subDbs.size(), unsubDbs.size());
527 ZLOGD("Subscribe user%{public}d details:%{public}s", sub.userId, Serializable::Marshall(subDbs).c_str());
528 ZLOGD("Unsubscribe user%{public}d details:%{public}s", sub.userId, Serializable::Marshall(unsubDbs).c_str());
529 CloudServer::GetInstance()->Subscribe(sub.userId, subDbs);
530 CloudServer::GetInstance()->Unsubscribe(sub.userId, unsubDbs);
531 return subDbs.empty() && unsubDbs.empty();
532 }
533
Execute(Task task)534 void CloudServiceImpl::Execute(Task task)
535 {
536 auto executor = executor_;
537 if (executor == nullptr) {
538 return;
539 }
540 executor->Execute(std::move(task));
541 }
542 } // namespace OHOS::CloudData