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 "ObjectAssetMachine"
17 #include "object_asset_machine.h"
18
19 #include <utility>
20 #include <utils/anonymous.h>
21
22 #include "cloud/change_event.h"
23 #include "device_manager_adapter.h"
24 #include "eventcenter/event_center.h"
25 #include "log_print.h"
26 #include "metadata/meta_data_manager.h"
27 #include "object_asset_loader.h"
28 #include "snapshot/bind_event.h"
29 #include "store/auto_cache.h"
30 #include "utils/anonymous.h"
31
32 namespace OHOS {
33 namespace DistributedObject {
34 using namespace OHOS::DistributedData;
35 using namespace OHOS::DistributedRdb;
36 using DmAdapter = OHOS::DistributedData::DeviceManagerAdapter;
37
38 constexpr static const char* SQL_AND = " = ? and ";
39 constexpr static const int32_t AND_SIZE = 5;
40 static int32_t DoTransfer(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
41 const std::pair<std::string, Asset>& newAsset);
42
43 static int32_t ChangeAssetToNormal(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
44 const std::pair<std::string, Asset>& newAsset);
45
46 static int32_t CompensateSync(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
47 const std::pair<std::string, Asset>& newAsset);
48
49 static int32_t CompensateTransferring(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
50 const std::pair<std::string, Asset>& newAsset);
51
52 static int32_t SaveNewAsset(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
53 const std::pair<std::string, Asset>& newAsset);
54
55 static int32_t Recover(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
56 const std::pair<std::string, Asset>& newAsset);
57
58 static int32_t UpdateStore(ChangedAssetInfo& changedAsset);
59
60 static AutoCache::Store GetStore(const ChangedAssetInfo& changedAsset);
61 static VBuckets GetMigratedData(AutoCache::Store& store, AssetBindInfo& assetBindInfo, const Asset& newAsset);
62 static void MergeAssetData(VBucket& record, const Asset& newAsset, const AssetBindInfo& assetBindInfo);
63 static void MergeAsset(Asset& oldAsset, const Asset& newAsset);
64 static std::string BuildSql(const AssetBindInfo& bindInfo, Values& args);
65 static BindEvent::BindEventInfo MakeBindInfo(const ChangedAssetInfo& changedAsset);
66
67 static const DFAAction AssetDFA[STATUS_BUTT][EVENT_BUTT] = {
68 {
69 // STATUS_STABLE
70 { STATUS_TRANSFERRING, nullptr, (Action)DoTransfer }, // remote_changed
71 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // transfer_finished
72 { STATUS_UPLOADING, nullptr, nullptr }, // upload
73 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
74 { STATUS_DOWNLOADING, nullptr, nullptr }, // download
75 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
76 },
77 {
78 // TRANSFERRING
79 { STATUS_WAIT_TRANSFER, nullptr, (Action)SaveNewAsset }, // remote_changed
80 { STATUS_STABLE, nullptr, nullptr }, // transfer_finished
81 { STATUS_WAIT_UPLOAD, nullptr, (Action)ChangeAssetToNormal }, // upload
82 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
83 { STATUS_WAIT_DOWNLOAD, nullptr, (Action)ChangeAssetToNormal }, // download
84 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
85 },
86 {
87 // DOWNLOADING
88 { STATUS_WAIT_TRANSFER, nullptr, (Action)SaveNewAsset }, // remote_changed
89 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // transfer_finished
90 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload
91 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
92 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // download
93 { STATUS_STABLE, nullptr, nullptr }, // download_finished
94 },
95 {
96 // STATUS_UPLOADING
97 { STATUS_WAIT_TRANSFER, nullptr, (Action)SaveNewAsset }, // remote_changed
98 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // transfer_finished
99 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload
100 { STATUS_STABLE, nullptr, nullptr }, // upload_finished
101 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // download
102 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // download_finished
103 },
104 {
105 // STATUS_WAIT_TRANSFER
106 { STATUS_WAIT_TRANSFER, nullptr, (Action)SaveNewAsset }, // remote_changed
107 { STATUS_STABLE, nullptr, (Action)CompensateTransferring }, // transfer_finished
108 { STATUS_WAIT_UPLOAD, nullptr, (Action)ChangeAssetToNormal }, // upload
109 { STATUS_STABLE, nullptr, (Action)CompensateTransferring }, // upload_finished
110 { STATUS_WAIT_DOWNLOAD, nullptr, (Action)ChangeAssetToNormal }, // download
111 { STATUS_STABLE, nullptr, (Action)CompensateTransferring }, // download_finished
112 },
113 {
114 // STATUS_WAIT_UPLOAD
115 { STATUS_WAIT_TRANSFER, nullptr, (Action)SaveNewAsset }, // remote_changed
116 { STATUS_STABLE, nullptr, (Action)CompensateSync }, // transfer_finished
117 { STATUS_WAIT_UPLOAD, nullptr, (Action)ChangeAssetToNormal }, // upload
118 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
119 { STATUS_WAIT_DOWNLOAD, nullptr, (Action)ChangeAssetToNormal }, // download
120 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // download_finished
121 },
122 {
123 // STATUS_WAIT_DOWNLOAD
124 { STATUS_WAIT_TRANSFER, nullptr, (Action)SaveNewAsset }, // remote_changed
125 { STATUS_STABLE, nullptr, (Action)CompensateSync }, // transfer_finished
126 { STATUS_WAIT_UPLOAD, nullptr, (Action)ChangeAssetToNormal }, // upload
127 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // upload_finished
128 { STATUS_WAIT_DOWNLOAD, nullptr, (Action)ChangeAssetToNormal }, // download
129 { STATUS_NO_CHANGE, nullptr, (Action)Recover }, // download_finished
130 }
131 };
132
DFAPostEvent(AssetEvent eventId,ChangedAssetInfo & changedAssetInfo,Asset & asset,const std::pair<std::string,Asset> & newAsset)133 int32_t ObjectAssetMachine::DFAPostEvent(AssetEvent eventId, ChangedAssetInfo& changedAssetInfo, Asset& asset,
134 const std::pair<std::string, Asset>& newAsset)
135 {
136 if (eventId < 0 || eventId >= EVENT_BUTT || changedAssetInfo.status >= STATUS_BUTT) {
137 ZLOGE("invalid parameters, eventId: %{public}d, status:%{public}d", eventId, changedAssetInfo.status);
138 return GeneralError::E_ERROR;
139 }
140
141 const DFAAction* action = &AssetDFA[changedAssetInfo.status][eventId];
142 if (action->before != nullptr) {
143 int32_t res = action->before(eventId, changedAssetInfo, asset, newAsset);
144 if (res != GeneralError::E_OK) {
145 return GeneralError::E_ERROR;
146 }
147 }
148 if (action->next != STATUS_NO_CHANGE) {
149 ZLOGI("status before:%{public}d, eventId: %{public}d, status after:%{public}d", changedAssetInfo.status,
150 eventId, action->next);
151 changedAssetInfo.status = static_cast<TransferStatus>(action->next);
152 }
153 if (action->after != nullptr) {
154 int32_t res = action->after(eventId, changedAssetInfo, asset, newAsset);
155 if (res != GeneralError::E_OK) {
156 return GeneralError::E_ERROR;
157 }
158 }
159 return GeneralError::E_OK;
160 }
161
DoTransfer(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)162 static int32_t DoTransfer(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
163 const std::pair<std::string, Asset>& newAsset)
164 {
165 changedAsset.deviceId = newAsset.first;
166 changedAsset.asset = newAsset.second;
167 std::vector<Asset> assets{ changedAsset.asset };
168 ObjectAssetLoader::GetInstance().TransferAssetsAsync(changedAsset.storeInfo.user,
169 changedAsset.storeInfo.bundleName, changedAsset.deviceId, assets, [&changedAsset](bool success) {
170 if (success) {
171 auto status = UpdateStore(changedAsset);
172 if (status != E_OK) {
173 ZLOGE("UpdateStore error, error:%{public}d, assetName:%{public}s, store:%{public}s, "
174 "table:%{public}s",
175 status, Anonymous::Change(changedAsset.asset.name).c_str(),
176 Anonymous::Change(changedAsset.bindInfo.storeName).c_str(),
177 Anonymous::Change(changedAsset.bindInfo.tableName).c_str());
178 }
179 }
180 ObjectAssetMachine::DFAPostEvent(TRANSFER_FINISHED, changedAsset, changedAsset.asset);
181 });
182 return E_OK;
183 }
184
UpdateStore(ChangedAssetInfo & changedAsset)185 static int32_t UpdateStore(ChangedAssetInfo& changedAsset)
186 {
187 auto store = GetStore(changedAsset);
188 if (store == nullptr) {
189 ZLOGE("store null, storeId:%{public}s", Anonymous::Change(changedAsset.bindInfo.storeName).c_str());
190 return E_ERROR;
191 }
192
193 VBuckets vBuckets = GetMigratedData(store, changedAsset.bindInfo, changedAsset.asset);
194 if (vBuckets.empty()) {
195 return E_OK;
196 }
197 return store->MergeMigratedData(changedAsset.bindInfo.tableName, std::move(vBuckets));
198 }
199
GetMigratedData(AutoCache::Store & store,AssetBindInfo & assetBindInfo,const Asset & newAsset)200 static VBuckets GetMigratedData(AutoCache::Store& store, AssetBindInfo& assetBindInfo, const Asset& newAsset)
201 {
202 Values args;
203 VBuckets vBuckets;
204 auto sql = BuildSql(assetBindInfo, args);
205 auto [errCode, cursor] = store->Query(assetBindInfo.tableName, sql, std::move(args));
206 if (errCode != E_OK || cursor == nullptr) {
207 return vBuckets;
208 }
209 int32_t count = cursor->GetCount();
210 if (count != 1) {
211 return vBuckets;
212 }
213 vBuckets.reserve(count);
214 auto err = cursor->MoveToFirst();
215 while (err == E_OK && count > 0) {
216 VBucket entry;
217 err = cursor->GetRow(entry);
218 if (err != E_OK) {
219 return vBuckets;
220 }
221 MergeAssetData(entry, newAsset, assetBindInfo);
222 vBuckets.emplace_back(std::move(entry));
223 err = cursor->MoveToNext();
224 count--;
225 }
226 return vBuckets;
227 }
228
BuildSql(const AssetBindInfo & bindInfo,Values & args)229 static std::string BuildSql(const AssetBindInfo& bindInfo, Values& args)
230 {
231 std::string sql;
232 sql.append("SELECT ").append(bindInfo.field).append(" FROM ").append(bindInfo.tableName).append(" WHERE ");
233 for (auto const& [key, value] : bindInfo.primaryKey) {
234 sql.append(key).append(SQL_AND);
235 args.emplace_back(value);
236 }
237 sql = sql.substr(0, sql.size() - AND_SIZE);
238 return sql;
239 }
240
MergeAssetData(VBucket & record,const Asset & newAsset,const AssetBindInfo & assetBindInfo)241 static void MergeAssetData(VBucket& record, const Asset& newAsset, const AssetBindInfo& assetBindInfo)
242 {
243 for (auto const& [key, primary] : assetBindInfo.primaryKey) {
244 record[key] = primary;
245 }
246
247 auto it = record.find(assetBindInfo.field);
248 if (it == record.end()) {
249 ZLOGD("Not find field:%{public}s in store", assetBindInfo.field.c_str());
250 return;
251 }
252
253 auto& value = it->second;
254 if (value.index() == TYPE_INDEX<std::monostate>) {
255 Assets assets{ newAsset };
256 value = assets;
257 return;
258 }
259 if (value.index() == TYPE_INDEX<DistributedData::Asset>) {
260 auto* asset = Traits::get_if<DistributedData::Asset>(&value);
261 if (asset->name != newAsset.name) {
262 ZLOGD("Asset not same, old uri: %{public}s, new uri: %{public}s",
263 Anonymous::Change(asset->uri).c_str(), Anonymous::Change(newAsset.uri).c_str());
264 return;
265 }
266 }
267
268 if (value.index() == TYPE_INDEX<DistributedData::Assets>) {
269 auto* assets = Traits::get_if<DistributedData::Assets>(&value);
270 for (auto& asset : *assets) {
271 if (asset.name == newAsset.name) {
272 MergeAsset(asset, newAsset);
273 return;
274 }
275 }
276 assets->emplace_back(newAsset);
277 }
278 }
279
MergeAsset(Asset & oldAsset,const Asset & newAsset)280 static void MergeAsset(Asset& oldAsset, const Asset& newAsset)
281 {
282 oldAsset.name = newAsset.name;
283 oldAsset.uri = newAsset.uri;
284 oldAsset.modifyTime = newAsset.modifyTime;
285 oldAsset.createTime = newAsset.createTime;
286 oldAsset.size = newAsset.size;
287 oldAsset.hash = newAsset.hash;
288 oldAsset.path = newAsset.path;
289 }
290
GetStore(const ChangedAssetInfo & changedAsset)291 static AutoCache::Store GetStore(const ChangedAssetInfo& changedAsset)
292 {
293 StoreMetaData meta;
294 meta.storeId = changedAsset.bindInfo.storeName;
295 meta.bundleName = changedAsset.storeInfo.bundleName;
296 meta.user = std::to_string(changedAsset.storeInfo.user);
297 meta.instanceId = changedAsset.storeInfo.instanceId;
298 meta.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid;
299 if (!MetaDataManager::GetInstance().LoadMeta(meta.GetKeyWithoutPath(), meta)) {
300 ZLOGE("meta empty, bundleName:%{public}s, storeId:%{public}s", meta.bundleName.c_str(),
301 meta.GetStoreAlias().c_str());
302 return nullptr;
303 }
304 return AutoCache::GetInstance().GetStore(meta, {});
305 }
306
CompensateTransferring(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)307 static int32_t CompensateTransferring(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
308 const std::pair<std::string, Asset>& newAsset)
309 {
310 std::pair<std::string, Asset> newChangedAsset{ changedAsset.deviceId, changedAsset.asset };
311 return ObjectAssetMachine::DFAPostEvent(REMOTE_CHANGED, changedAsset, changedAsset.asset, newChangedAsset);
312 }
313
CompensateSync(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)314 static int32_t CompensateSync(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
315 const std::pair<std::string, Asset>& newAsset)
316 {
317 BindEvent::BindEventInfo bindEventInfo = MakeBindInfo(changedAsset);
318 auto evt = std::make_unique<BindEvent>(BindEvent::COMPENSATE_SYNC, std::move(bindEventInfo));
319 EventCenter::GetInstance().PostEvent(std::move(evt));
320 return E_OK;
321 }
322
SaveNewAsset(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)323 static int32_t SaveNewAsset(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
324 const std::pair<std::string, Asset>& newAsset)
325 {
326 changedAsset.deviceId = newAsset.first;
327 changedAsset.asset = newAsset.second;
328 return E_OK;
329 }
330
ChangeAssetToNormal(int32_t eventId,ChangedAssetInfo & changedAssetInfo,Asset & asset,const std::pair<std::string,Asset> & newAsset)331 static int32_t ChangeAssetToNormal(int32_t eventId, ChangedAssetInfo& changedAssetInfo, Asset& asset,
332 const std::pair<std::string, Asset>& newAsset)
333 {
334 asset.status = Asset::STATUS_NORMAL;
335 return E_OK;
336 }
337
Recover(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)338 static int32_t Recover(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
339 const std::pair<std::string, Asset>& newAsset)
340 {
341 ZLOGI("An abnormal event has occurred, eventId:%{public}d, status:%{public}d, assetName:%{public}s", eventId,
342 changedAsset.status, Anonymous::Change(changedAsset.asset.name).c_str());
343
344 BindEvent::BindEventInfo bindEventInfo = MakeBindInfo(changedAsset);
345 changedAsset.status = TransferStatus::STATUS_STABLE;
346 auto evt = std::make_unique<BindEvent>(BindEvent::RECOVER_SYNC, std::move(bindEventInfo));
347 EventCenter::GetInstance().PostEvent(std::move(evt));
348 return E_OK;
349 }
350
MakeBindInfo(const ChangedAssetInfo & changedAsset)351 static BindEvent::BindEventInfo MakeBindInfo(const ChangedAssetInfo& changedAsset)
352 {
353 BindEvent::BindEventInfo bindEventInfo;
354 bindEventInfo.bundleName = changedAsset.storeInfo.bundleName;
355 bindEventInfo.user = changedAsset.storeInfo.user;
356 bindEventInfo.tokenId = changedAsset.storeInfo.tokenId;
357 bindEventInfo.instanceId = changedAsset.storeInfo.instanceId;
358 bindEventInfo.storeName = changedAsset.bindInfo.storeName;
359 bindEventInfo.tableName = changedAsset.bindInfo.tableName;
360 bindEventInfo.filed = changedAsset.bindInfo.field;
361 bindEventInfo.primaryKey = changedAsset.bindInfo.primaryKey;
362 bindEventInfo.assetName = changedAsset.bindInfo.assetName;
363 return bindEventInfo;
364 }
365 } // namespace DistributedObject
366 } // namespace OHOS
367