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