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
28namespace OHOS {
29namespace Msdp {
30namespace DeviceStatus {
31namespace Cooperate {
32
33Cooperate::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
44Cooperate::~Cooperate()
45{
46    StopWorker();
47    context_.Disable();
48}
49
50void 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
63void 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
76int32_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
90int32_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
104int32_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
118int32_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
132int32_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
148int32_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
163int32_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
187int32_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
203int32_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
219int32_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
234int32_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
249int32_t Cooperate::GetCooperateState(const std::string &udId, bool &state)
250{
251    CALL_DEBUG_ENTER;
252    state = sm_.IsCooperateEnable();
253    return RET_OK;
254}
255
256int32_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
270int32_t Cooperate::SetDamplingCoefficient(uint32_t direction, double coefficient)
271{
272    auto ret = context_.Sender().Send(CooperateEvent(
273        CooperateEventType::SET_DAMPLING_COEFFICIENT,
274        SetDamplingCoefficientEvent {
275            .direction = direction,
276            .coefficient = coefficient,
277        }));
278    if (ret != Channel<CooperateEvent>::NO_ERROR) {
279        FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
280    }
281    return RET_OK;
282}
283
284void Cooperate::Dump(int32_t fd)
285{
286    CALL_DEBUG_ENTER;
287    auto ret = context_.Sender().Send(CooperateEvent(
288        CooperateEventType::DUMP,
289        DumpEvent {
290            .fd = fd
291        }));
292    if (ret != Channel<CooperateEvent>::NO_ERROR) {
293        FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
294    }
295}
296
297void Cooperate::Loop()
298{
299    CALL_DEBUG_ENTER;
300    bool running = true;
301    SetThreadName("OS_Cooperate");
302    LoadMotionDrag();
303
304    while (running) {
305        CooperateEvent event = receiver_.Receive();
306        switch (event.type) {
307            case CooperateEventType::NOOP: {
308                break;
309            }
310            case CooperateEventType::QUIT: {
311                FI_HILOGI("Skip out of loop");
312                running = false;
313                break;
314            }
315            case CooperateEventType::SET_DAMPLING_COEFFICIENT: {
316                SetDamplingCoefficient(event);
317                break;
318            }
319            default: {
320                sm_.OnEvent(context_, event);
321                break;
322            }
323        }
324    }
325}
326
327void Cooperate::StartWorker()
328{
329    CALL_DEBUG_ENTER;
330    std::lock_guard guard(lock_);
331    if (!workerStarted_) {
332        workerStarted_ = true;
333        worker_ = std::thread([this] { this->Loop(); });
334    }
335}
336
337void Cooperate::StopWorker()
338{
339    CALL_DEBUG_ENTER;
340    std::lock_guard guard(lock_);
341    if (workerStarted_) {
342        auto ret = context_.Sender().Send(CooperateEvent(CooperateEventType::QUIT));
343        if (ret != Channel<CooperateEvent>::NO_ERROR) {
344            FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
345        }
346        if (worker_.joinable()) {
347            worker_.join();
348        }
349        workerStarted_ = false;
350    }
351}
352
353void Cooperate::LoadMotionDrag()
354{
355    FI_HILOGI("Load 'MotionDrag' module");
356    IMotionDrag *motionDrag = env_->GetPluginManager().LoadMotionDrag();
357    if (motionDrag == nullptr) {
358        FI_HILOGE("Failed to load motion drag");
359        return;
360    }
361    motionDrag->Enable(context_.EventHandler());
362}
363
364void Cooperate::SetDamplingCoefficient(const CooperateEvent &event)
365{
366    SetDamplingCoefficientEvent notice = std::get<SetDamplingCoefficientEvent>(event.event);
367    context_.inputEventBuilder_.SetDamplingCoefficient(notice.direction, notice.coefficient);
368}
369
370extern "C" ICooperate* CreateInstance(IContext *env)
371{
372    CHKPP(env);
373    return new Cooperate(env);
374}
375
376extern "C" void DestroyInstance(ICooperate *instance)
377{
378    if (instance != nullptr) {
379        delete instance;
380    }
381}
382} // namespace Cooperate
383} // namespace DeviceStatus
384} // namespace Msdp
385} // namespace OHOS