1 /*
2  * Copyright (c) 2021-2024 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 #include "offline_task.h"
17 
18 #include <pthread.h>
19 #include <thread>
20 
21 #include "ffrt.h"
22 
23 #include "anonymous_string.h"
24 #include "capability_info_manager.h"
25 #include "constants.h"
26 #include "device_manager.h"
27 #include "dh_context.h"
28 #include "dh_utils_tool.h"
29 #include "distributed_hardware_errno.h"
30 #include "distributed_hardware_log.h"
31 #include "distributed_hardware_manager_factory.h"
32 #include "meta_info_manager.h"
33 #include "task_board.h"
34 #include "task_executor.h"
35 #include "task_factory.h"
36 
37 namespace OHOS {
38 namespace DistributedHardware {
39 #undef DH_LOG_TAG
40 #define DH_LOG_TAG "OffLineTask"
41 
OffLineTask(const std::string & networkId,const std::string & uuid,const std::string & udid,const std::string & dhId,const DHType dhType)42 OffLineTask::OffLineTask(const std::string &networkId, const std::string &uuid, const std::string &udid,
43     const std::string &dhId, const DHType dhType) : Task(networkId, uuid, udid, dhId, dhType)
44 {
45     this->SetTaskType(TaskType::OFF_LINE);
46     this->SetTaskSteps({TaskStep::META_DISABLE_TASK, TaskStep::UNREGISTER_OFFLINE_DISTRIBUTED_HARDWARE,
47         TaskStep::WAIT_UNREGISTGER_COMPLETE, TaskStep::CLEAR_OFFLINE_INFO});
48     DHLOGD("OffLineTask id: %{public}s, networkId: %{public}s, uuid: %{public}s, udid: %{public}s",
49         GetId().c_str(), GetAnonyString(GetNetworkId()).c_str(), GetAnonyString(GetUUID()).c_str(),
50         GetAnonyString(GetUDID()).c_str());
51 }
52 
~OffLineTask()53 OffLineTask::~OffLineTask()
54 {
55     DHLOGD("id = %{public}s, uuid = %{public}s", GetId().c_str(), GetAnonyString(GetUUID()).c_str());
56 }
57 
DoTask()58 void OffLineTask::DoTask()
59 {
60     ffrt::submit([this]() { this->DoTaskInner(); });
61 }
62 
DoTaskInner()63 void OffLineTask::DoTaskInner()
64 {
65     int32_t ret = pthread_setname_np(pthread_self(), OFFLINE_TASK_INNER);
66     if (ret != DH_FWK_SUCCESS) {
67         DHLOGE("DoTaskInner setname failed.");
68     }
69     DHLOGD("start offline task, id = %{public}s, uuid = %{public}s", GetId().c_str(),
70         GetAnonyString(GetUUID()).c_str());
71     this->SetTaskState(TaskState::RUNNING);
72     for (const auto& step : this->GetTaskSteps()) {
73         switch (step) {
74             case TaskStep::UNREGISTER_OFFLINE_DISTRIBUTED_HARDWARE: {
75                 CreateDisableTask();
76                 break;
77             }
78             case TaskStep::WAIT_UNREGISTGER_COMPLETE: {
79                 WaitDisableTaskFinish();
80                 break;
81             }
82             case TaskStep::CLEAR_OFFLINE_INFO: {
83                 ClearOffLineInfo();
84                 break;
85             }
86             case TaskStep::META_DISABLE_TASK: {
87                 CreateMetaDisableTask();
88                 break;
89             }
90             default: {
91                 break;
92             }
93         }
94     }
95 
96     this->SetTaskState(TaskState::SUCCESS);
97     DHLOGD("Finish OffLine task, remove it, id: %{public}s", GetId().c_str());
98     TaskBoard::GetInstance().RemoveTask(this->GetId());
99     if (DHContext::GetInstance().GetRealTimeOnlineDeviceCount() == 0 &&
100         DHContext::GetInstance().GetIsomerismConnectCount() == 0 &&
101         TaskBoard::GetInstance().IsAllTaskFinish()) {
102         DHLOGI("all devices are offline, start to free the resource");
103         DistributedHardwareManagerFactory::GetInstance().UnInit();
104     }
105 }
106 
CreateDisableTask()107 void OffLineTask::CreateDisableTask()
108 {
109     DHLOGI("networkId = %{public}s, uuid = %{public}s", GetAnonyString(GetNetworkId()).c_str(),
110         GetAnonyString(GetUUID()).c_str());
111     std::string deviceId = GetDeviceIdByUUID(GetUUID());
112     std::vector<std::pair<std::string, DHType>> devDhInfos;
113     std::vector<std::shared_ptr<CapabilityInfo>> capabilityInfos;
114     CapabilityInfoManager::GetInstance()->GetCapabilitiesByDeviceId(deviceId, capabilityInfos);
115     std::for_each(capabilityInfos.begin(), capabilityInfos.end(), [&](std::shared_ptr<CapabilityInfo> cap) {
116         devDhInfos.push_back({cap->GetDHId(), cap->GetDHType()});
117     });
118 
119     if (devDhInfos.empty()) {
120         DHLOGW("Can not get cap info from CapabilityInfo, try use meta info");
121         std::vector<std::shared_ptr<MetaCapabilityInfo>> metaCapInfos;
122         std::string udidHash = DHContext::GetInstance().GetUdidHashIdByUUID(GetUUID());
123         MetaInfoManager::GetInstance()->GetMetaCapInfosByUdidHash(udidHash, metaCapInfos);
124         std::for_each(metaCapInfos.begin(), metaCapInfos.end(), [&](std::shared_ptr<MetaCapabilityInfo> cap) {
125             devDhInfos.push_back({cap->GetDHId(), cap->GetDHType()});
126         });
127     }
128 
129     if (devDhInfos.empty()) {
130         DHLOGE("Can not get cap info, uuid = %{public}s, deviceId = %{public}s", GetAnonyString(GetUUID()).c_str(),
131             GetAnonyString(deviceId).c_str());
132     }
133 
134     for (const auto &info : devDhInfos) {
135         TaskParam taskParam = {
136             .networkId = GetNetworkId(),
137             .uuid = GetUUID(),
138             .dhId = info.first,
139             .dhType = info.second
140         };
141         auto task = TaskFactory::GetInstance().CreateTask(TaskType::DISABLE, taskParam, shared_from_this());
142         TaskExecutor::GetInstance().PushTask(task);
143     }
144 }
145 
WaitDisableTaskFinish()146 void OffLineTask::WaitDisableTaskFinish()
147 {
148     DHLOGI("start wait disable task finish");
149     std::unique_lock<std::mutex> waitLock(unFinishTaskMtx_);
150     finishCondVar_.wait(waitLock, [&] { return this->unFinishChildrenTasks_.empty(); });
151     DHLOGI("all disable task finish");
152     DHContext::GetInstance().RemoveOnlineDeviceIdEntryByNetworkId(GetNetworkId());
153 }
154 
ClearOffLineInfo()155 void OffLineTask::ClearOffLineInfo()
156 {
157     DHLOGI("start clear resource when device offline, uuid = %{public}s", GetAnonyString(GetUUID()).c_str());
158     auto ret = CapabilityInfoManager::GetInstance()->RemoveCapabilityInfoInMem(GetDeviceIdByUUID(GetUUID()));
159     if (ret != DH_FWK_SUCCESS) {
160         DHLOGE("RemoveCapabilityInfoInMem failed, uuid = %{public}s, errCode = %{public}d",
161             GetAnonyString(GetUUID()).c_str(), ret);
162     }
163 }
164 
NotifyFatherFinish(std::string taskId)165 void OffLineTask::NotifyFatherFinish(std::string taskId)
166 {
167     {
168         std::lock_guard<std::mutex> lock(unFinishTaskMtx_);
169         this->unFinishChildrenTasks_.erase(taskId);
170     }
171     finishCondVar_.notify_all();
172 }
173 
AddChildrenTask(std::shared_ptr<Task> childrenTask)174 void OffLineTask::AddChildrenTask(std::shared_ptr<Task> childrenTask)
175 {
176     std::lock_guard<std::mutex> lock(unFinishTaskMtx_);
177     this->unFinishChildrenTasks_.insert(childrenTask->GetId());
178 }
179 
CreateMetaDisableTask()180 void OffLineTask::CreateMetaDisableTask()
181 {
182     DHLOGI("CreateMetaDisableTask, networkId = %{public}s, uuid = %{public}s", GetAnonyString(GetNetworkId()).c_str(),
183         GetAnonyString(GetUUID()).c_str());
184     int32_t deviceType = DmDeviceType::DEVICE_TYPE_UNKNOWN;
185     DeviceManager::GetInstance().GetDeviceType(DH_FWK_PKG_NAME, GetNetworkId(), deviceType);
186     if (deviceType != DmDeviceType::DEVICE_TYPE_PHONE) {
187         DHLOGI("CreateMetaDisableTask, offline device not phone, deviceType = %{public}d", deviceType);
188         return;
189     }
190     TaskParam taskParam = {
191         .networkId = GetNetworkId(),
192         .uuid = GetUUID(),
193         .dhId = GetDhId(),
194         .dhType = GetDhType()
195     };
196     auto task = TaskFactory::GetInstance().CreateTask(TaskType::META_DISABLE, taskParam, shared_from_this());
197     TaskExecutor::GetInstance().PushTask(task);
198 }
199 } // namespace DistributedHardware
200 } // namespace OHOS
201