• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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