* Copyright (c) 2023-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cooperate.h"
#include "cooperate_hisysevent.h"
#ifdef ENABLE_PERFORMANCE_CHECK
#include <sstream>
#include "utility.h"
#endif
#include "devicestatus_define.h"
#undef LOG_TAG
#define LOG_TAG "Cooperate"
namespace OHOS {
namespace Msdp {
namespace DeviceStatus {
namespace Cooperate {
Cooperate::Cooperate(IContext *env)
: env_(env), context_(env), sm_(env)
{
auto [sender, receiver] = Channel<CooperateEvent>::OpenChannel();
receiver_ = receiver;
receiver_.Enable();
context_.AttachSender(sender);
context_.Enable();
StartWorker();
}
Cooperate::~Cooperate()
{
CALL_INFO_TRACE;
StopWorker();
context_.Disable();
}
void Cooperate::AddObserver(std::shared_ptr<ICooperateObserver> observer)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::ADD_OBSERVER,
AddObserverEvent {
.observer = observer
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
}
void Cooperate::RemoveObserver(std::shared_ptr<ICooperateObserver> observer)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::REMOVE_OBSERVER,
RemoveObserverEvent {
.observer = observer
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
}
int32_t Cooperate::RegisterListener(int32_t pid)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::REGISTER_LISTENER,
RegisterListenerEvent {
.pid = pid
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::UnregisterListener(int32_t pid)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::UNREGISTER_LISTENER,
UnregisterListenerEvent {
.pid = pid
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::RegisterHotAreaListener(int32_t pid)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::REGISTER_HOTAREA_LISTENER,
RegisterHotareaListenerEvent {
.pid = pid
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::UnregisterHotAreaListener(int32_t pid)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::UNREGISTER_HOTAREA_LISTENER,
UnregisterHotareaListenerEvent {
.pid = pid
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::Enable(int32_t tokenId, int32_t pid, int32_t userData)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::ENABLE,
EnableCooperateEvent {
.tokenId = tokenId,
.pid = pid,
.userData = userData,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::Disable(int32_t pid, int32_t userData)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::DISABLE,
DisableCooperateEvent {
.pid = pid,
.userData = userData,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::Start(int32_t pid, int32_t userData, const std::string &remoteNetworkId,
int32_t startDeviceId, const int32_t uid)
{
CALL_DEBUG_ENTER;
CooperateRadarInfo radarInfo {
.funcName = __FUNCTION__,
.bizState = static_cast<int32_t> (BizState::STATE_END),
.bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_ACTIVE),
.hostName = "",
.localNetId = Utility::DFXRadarAnonymize(context_.Local().c_str()),
.peerNetId = Utility::DFXRadarAnonymize(remoteNetworkId.c_str())
};
if (!sm_.IsCooperateEnable()) {
radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_LOCAL_SWITCH);
radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_LOCAL_SWITCH_FAILED);
CooperateRadar::ReportCooperateRadarInfo(radarInfo);
}
#ifdef ENABLE_PERFORMANCE_CHECK
std::ostringstream ss;
ss << "start_cooperation_with_" << Utility::Anonymize(remoteNetworkId).c_str();
context_.StartTrace(ss.str());
#endif
StartCooperateEvent event {
.pid = pid,
.userData = userData,
.remoteNetworkId = remoteNetworkId,
.startDeviceId = startDeviceId,
.errCode = std::make_shared<std::promise<int32_t>>(),
.uid = uid,
};
auto errCode = event.errCode->get_future();
auto ret = context_.Sender().Send(CooperateEvent(CooperateEventType::START, event));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
if (ret != RET_OK) {
radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CALLING_COOPERATE);
radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CALLING_COOPERATE_FAILED);
CooperateRadar::ReportCooperateRadarInfo(radarInfo);
};
radarInfo.bizState = static_cast<int32_t> (BizState::STATE_BEGIN),
radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_SUCCESS),
radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CALLING_COOPERATE_SUCCESS),
CooperateRadar::ReportCooperateRadarInfo(radarInfo);
return errCode.get();
}
int32_t Cooperate::Stop(int32_t pid, int32_t userData, bool isUnchained)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::STOP,
StopCooperateEvent {
.pid = pid,
.userData = userData,
.isUnchained = isUnchained,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::StartWithOptions(int32_t pid, int32_t userData, const std::string &remoteNetworkId,
int32_t startDeviceId, const CooperateOptions &options)
{
CALL_DEBUG_ENTER;
CooperateRadarInfo radarInfo {
.funcName = __FUNCTION__,
.bizState = static_cast<int32_t> (BizState::STATE_END),
.bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_ACTIVE),
.hostName = "",
.localNetId = Utility::DFXRadarAnonymize(context_.Local().c_str()),
.peerNetId = Utility::DFXRadarAnonymize(remoteNetworkId.c_str())
};
if (!sm_.IsCooperateEnable()) {
radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_LOCAL_SWITCH);
radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_LOCAL_SWITCH_FAILED);
CooperateRadar::ReportCooperateRadarInfo(radarInfo);
}
#ifdef ENABLE_PERFORMANCE_CHECK
std::ostringstream ss;
ss << "start_cooperation_with_" << Utility::Anonymize(remoteNetworkId).c_str();
context_.StartTrace(ss.str());
#endif
StartWithOptionsEvent event {
.pid = pid,
.userData = userData,
.remoteNetworkId = remoteNetworkId,
.startDeviceId = startDeviceId,
.displayX = options.displayX,
.displayY = options.displayY,
.displayId = options.displayId,
.errCode = std::make_shared<std::promise<int32_t>>(),
};
FI_HILOGI("Server start cooperate,displayX:%{private}d,displayY:%{private}d,displayId:%{public}d",
event.displayX, event.displayY, event.displayId);
auto errCode = event.errCode->get_future();
auto ret = context_.Sender().Send(CooperateEvent(CooperateEventType::WITH_OPTIONS_START, event));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
if (ret != RET_OK) {
radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CALLING_COOPERATE);
radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CALLING_COOPERATE_FAILED);
CooperateRadar::ReportCooperateRadarInfo(radarInfo);
};
radarInfo.bizState = static_cast<int32_t> (BizState::STATE_BEGIN),
radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_SUCCESS),
radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CALLING_COOPERATE_SUCCESS),
CooperateRadar::ReportCooperateRadarInfo(radarInfo);
return errCode.get();
}
int32_t Cooperate::GetCooperateState(int32_t pid, int32_t userData, const std::string &networkId)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::GET_COOPERATE_STATE,
GetCooperateStateEvent {
.pid = pid,
.userData = userData,
.networkId = networkId,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::RegisterEventListener(int32_t pid, const std::string &networkId)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::REGISTER_EVENT_LISTENER,
RegisterEventListenerEvent {
.pid = pid,
.networkId = networkId,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::UnregisterEventListener(int32_t pid, const std::string &networkId)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::UNREGISTER_EVENT_LISTENER,
UnregisterEventListenerEvent {
.pid = pid,
.networkId = networkId,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::GetCooperateState(const std::string &udId, bool &state)
{
CALL_DEBUG_ENTER;
state = sm_.IsCooperateEnable();
return RET_OK;
}
int32_t Cooperate::Update(uint32_t mask, uint32_t flag)
{
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::UPDATE_COOPERATE_FLAG,
UpdateCooperateFlagEvent {
.mask = mask,
.flag = flag,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
int32_t Cooperate::SetDamplingCoefficient(uint32_t direction, double coefficient)
{
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::SET_DAMPLING_COEFFICIENT,
SetDamplingCoefficientEvent {
.direction = direction,
.coefficient = coefficient,
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
return RET_OK;
}
void Cooperate::Dump(int32_t fd)
{
CALL_DEBUG_ENTER;
auto ret = context_.Sender().Send(CooperateEvent(
CooperateEventType::DUMP,
DumpEvent {
.fd = fd
}));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
}
void Cooperate::Loop()
{
CALL_DEBUG_ENTER;
bool running = true;
SetThreadName("OS_Cooperate");
LoadMotionDrag();
while (running) {
CooperateEvent event = receiver_.Receive();
switch (event.type) {
case CooperateEventType::NOOP: {
break;
}
case CooperateEventType::QUIT: {
FI_HILOGI("Skip out of loop");
running = false;
break;
}
case CooperateEventType::SET_DAMPLING_COEFFICIENT: {
SetDamplingCoefficient(event);
break;
}
default: {
sm_.OnEvent(context_, event);
break;
}
}
}
}
void Cooperate::StartWorker()
{
CALL_INFO_TRACE;
std::lock_guard guard(lock_);
if (!workerStarted_) {
workerStarted_ = true;
worker_ = std::thread([this] { this->Loop(); });
}
}
void Cooperate::StopWorker()
{
CALL_INFO_TRACE;
std::lock_guard guard(lock_);
if (workerStarted_) {
auto ret = context_.Sender().Send(CooperateEvent(CooperateEventType::QUIT));
if (ret != Channel<CooperateEvent>::NO_ERROR) {
FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
}
if (worker_.joinable()) {
worker_.join();
}
workerStarted_ = false;
}
}
void Cooperate::LoadMotionDrag()
{
FI_HILOGI("Load 'MotionDrag' module");
CHKPV(env_);
IMotionDrag *motionDrag = env_->GetPluginManager().LoadMotionDrag();
if (motionDrag == nullptr) {
FI_HILOGE("Failed to load motion drag");
return;
}
motionDrag->Enable(context_.EventHandler());
}
void Cooperate::SetDamplingCoefficient(const CooperateEvent &event)
{
if (std::holds_alternative<SetDamplingCoefficientEvent>(event.event)) {
SetDamplingCoefficientEvent notice = std::get<SetDamplingCoefficientEvent>(event.event);
context_.inputEventBuilder_.SetDamplingCoefficient(notice.direction, notice.coefficient);
} else {
FI_HILOGE("event type is not SetDamplingCoefficientEvent");
}
}
extern "C" ICooperate* CreateInstance(IContext *env)
{
CHKPP(env);
return new Cooperate(env);
}
extern "C" void DestroyInstance(ICooperate *instance)
{
if (instance != nullptr) {
delete instance;
}
}
}
}
}
}