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