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(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(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) {
137 return GeneralError::E_ERROR;
138 }
139
140 const DFAAction* action = &AssetDFA[changedAssetInfo.status][eventId];
141 if (action->before != nullptr) {
142 int32_t res = action->before(eventId, changedAssetInfo, asset, newAsset);
143 if (res != GeneralError::E_OK) {
144 return GeneralError::E_ERROR;
145 }
146 }
147 if (action->next != STATUS_NO_CHANGE) {
148 ZLOGI("status before:%{public}d, eventId: %{public}d, status after:%{public}d", changedAssetInfo.status,
149 eventId, action->next);
150 changedAssetInfo.status = static_cast<TransferStatus>(action->next);
151 }
152 if (action->after != nullptr) {
153 int32_t res = action->after(eventId, changedAssetInfo, asset, newAsset);
154 if (res != GeneralError::E_OK) {
155 return GeneralError::E_ERROR;
156 }
157 }
158 return GeneralError::E_OK;
159 }
160
DoTransfer(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)161 static int32_t DoTransfer(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
162 const std::pair<std::string, Asset>& newAsset)
163 {
164 changedAsset.deviceId = newAsset.first;
165 changedAsset.asset = newAsset.second;
166 std::vector<Asset> assets{ changedAsset.asset };
167 ObjectAssetLoader::GetInstance()->TransferAssetsAsync(changedAsset.storeInfo.user,
168 changedAsset.storeInfo.bundleName, changedAsset.deviceId, assets, [&changedAsset](bool success) {
169 if (success) {
170 auto status = UpdateStore(changedAsset);
171 if (status != E_OK) {
172 ZLOGE("UpdateStore error, error:%{public}d, assetName:%{public}s, store:%{public}s, "
173 "table:%{public}s",
174 status, changedAsset.asset.name.c_str(),
175 Anonymous::Change(changedAsset.bindInfo.storeName).c_str(),
176 changedAsset.bindInfo.tableName.c_str());
177 }
178 }
179 ObjectAssetMachine::DFAPostEvent(TRANSFER_FINISHED, changedAsset, changedAsset.asset);
180 });
181 return E_OK;
182 }
183
UpdateStore(ChangedAssetInfo & changedAsset)184 static int32_t UpdateStore(ChangedAssetInfo& changedAsset)
185 {
186 auto store = GetStore(changedAsset);
187 if (store == nullptr) {
188 ZLOGE("store null, storeId:%{public}s", Anonymous::Change(changedAsset.bindInfo.storeName).c_str());
189 return E_ERROR;
190 }
191
192 VBuckets vBuckets = GetMigratedData(store, changedAsset.bindInfo, changedAsset.asset);
193 if (vBuckets.empty()) {
194 return E_OK;
195 }
196 return store->MergeMigratedData(changedAsset.bindInfo.tableName, std::move(vBuckets));
197 }
198
GetMigratedData(AutoCache::Store & store,AssetBindInfo & assetBindInfo,const Asset & newAsset)199 static VBuckets GetMigratedData(AutoCache::Store& store, AssetBindInfo& assetBindInfo, const Asset& newAsset)
200 {
201 Values args;
202 VBuckets vBuckets;
203 auto sql = BuildSql(assetBindInfo, args);
204 auto [errCode, cursor] = store->Query(assetBindInfo.tableName, sql, std::move(args));
205 if (errCode != E_OK || cursor == nullptr) {
206 return vBuckets;
207 }
208 int32_t count = cursor->GetCount();
209 if (count != 1) {
210 return vBuckets;
211 }
212 vBuckets.reserve(count);
213 auto err = cursor->MoveToFirst();
214 while (err == E_OK && count > 0) {
215 VBucket entry;
216 err = cursor->GetRow(entry);
217 if (err != E_OK) {
218 return vBuckets;
219 }
220 MergeAssetData(entry, newAsset, assetBindInfo);
221 vBuckets.emplace_back(std::move(entry));
222 err = cursor->MoveToNext();
223 count--;
224 }
225 return vBuckets;
226 }
227
BuildSql(const AssetBindInfo & bindInfo,Values & args)228 static std::string BuildSql(const AssetBindInfo& bindInfo, Values& args)
229 {
230 std::string sql;
231 sql.append("SELECT ").append(bindInfo.field).append(" FROM ").append(bindInfo.tableName).append(" WHERE ");
232 for (auto const& [key, value] : bindInfo.primaryKey) {
233 sql.append(key).append(SQL_AND);
234 args.emplace_back(value);
235 }
236 sql = sql.substr(0, sql.size() - AND_SIZE);
237 return sql;
238 }
239
MergeAssetData(VBucket & record,const Asset & newAsset,const AssetBindInfo & assetBindInfo)240 static void MergeAssetData(VBucket& record, const Asset& newAsset, const AssetBindInfo& assetBindInfo)
241 {
242 for (auto const& [key, primary] : assetBindInfo.primaryKey) {
243 record[key] = primary;
244 }
245
246 auto it = record.find(assetBindInfo.field);
247 if (it == record.end()) {
248 ZLOGD("Not find field:%{public}s in store", assetBindInfo.field.c_str());
249 return;
250 }
251
252 auto& value = it->second;
253 if (value.index() == TYPE_INDEX<std::monostate>) {
254 Assets assets{ newAsset };
255 value = assets;
256 return;
257 }
258 if (value.index() == TYPE_INDEX<DistributedData::Asset>) {
259 auto* asset = Traits::get_if<DistributedData::Asset>(&value);
260 if (asset->name != newAsset.name) {
261 ZLOGD("Asset not same, old uri: %{public}s, new uri: %{public}s",
262 Anonymous::Change(asset->uri, true).c_str(), Anonymous::Change(newAsset.uri, true).c_str());
263 return;
264 }
265 }
266
267 if (value.index() == TYPE_INDEX<DistributedData::Assets>) {
268 auto* assets = Traits::get_if<DistributedData::Assets>(&value);
269 for (auto& asset : *assets) {
270 if (asset.name == newAsset.name) {
271 MergeAsset(asset, newAsset);
272 return;
273 }
274 }
275 assets->emplace_back(newAsset);
276 }
277 }
278
MergeAsset(Asset & oldAsset,const Asset & newAsset)279 static void MergeAsset(Asset& oldAsset, const Asset& newAsset)
280 {
281 oldAsset.name = newAsset.name;
282 oldAsset.uri = newAsset.uri;
283 oldAsset.modifyTime = newAsset.modifyTime;
284 oldAsset.createTime = newAsset.createTime;
285 oldAsset.size = newAsset.size;
286 oldAsset.hash = newAsset.hash;
287 oldAsset.path = newAsset.path;
288 }
289
GetStore(ChangedAssetInfo & changedAsset)290 static AutoCache::Store GetStore(ChangedAssetInfo& changedAsset)
291 {
292 StoreMetaData meta;
293 meta.storeId = changedAsset.bindInfo.storeName;
294 meta.bundleName = changedAsset.storeInfo.bundleName;
295 meta.user = std::to_string(changedAsset.storeInfo.user);
296 meta.instanceId = changedAsset.storeInfo.instanceId;
297 meta.deviceId = DmAdapter::GetInstance().GetLocalDevice().uuid;
298 if (!MetaDataManager::GetInstance().LoadMeta(meta.GetKey(), meta)) {
299 ZLOGE("meta empty, bundleName:%{public}s, storeId:%{public}s", meta.bundleName.c_str(),
300 meta.GetStoreAlias().c_str());
301 return nullptr;
302 }
303 return AutoCache::GetInstance().GetStore(meta, {});
304 }
305
CompensateTransferring(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)306 static int32_t CompensateTransferring(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
307 const std::pair<std::string, Asset>& newAsset)
308 {
309 std::pair<std::string, Asset> newChangedAsset{ changedAsset.deviceId, changedAsset.asset };
310 return ObjectAssetMachine::DFAPostEvent(REMOTE_CHANGED, changedAsset, changedAsset.asset, newChangedAsset);
311 }
312
CompensateSync(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)313 static int32_t CompensateSync(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
314 const std::pair<std::string, Asset>& newAsset)
315 {
316 BindEvent::BindEventInfo bindEventInfo = MakeBindInfo(changedAsset);
317 auto evt = std::make_unique<BindEvent>(BindEvent::COMPENSATE_SYNC, std::move(bindEventInfo));
318 EventCenter::GetInstance().PostEvent(std::move(evt));
319 return E_OK;
320 }
321
SaveNewAsset(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)322 static int32_t SaveNewAsset(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
323 const std::pair<std::string, Asset>& newAsset)
324 {
325 changedAsset.deviceId = newAsset.first;
326 changedAsset.asset = newAsset.second;
327 return E_OK;
328 }
329
ChangeAssetToNormal(int32_t eventId,ChangedAssetInfo & changedAssetInfo,Asset & asset,const std::pair<std::string,Asset> & newAsset)330 static int32_t ChangeAssetToNormal(int32_t eventId, ChangedAssetInfo& changedAssetInfo, Asset& asset,
331 const std::pair<std::string, Asset>& newAsset)
332 {
333 asset.status = Asset::STATUS_NORMAL;
334 return E_OK;
335 }
336
Recover(int32_t eventId,ChangedAssetInfo & changedAsset,Asset & asset,const std::pair<std::string,Asset> & newAsset)337 static int32_t Recover(int32_t eventId, ChangedAssetInfo& changedAsset, Asset& asset,
338 const std::pair<std::string, Asset>& newAsset)
339 {
340 ZLOGE("An abnormal event has occurred, eventId:%{public}d, status:%{public}d, assetName:%{public}s", eventId,
341 changedAsset.status, changedAsset.asset.name.c_str());
342
343 BindEvent::BindEventInfo bindEventInfo = MakeBindInfo(changedAsset);
344 changedAsset.status = TransferStatus::STATUS_STABLE;
345 auto evt = std::make_unique<BindEvent>(BindEvent::RECOVER_SYNC, std::move(bindEventInfo));
346 EventCenter::GetInstance().PostEvent(std::move(evt));
347 return E_OK;
348 }
349
MakeBindInfo(ChangedAssetInfo & changedAsset)350 static BindEvent::BindEventInfo MakeBindInfo(ChangedAssetInfo& changedAsset)
351 {
352 BindEvent::BindEventInfo bindEventInfo;
353 bindEventInfo.bundleName = changedAsset.storeInfo.bundleName;
354 bindEventInfo.user = changedAsset.storeInfo.user;
355 bindEventInfo.tokenId = changedAsset.storeInfo.tokenId;
356 bindEventInfo.instanceId = changedAsset.storeInfo.instanceId;
357 bindEventInfo.storeName = changedAsset.bindInfo.storeName;
358 bindEventInfo.tableName = changedAsset.bindInfo.tableName;
359 bindEventInfo.filed = changedAsset.bindInfo.field;
360 bindEventInfo.primaryKey = changedAsset.bindInfo.primaryKey;
361 bindEventInfo.assetName = changedAsset.bindInfo.assetName;
362 return bindEventInfo;
363 }
364
ObjectAssetMachine()365 ObjectAssetMachine::ObjectAssetMachine() {}
366
367 } // namespace DistributedObject
368 } // namespace OHOS
369