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 #include "cooperate.h"
17 
18 #ifdef ENABLE_PERFORMANCE_CHECK
19 #include <sstream>
20 #include "utility.h"
21 #endif // ENABLE_PERFORMANCE_CHECK
22 
23 #include "devicestatus_define.h"
24 
25 #undef LOG_TAG
26 #define LOG_TAG "Cooperate"
27 
28 namespace OHOS {
29 namespace Msdp {
30 namespace DeviceStatus {
31 namespace Cooperate {
32 
Cooperate(IContext * env)33 Cooperate::Cooperate(IContext *env)
34     : env_(env), context_(env), sm_(env)
35 {
36     auto [sender, receiver] = Channel<CooperateEvent>::OpenChannel();
37     receiver_ = receiver;
38     receiver_.Enable();
39     context_.AttachSender(sender);
40     context_.Enable();
41     StartWorker();
42 }
43 
~Cooperate()44 Cooperate::~Cooperate()
45 {
46     StopWorker();
47     context_.Disable();
48 }
49 
AddObserver(std::shared_ptr<ICooperateObserver> observer)50 void Cooperate::AddObserver(std::shared_ptr<ICooperateObserver> observer)
51 {
52     CALL_DEBUG_ENTER;
53     auto ret = context_.Sender().Send(CooperateEvent(
54         CooperateEventType::ADD_OBSERVER,
55         AddObserverEvent {
56             .observer = observer
57         }));
58     if (ret != Channel<CooperateEvent>::NO_ERROR) {
59         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
60     }
61 }
62 
RemoveObserver(std::shared_ptr<ICooperateObserver> observer)63 void Cooperate::RemoveObserver(std::shared_ptr<ICooperateObserver> observer)
64 {
65     CALL_DEBUG_ENTER;
66     auto ret = context_.Sender().Send(CooperateEvent(
67         CooperateEventType::REMOVE_OBSERVER,
68         RemoveObserverEvent {
69             .observer = observer
70         }));
71     if (ret != Channel<CooperateEvent>::NO_ERROR) {
72         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
73     }
74 }
75 
RegisterListener(int32_t pid)76 int32_t Cooperate::RegisterListener(int32_t pid)
77 {
78     CALL_DEBUG_ENTER;
79     auto ret = context_.Sender().Send(CooperateEvent(
80         CooperateEventType::REGISTER_LISTENER,
81         RegisterListenerEvent {
82             .pid = pid
83         }));
84     if (ret != Channel<CooperateEvent>::NO_ERROR) {
85         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
86     }
87     return RET_OK;
88 }
89 
UnregisterListener(int32_t pid)90 int32_t Cooperate::UnregisterListener(int32_t pid)
91 {
92     CALL_DEBUG_ENTER;
93     auto ret = context_.Sender().Send(CooperateEvent(
94         CooperateEventType::UNREGISTER_LISTENER,
95         UnregisterListenerEvent {
96             .pid = pid
97         }));
98     if (ret != Channel<CooperateEvent>::NO_ERROR) {
99         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
100     }
101     return RET_OK;
102 }
103 
RegisterHotAreaListener(int32_t pid)104 int32_t Cooperate::RegisterHotAreaListener(int32_t pid)
105 {
106     CALL_DEBUG_ENTER;
107     auto ret = context_.Sender().Send(CooperateEvent(
108         CooperateEventType::REGISTER_HOTAREA_LISTENER,
109         RegisterHotareaListenerEvent {
110             .pid = pid
111         }));
112     if (ret != Channel<CooperateEvent>::NO_ERROR) {
113         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
114     }
115     return RET_OK;
116 }
117 
UnregisterHotAreaListener(int32_t pid)118 int32_t Cooperate::UnregisterHotAreaListener(int32_t pid)
119 {
120     CALL_DEBUG_ENTER;
121     auto ret = context_.Sender().Send(CooperateEvent(
122         CooperateEventType::UNREGISTER_HOTAREA_LISTENER,
123         UnregisterHotareaListenerEvent {
124             .pid = pid
125         }));
126     if (ret != Channel<CooperateEvent>::NO_ERROR) {
127         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
128     }
129     return RET_OK;
130 }
131 
Enable(int32_t tokenId,int32_t pid,int32_t userData)132 int32_t Cooperate::Enable(int32_t tokenId, int32_t pid, int32_t userData)
133 {
134     CALL_DEBUG_ENTER;
135     auto ret = context_.Sender().Send(CooperateEvent(
136         CooperateEventType::ENABLE,
137         EnableCooperateEvent {
138             .tokenId = tokenId,
139             .pid = pid,
140             .userData = userData,
141         }));
142     if (ret != Channel<CooperateEvent>::NO_ERROR) {
143         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
144     }
145     return RET_OK;
146 }
147 
Disable(int32_t pid,int32_t userData)148 int32_t Cooperate::Disable(int32_t pid, int32_t userData)
149 {
150     CALL_DEBUG_ENTER;
151     auto ret = context_.Sender().Send(CooperateEvent(
152         CooperateEventType::DISABLE,
153         DisableCooperateEvent {
154             .pid = pid,
155             .userData = userData,
156         }));
157     if (ret != Channel<CooperateEvent>::NO_ERROR) {
158         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
159     }
160     return RET_OK;
161 }
162 
Start(int32_t pid,int32_t userData,const std::string & remoteNetworkId,int32_t startDeviceId)163 int32_t Cooperate::Start(int32_t pid, int32_t userData, const std::string &remoteNetworkId, int32_t startDeviceId)
164 {
165     CALL_DEBUG_ENTER;
166 
167 #ifdef ENABLE_PERFORMANCE_CHECK
168     std::ostringstream ss;
169     ss << "start_cooperation_with_" << Utility::Anonymize(remoteNetworkId).c_str();
170     context_.StartTrace(ss.str());
171 #endif // ENABLE_PERFORMANCE_CHECK
172     StartCooperateEvent event {
173         .pid = pid,
174         .userData = userData,
175         .remoteNetworkId = remoteNetworkId,
176         .startDeviceId = startDeviceId,
177         .errCode = std::make_shared<std::promise<int32_t>>(),
178     };
179     auto errCode = event.errCode->get_future();
180     auto ret = context_.Sender().Send(CooperateEvent(CooperateEventType::START, event));
181     if (ret != Channel<CooperateEvent>::NO_ERROR) {
182         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
183     }
184     return errCode.get();
185 }
186 
Stop(int32_t pid,int32_t userData,bool isUnchained)187 int32_t Cooperate::Stop(int32_t pid, int32_t userData, bool isUnchained)
188 {
189     CALL_DEBUG_ENTER;
190     auto ret = context_.Sender().Send(CooperateEvent(
191         CooperateEventType::STOP,
192         StopCooperateEvent {
193             .pid = pid,
194             .userData = userData,
195             .isUnchained = isUnchained,
196         }));
197     if (ret != Channel<CooperateEvent>::NO_ERROR) {
198         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
199     }
200     return RET_OK;
201 }
202 
GetCooperateState(int32_t pid,int32_t userData,const std::string & networkId)203 int32_t Cooperate::GetCooperateState(int32_t pid, int32_t userData, const std::string &networkId)
204 {
205     CALL_DEBUG_ENTER;
206     auto ret = context_.Sender().Send(CooperateEvent(
207         CooperateEventType::GET_COOPERATE_STATE,
208         GetCooperateStateEvent {
209             .pid = pid,
210             .userData = userData,
211             .networkId = networkId,
212         }));
213     if (ret != Channel<CooperateEvent>::NO_ERROR) {
214         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
215     }
216     return RET_OK;
217 }
218 
RegisterEventListener(int32_t pid,const std::string & networkId)219 int32_t Cooperate::RegisterEventListener(int32_t pid, const std::string &networkId)
220 {
221     CALL_DEBUG_ENTER;
222     auto ret = context_.Sender().Send(CooperateEvent(
223         CooperateEventType::REGISTER_EVENT_LISTENER,
224         RegisterEventListenerEvent {
225             .pid = pid,
226             .networkId = networkId,
227         }));
228     if (ret != Channel<CooperateEvent>::NO_ERROR) {
229         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
230     }
231     return RET_OK;
232 }
233 
UnregisterEventListener(int32_t pid,const std::string & networkId)234 int32_t Cooperate::UnregisterEventListener(int32_t pid, const std::string &networkId)
235 {
236     CALL_DEBUG_ENTER;
237     auto ret = context_.Sender().Send(CooperateEvent(
238         CooperateEventType::UNREGISTER_EVENT_LISTENER,
239         UnregisterEventListenerEvent {
240             .pid = pid,
241             .networkId = networkId,
242         }));
243     if (ret != Channel<CooperateEvent>::NO_ERROR) {
244         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
245     }
246     return RET_OK;
247 }
248 
GetCooperateState(const std::string & udId,bool & state)249 int32_t Cooperate::GetCooperateState(const std::string &udId, bool &state)
250 {
251     CALL_DEBUG_ENTER;
252     state = sm_.IsCooperateEnable();
253     return RET_OK;
254 }
255 
Update(uint32_t mask,uint32_t flag)256 int32_t Cooperate::Update(uint32_t mask, uint32_t flag)
257 {
258     auto ret = context_.Sender().Send(CooperateEvent(
259         CooperateEventType::UPDATE_COOPERATE_FLAG,
260         UpdateCooperateFlagEvent {
261             .mask = mask,
262             .flag = flag,
263         }));
264     if (ret != Channel<CooperateEvent>::NO_ERROR) {
265         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
266     }
267     return RET_OK;
268 }
269 
Dump(int32_t fd)270 void Cooperate::Dump(int32_t fd)
271 {
272     CALL_DEBUG_ENTER;
273     auto ret = context_.Sender().Send(CooperateEvent(
274         CooperateEventType::DUMP,
275         DumpEvent {
276             .fd = fd
277         }));
278     if (ret != Channel<CooperateEvent>::NO_ERROR) {
279         FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
280     }
281 }
282 
Loop()283 void Cooperate::Loop()
284 {
285     CALL_DEBUG_ENTER;
286     bool running = true;
287     SetThreadName("OS_Cooperate");
288     LoadMotionDrag();
289 
290     while (running) {
291         CooperateEvent event = receiver_.Receive();
292         switch (event.type) {
293             case CooperateEventType::NOOP: {
294                 break;
295             }
296             case CooperateEventType::QUIT: {
297                 FI_HILOGI("Skip out of loop");
298                 running = false;
299                 break;
300             }
301             default: {
302                 sm_.OnEvent(context_, event);
303                 break;
304             }
305         }
306     }
307 }
308 
StartWorker()309 void Cooperate::StartWorker()
310 {
311     CALL_DEBUG_ENTER;
312     std::lock_guard guard(lock_);
313     if (!workerStarted_) {
314         workerStarted_ = true;
315         worker_ = std::thread([this] { this->Loop(); });
316     }
317 }
318 
StopWorker()319 void Cooperate::StopWorker()
320 {
321     CALL_DEBUG_ENTER;
322     std::lock_guard guard(lock_);
323     if (workerStarted_) {
324         auto ret = context_.Sender().Send(CooperateEvent(CooperateEventType::QUIT));
325         if (ret != Channel<CooperateEvent>::NO_ERROR) {
326             FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
327         }
328         if (worker_.joinable()) {
329             worker_.join();
330         }
331         workerStarted_ = false;
332     }
333 }
334 
LoadMotionDrag()335 void Cooperate::LoadMotionDrag()
336 {
337     FI_HILOGI("Load 'MotionDrag' module");
338     IMotionDrag *motionDrag = env_->GetPluginManager().LoadMotionDrag();
339     if (motionDrag == nullptr) {
340         FI_HILOGE("Failed to load motion drag");
341         return;
342     }
343     motionDrag->Enable(context_.EventHandler());
344 }
345 
CreateInstance(IContext * env)346 extern "C" ICooperate* CreateInstance(IContext *env)
347 {
348     CHKPP(env);
349     return new Cooperate(env);
350 }
351 
DestroyInstance(ICooperate * instance)352 extern "C" void DestroyInstance(ICooperate *instance)
353 {
354     if (instance != nullptr) {
355         delete instance;
356     }
357 }
358 } // namespace Cooperate
359 } // namespace DeviceStatus
360 } // namespace Msdp
361 } // namespace OHOS