1 /*
2  * Copyright (C) 2021-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 #define MLOG_TAG "Distributed"
16 
17 #include "medialibrary_device.h"
18 #include "device_permission_verification.h"
19 #include "device_auth.h"
20 #include "media_log.h"
21 #include "medialibrary_data_manager.h"
22 #include "medialibrary_sync_operation.h"
23 #include "medialibrary_tracer.h"
24 
25 namespace OHOS {
26 namespace Media {
27 using namespace std;
28 using namespace OHOS::AppExecFwk;
29 std::shared_ptr<MediaLibraryDevice> MediaLibraryDevice::mlDMInstance_ = nullptr;
30 
31 constexpr int TRIM_LENGTH = 4;
32 constexpr int MIN_ACTIVE_DEVICE_NUMBER = 0;
MediaLibraryDevice()33 MediaLibraryDevice::MediaLibraryDevice()
34 {
35     MEDIA_DEBUG_LOG("MediaLibraryDevice::constructor");
36 }
37 
~MediaLibraryDevice()38 MediaLibraryDevice::~MediaLibraryDevice()
39 {
40     MEDIA_DEBUG_LOG("MediaLibraryDevice::deconstructor");
41 }
42 
Start()43 void MediaLibraryDevice::Start()
44 {
45     MEDIA_DEBUG_LOG("MediaLibraryDevice::start");
46     bundleName_ = BUNDLE_NAME;
47     RegisterToDM();
48     if (deviceHandler_ == nullptr) {
49         auto runner = AppExecFwk::EventRunner::Create("MediaLibraryDevice");
50         deviceHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
51     }
52     devsInfoInter_ = make_shared<DevicesInfoInteract>();
53     if (devsInfoInter_ != nullptr) {
54         devsInfoInter_->Init();
55         std::string local = "";
56         localUdid_ = GetUdidByNetworkId(local);
57         devsInfoInter_->PutMLDeviceInfos(localUdid_);
58         isStart = true;
59     } else {
60         MEDIA_ERR_LOG("init devsInfoInter failed");
61     }
62 }
63 
Stop()64 void MediaLibraryDevice::Stop()
65 {
66     MEDIA_DEBUG_LOG("Stop enter");
67     UnRegisterFromDM();
68     ClearAllDevices();
69     isStart = false;
70     devsInfoInter_ = nullptr;
71     kvSyncDoneCv_.notify_all();
72 }
73 
GetInstance()74 std::shared_ptr<MediaLibraryDevice> MediaLibraryDevice::GetInstance()
75 {
76     static std::once_flag onceFlag;
77     std::call_once(onceFlag, []() mutable {
78         mlDMInstance_ = std::shared_ptr<MediaLibraryDevice>(new(std::nothrow) MediaLibraryDevice());
79         if (mlDMInstance_ != nullptr) {
80             mlDMInstance_ ->Start();
81         }
82     });
83     return mlDMInstance_;
84 }
85 
GetAllNetworkId(std::vector<OHOS::DistributedHardware::DmDeviceInfo> & deviceList)86 void MediaLibraryDevice::GetAllNetworkId(
87     std::vector<OHOS::DistributedHardware::DmDeviceInfo> &deviceList)
88 {
89     std::string extra = "";
90     auto &deviceManager = OHOS::DistributedHardware::DeviceManager::GetInstance();
91     int32_t ret = deviceManager.GetTrustedDeviceList(bundleName_, extra, deviceList);
92     if (ret != 0) {
93         MEDIA_ERR_LOG("get trusted device list failed, ret %{public}d", ret);
94     }
95 }
OnSyncCompleted(const std::string & devId,const DistributedKv::Status status)96 void MediaLibraryDevice::OnSyncCompleted(const std::string &devId, const DistributedKv::Status status)
97 {
98     MEDIA_INFO_LOG("OnSyncCompleted dev id %{private}s, status %{public}d", devId.c_str(), status);
99     std::unique_lock<std::mutex> lock(cvMtx_);
100     kvSyncDoneCv_.notify_one();
101 }
102 
TryToGetTargetDevMLInfos(const std::string & udid,const std::string & networkId)103 void MediaLibraryDevice::TryToGetTargetDevMLInfos(const std::string &udid, const std::string &networkId)
104 {
105     static constexpr int SLEEP_WAITOUT = 500;
106     if (devsInfoInter_ == nullptr) {
107         MEDIA_ERR_LOG("devsInfoInter_ is nullptr");
108         return;
109     }
110     std::string version;
111     bool ret = devsInfoInter_->GetMLDeviceInfos(udid, version);
112     if (!ret) {
113         MEDIA_INFO_LOG("get ml infos failed, so try to sync pull first, wait...");
114         devsInfoInter_->SyncMLDeviceInfos(udid, networkId);
115         {
116             std::unique_lock<std::mutex> lock(cvMtx_);
117             if (kvSyncDoneCv_.wait_for(lock, std::chrono::milliseconds(SLEEP_WAITOUT)) == std::cv_status::timeout) {
118                 MEDIA_DEBUG_LOG("get ml infos sync timeout");
119             }
120             if (!isStart) {
121                 MEDIA_ERR_LOG("MediaLibraryDevice is stopped, this thread will exit");
122                 return;
123             }
124         }
125         MEDIA_DEBUG_LOG("get ml infos sync done, wakeup, try to get again");
126         ret = devsInfoInter_->GetMLDeviceInfos(udid, version);
127         if (!ret) {
128             MEDIA_ERR_LOG("get ml infos failed again, maybe target dev have never init");
129             return;
130         }
131     }
132     lock_guard<std::mutex> lock(devMtx_);
133     deviceInfoMap_[networkId].versionId = version;
134     MEDIA_INFO_LOG("get dev %{private}s ml infos, version %{private}s",
135         networkId.substr(0, TRIM_LENGTH).c_str(), version.c_str());
136 }
137 
OnGetDevSecLevel(const std::string & udid,const int32_t devLevel)138 void MediaLibraryDevice::OnGetDevSecLevel(const std::string &udid, const int32_t devLevel)
139 {
140     MEDIA_INFO_LOG("get dev %{public}s sec level %{public}d", udid.substr(0, TRIM_LENGTH).c_str(), devLevel);
141     if (udid == localUdid_) {
142         localDevLev_ = devLevel;
143         localSecLevelGot_.store(true);
144         localSecLevelDoneCv_.notify_all();
145         MEDIA_INFO_LOG("get local dev sec level %{public}d, notify all wait pids", devLevel);
146         return;
147     }
148     {
149         std::unique_lock<std::mutex> cvlock(gotSecLevelMtx_);
150         localSecLevelDoneCv_.wait(cvlock, [this] () { return localSecLevelGot_.load(); });
151         MEDIA_INFO_LOG("wakeup, get other dev sec level %{public}d", devLevel);
152     }
153 
154     if (localDevLev_ < devLevel || devLevel <= 0) {
155         MEDIA_ERR_LOG("local dev's sec lev %{public}d is lower than dev %{private}s %{public}d, or level invalid!",
156             localDevLev_, udid.substr(0, TRIM_LENGTH).c_str(), devLevel);
157         return;
158     }
159 
160     MediaLibraryDeviceInfo mldevInfo;
161     bool findTargetDev {false};
162     {
163         lock_guard<mutex> lock(devMtx_);
164         for (auto &[_, mlinfo] : deviceInfoMap_) {
165             if (mlinfo.deviceUdid == udid) {
166                 mldevInfo = mlinfo;
167                 findTargetDev = true;
168                 break;
169             }
170         }
171     }
172     if (!findTargetDev) {
173         MEDIA_ERR_LOG("not find this dev %{private}s in device map table", udid.substr(0, TRIM_LENGTH).c_str());
174         return;
175     }
176 
177     if (!MediaLibraryDeviceOperations::InsertDeviceInfo(rdbStore_, mldevInfo, bundleName_)) {
178         MEDIA_ERR_LOG("OnDeviceOnline InsertDeviceInfo failed!");
179         return;
180     }
181 
182     lock_guard<mutex> lock(devMtx_);
183     mldevInfo.devSecLevel = devLevel;
184     deviceInfoMap_[mldevInfo.networkId] = mldevInfo;
185 }
186 
DevOnlineProcess(const DistributedHardware::DmDeviceInfo & devInfo)187 void MediaLibraryDevice::DevOnlineProcess(const DistributedHardware::DmDeviceInfo &devInfo)
188 {
189     if (!localSecLevelGot_.load()) {
190         DevicePermissionVerification::ReqDestDevSecLevel(localUdid_);
191     }
192     MediaLibraryDeviceInfo mldevInfo;
193     GetMediaLibraryDeviceInfo(devInfo, mldevInfo);
194     {
195         lock_guard<mutex> autoLock(devMtx_);
196         deviceInfoMap_[devInfo.networkId] = mldevInfo;
197     }
198 
199     if (!DevicePermissionVerification::CheckPermission(mldevInfo.deviceUdid)) {
200         MEDIA_ERR_LOG("this dev has permission denied!");
201         return;
202     }
203 
204     MediaLibrarySyncOpts syncOpts;
205     syncOpts.rdbStore = rdbStore_;
206     syncOpts.kvStore = kvStore_;
207     syncOpts.bundleName = bundleName_;
208     std::vector<std::string> devices = { mldevInfo.networkId };
209     MediaLibrarySyncOperation::SyncPullAllTableByNetworkId(syncOpts, devices);
210 
211     auto getTargetMLInfoTask = std::make_unique<std::thread>(
212         [this, deviceUdid = mldevInfo.deviceUdid, networkId = mldevInfo.networkId]() {
213         this->TryToGetTargetDevMLInfos(deviceUdid, networkId);
214     });
215     getTargetMLInfoTask->detach();
216 }
217 
OnDeviceOnline(const OHOS::DistributedHardware::DmDeviceInfo & deviceInfo)218 void MediaLibraryDevice::OnDeviceOnline(const OHOS::DistributedHardware::DmDeviceInfo &deviceInfo)
219 {
220     MEDIA_INFO_LOG("dev online network id %{private}s", deviceInfo.networkId);
221 }
222 
OnDeviceOffline(const OHOS::DistributedHardware::DmDeviceInfo & deviceInfo)223 void MediaLibraryDevice::OnDeviceOffline(const OHOS::DistributedHardware::DmDeviceInfo &deviceInfo)
224 {
225     MEDIA_INFO_LOG("OnDeviceOffline networkId = %{private}s", deviceInfo.networkId);
226 
227     if (deviceHandler_ == nullptr) {
228         MEDIA_ERR_LOG("OnDeviceOffline mediaLibraryDeviceHandler null");
229         return;
230     }
231     auto nodeOffline = [this, deviceInfo]() {
232         lock_guard<mutex> autoLock(devMtx_);
233         std::string networkId = deviceInfo.networkId;
234         auto info = deviceInfoMap_.find(networkId);
235         if (info == deviceInfoMap_.end()) {
236             MEDIA_ERR_LOG("OnDeviceOffline can not find networkId:%{private}s", networkId.c_str());
237             return;
238         }
239 
240         MediaLibraryDeviceOperations::UpdateDeviceInfo(rdbStore_, info->second, bundleName_);
241         deviceInfoMap_.erase(networkId);
242 
243         // 设备变更通知
244         NotifyDeviceChange();
245     };
246     if (!deviceHandler_->PostTask(nodeOffline)) {
247         MEDIA_ERR_LOG("OnDeviceOffline handler postTask failed");
248     }
249 }
250 
OnDeviceChanged(const OHOS::DistributedHardware::DmDeviceInfo & deviceInfo)251 void MediaLibraryDevice::OnDeviceChanged(const OHOS::DistributedHardware::DmDeviceInfo &deviceInfo)
252 {
253     MEDIA_INFO_LOG("MediaLibraryDevice OnDeviceChanged called networkId = %{private}s", deviceInfo.networkId);
254 }
255 
OnDeviceReady(const OHOS::DistributedHardware::DmDeviceInfo & deviceInfo)256 void MediaLibraryDevice::OnDeviceReady(const OHOS::DistributedHardware::DmDeviceInfo &deviceInfo)
257 {
258     MEDIA_INFO_LOG("OnDeviceReady network id %{private}s", deviceInfo.networkId);
259     if (deviceHandler_ == nullptr) {
260         MEDIA_ERR_LOG("mediaLibraryDeviceHandler null");
261         return;
262     }
263 
264     auto nodeOnline = [this, deviceInfo]() {
265         DevOnlineProcess(deviceInfo);
266         NotifyDeviceChange();
267     };
268     if (!deviceHandler_->PostTask(nodeOnline)) {
269         MEDIA_ERR_LOG("handler postTask failed");
270     }
271 }
272 
ClearAllDevices()273 void MediaLibraryDevice::ClearAllDevices()
274 {
275     lock_guard<mutex> autoLock(devMtx_);
276     deviceInfoMap_.clear();
277     excludeMap_.clear();
278 }
279 
NotifyDeviceChange()280 void MediaLibraryDevice::NotifyDeviceChange()
281 {
282     auto contextUri = make_unique<Uri>(MEDIALIBRARY_DEVICE_URI);
283     MediaLibraryDataManager::GetInstance()->NotifyChange(*contextUri);
284 }
285 
NotifyRemoteFileChange()286 void MediaLibraryDevice::NotifyRemoteFileChange()
287 {
288     auto contextUri = make_unique<Uri>(MEDIALIBRARY_REMOTEFILE_URI);
289     MediaLibraryDataManager::GetInstance()->NotifyChange(*contextUri);
290 }
291 
IsHasDevice(const string & deviceUdid)292 bool MediaLibraryDevice::IsHasDevice(const string &deviceUdid)
293 {
294     for (auto &[_, info] : deviceInfoMap_) {
295         if (!deviceUdid.compare(info.deviceUdid)) {
296             return true;
297         }
298     }
299     return false;
300 }
301 
InitDeviceRdbStore(const shared_ptr<NativeRdb::RdbStore> & rdbStore)302 bool MediaLibraryDevice::InitDeviceRdbStore(const shared_ptr<NativeRdb::RdbStore> &rdbStore)
303 {
304     rdbStore_ = rdbStore;
305 
306     if (!QueryDeviceTable()) {
307         MEDIA_ERR_LOG("MediaLibraryDevice InitDeviceRdbStore QueryDeviceTable fail!");
308         return false;
309     }
310     // 获取同一网络中的所有设备Id
311     std::vector<OHOS::DistributedHardware::DmDeviceInfo> deviceList;
312     GetAllNetworkId(deviceList);
313     MEDIA_INFO_LOG("MediaLibraryDevice InitDeviceRdbStore deviceList size = %{public}d", (int) deviceList.size());
314     for (auto& deviceInfo : deviceList) {
315         DevOnlineProcess(deviceInfo);
316     }
317 
318     std::vector<OHOS::Media::MediaLibraryDeviceInfo> deviceDataBaseList;
319     MediaLibraryDeviceOperations::GetAllDeviceData(rdbStore, deviceDataBaseList);
320     for (auto deviceInfo : deviceDataBaseList) {
321         if (!IsHasDevice(deviceInfo.deviceUdid)) {
322             MediaLibraryDeviceOperations::UpdateDeviceInfo(rdbStore_, deviceInfo, bundleName_);
323         }
324     }
325     MEDIA_INFO_LOG("deviceInfoMap size = %{public}d, deviceDataBaseList size = %{public}d",
326         (int) deviceInfoMap_.size(), (int) deviceDataBaseList.size());
327     return true;
328 }
329 
InitDeviceKvStore(const shared_ptr<DistributedKv::SingleKvStore> & kvStore)330 bool MediaLibraryDevice::InitDeviceKvStore(const shared_ptr<DistributedKv::SingleKvStore> &kvStore)
331 {
332     kvStore_ = kvStore;
333     return kvStore_ != nullptr;
334 }
335 
UpdateDeviceSyncStatus(const std::string & networkId,const string & tableName,int32_t syncStatus)336 bool MediaLibraryDevice::UpdateDeviceSyncStatus(const std::string &networkId,
337     const string &tableName, int32_t syncStatus)
338 {
339     std::string udid;
340     {
341         lock_guard<mutex> autoLock(devMtx_);
342         auto iter = deviceInfoMap_.find(networkId);
343         if (iter == deviceInfoMap_.end()) {
344             MEDIA_ERR_LOG("UpdateDeviceSyncStatus can not find networkId:%{private}s", networkId.c_str());
345             return false;
346         }
347         udid = iter->second.deviceUdid;
348     }
349     return MediaLibraryDeviceOperations::UpdateSyncStatus(rdbStore_, udid, tableName, syncStatus);
350 }
351 
GetDeviceSyncStatus(const std::string & networkId,const std::string & tableName,int32_t & syncStatus)352 bool MediaLibraryDevice::GetDeviceSyncStatus(const std::string &networkId, const std::string &tableName,
353     int32_t &syncStatus)
354 {
355     std::string udid;
356     {
357         lock_guard<mutex> autoLock(devMtx_);
358         auto info = deviceInfoMap_.find(networkId);
359         if (info == deviceInfoMap_.end()) {
360             MEDIA_ERR_LOG("GetDeviceSyncStatus can not find networkId:%{private}s", networkId.c_str());
361             return false;
362         }
363         udid = info->second.deviceUdid;
364     }
365     return MediaLibraryDeviceOperations::GetSyncStatusById(rdbStore_, udid, tableName, syncStatus);
366 }
367 
GetUdidByNetworkId(std::string & networkId)368 std::string MediaLibraryDevice::GetUdidByNetworkId(std::string &networkId)
369 {
370     auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
371     if (networkId.empty()) {
372         OHOS::DistributedHardware::DmDeviceInfo deviceInfo;
373         auto ret = deviceManager.GetLocalDeviceInfo(bundleName_, deviceInfo);
374         if (ret != ERR_OK) {
375             MEDIA_ERR_LOG("get local device info failed, ret %{public}d", ret);
376             return "";
377         }
378         networkId = deviceInfo.networkId;
379     }
380 
381     std::string deviceUdid;
382     auto ret = deviceManager.GetUdidByNetworkId(bundleName_, networkId, deviceUdid);
383     if (ret != 0) {
384         MEDIA_INFO_LOG("GetDeviceUdid error networkId = %{private}s, ret %{public}d", networkId.c_str(), ret);
385         return std::string();
386     }
387     return deviceUdid;
388 }
389 
GetMediaLibraryDeviceInfo(const DistributedHardware::DmDeviceInfo & dmInfo,MediaLibraryDeviceInfo & mlInfo)390 void MediaLibraryDevice::GetMediaLibraryDeviceInfo(const DistributedHardware::DmDeviceInfo &dmInfo,
391     MediaLibraryDeviceInfo& mlInfo)
392 {
393     mlInfo.networkId = dmInfo.networkId;
394     mlInfo.deviceName = dmInfo.deviceName;
395     mlInfo.deviceTypeId = dmInfo.deviceTypeId;
396     mlInfo.deviceUdid = GetUdidByNetworkId(mlInfo.networkId);
397 }
398 
GetNetworkIdBySelfId(const std::string & selfId)399 string MediaLibraryDevice::GetNetworkIdBySelfId(const std::string &selfId)
400 {
401     for (auto &[_, info] : deviceInfoMap_) {
402         if (!selfId.compare(info.selfId)) {
403             return info.selfId;
404         }
405     }
406     MEDIA_ERR_LOG("GetNetworkIdBySelfId can not find selfId:%{private}s", selfId.c_str());
407     return "";
408 }
409 
QueryDeviceTable()410 bool MediaLibraryDevice::QueryDeviceTable()
411 {
412     if (rdbStore_ == nullptr) {
413         return false;
414     }
415     excludeMap_.clear();
416     return MediaLibraryDeviceOperations::QueryDeviceTable(rdbStore_, excludeMap_);
417 }
418 
OnRemoteDied()419 void MediaLibraryDevice::OnRemoteDied()
420 {
421     MEDIA_INFO_LOG("dm instance died");
422     UnRegisterFromDM();
423     RegisterToDM();
424 }
425 
RegisterToDM()426 void MediaLibraryDevice::RegisterToDM()
427 {
428     auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
429     int errCode = deviceManager.InitDeviceManager(bundleName_, shared_from_this());
430     if (errCode != 0) {
431         MEDIA_ERR_LOG("RegisterToDm InitDeviceManager failed %{public}d", errCode);
432     }
433 
434     std::string extra = "";
435     errCode = deviceManager.RegisterDevStateCallback(bundleName_, extra, shared_from_this());
436     if (errCode != 0) {
437         MEDIA_ERR_LOG("RegisterDevStateCallback failed errCode %{public}d", errCode);
438     }
439     MEDIA_INFO_LOG("RegisterToDM success!");
440 }
441 
UnRegisterFromDM()442 void MediaLibraryDevice::UnRegisterFromDM()
443 {
444     auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
445     int errCode = deviceManager.UnRegisterDevStateCallback(bundleName_);
446     if (errCode != 0) {
447         MEDIA_ERR_LOG("UnRegisterDevStateCallback failed errCode %{public}d", errCode);
448     }
449     errCode = deviceManager.UnInitDeviceManager(bundleName_);
450     if (errCode != 0) {
451         MEDIA_ERR_LOG("UnInitDeviceManager failed errCode %{public}d", errCode);
452     }
453     MEDIA_INFO_LOG("UnRegisterFromDM success");
454 }
455 
GetDeviceInfoMap(unordered_map<string,MediaLibraryDeviceInfo> & outDeviceMap)456 void MediaLibraryDevice::GetDeviceInfoMap(unordered_map<string, MediaLibraryDeviceInfo> &outDeviceMap)
457 {
458     outDeviceMap = deviceInfoMap_;
459 }
460 
QueryAgingDeviceInfos(vector<MediaLibraryDeviceInfo> & outDeviceInfos)461 bool MediaLibraryDevice::QueryAgingDeviceInfos(vector<MediaLibraryDeviceInfo> &outDeviceInfos)
462 {
463     return MediaLibraryDeviceOperations::GetAgingDeviceData(rdbStore_, outDeviceInfos);
464 }
465 
QueryAllDeviceUdid(vector<string> & deviceUdids)466 bool MediaLibraryDevice::QueryAllDeviceUdid(vector<string> &deviceUdids)
467 {
468     return MediaLibraryDeviceOperations::GetAllDeviceUdid(rdbStore_, deviceUdids);
469 }
470 
DeleteDeviceInfo(const string & udid)471 bool MediaLibraryDevice::DeleteDeviceInfo(const string &udid)
472 {
473     return MediaLibraryDeviceOperations::DeleteDeviceInfo(rdbStore_, udid);
474 }
475 
IsHasActiveDevice()476 bool MediaLibraryDevice::IsHasActiveDevice()
477 {
478     lock_guard<mutex> autoLock(devMtx_);
479     int deviceNumber = deviceInfoMap_.size();
480     if (deviceNumber > MIN_ACTIVE_DEVICE_NUMBER) {
481         MEDIA_DEBUG_LOG("device number = %{public}d", deviceNumber);
482         return true;
483     } else {
484         return false;
485     }
486 }
487 } // namespace Media
488 } // namespace OHOS