1f857971dSopenharmony_ci/*
2f857971dSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3f857971dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4f857971dSopenharmony_ci * you may not use this file except in compliance with the License.
5f857971dSopenharmony_ci * You may obtain a copy of the License at
6f857971dSopenharmony_ci *
7f857971dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8f857971dSopenharmony_ci *
9f857971dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10f857971dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11f857971dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12f857971dSopenharmony_ci * See the License for the specific language governing permissions and
13f857971dSopenharmony_ci * limitations under the License.
14f857971dSopenharmony_ci */
15f857971dSopenharmony_ci
16f857971dSopenharmony_ci#include "cooperate_server.h"
17f857971dSopenharmony_ci
18f857971dSopenharmony_ci#include <chrono>
19f857971dSopenharmony_ci
20f857971dSopenharmony_ci#include <tokenid_kit.h>
21f857971dSopenharmony_ci
22f857971dSopenharmony_ci#include "accesstoken_kit.h"
23f857971dSopenharmony_ci#include "cooperate_params.h"
24f857971dSopenharmony_ci#include "default_params.h"
25f857971dSopenharmony_ci#include "devicestatus_define.h"
26f857971dSopenharmony_ci#include "ipc_skeleton.h"
27f857971dSopenharmony_ci#include "utility.h"
28f857971dSopenharmony_ci
29f857971dSopenharmony_ci#undef LOG_TAG
30f857971dSopenharmony_ci#define LOG_TAG "CooperateServer"
31f857971dSopenharmony_ci
32f857971dSopenharmony_cinamespace OHOS {
33f857971dSopenharmony_cinamespace Msdp {
34f857971dSopenharmony_cinamespace DeviceStatus {
35f857971dSopenharmony_cinamespace {
36f857971dSopenharmony_ciconstexpr int32_t REPEAT_ONCE { 1 };
37f857971dSopenharmony_ciconstexpr int32_t DEFAULT_UNLOAD_COOLING_TIME_MS { 60000 };
38f857971dSopenharmony_ciconstexpr int32_t SYNC_TASK_TIMEOUT_DURATION { 2500 };
39f857971dSopenharmony_ci}
40f857971dSopenharmony_ci
41f857971dSopenharmony_ciCooperateServer::CooperateServer(IContext *context)
42f857971dSopenharmony_ci    : context_(context)
43f857971dSopenharmony_ci{}
44f857971dSopenharmony_ci
45f857971dSopenharmony_ciint32_t CooperateServer::Enable(CallingContext &context, MessageParcel &data, MessageParcel &reply)
46f857971dSopenharmony_ci{
47f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
48f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
49f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
50f857971dSopenharmony_ci        return ret;
51f857971dSopenharmony_ci    }
52f857971dSopenharmony_ci    DefaultParam param;
53f857971dSopenharmony_ci    if (!param.Unmarshalling(data)) {
54f857971dSopenharmony_ci        FI_HILOGE("DefaultParam::Unmarshalling fail");
55f857971dSopenharmony_ci        return RET_ERR;
56f857971dSopenharmony_ci    }
57f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
58f857971dSopenharmony_ci    if (unloadTimerId_ >= 0) {
59f857971dSopenharmony_ci        context_->GetTimerManager().RemoveTimer(unloadTimerId_);
60f857971dSopenharmony_ci    }
61f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
62f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
63f857971dSopenharmony_ci    cooperate->Enable(context.tokenId, context.pid, param.userData);
64f857971dSopenharmony_ci    return RET_OK;
65f857971dSopenharmony_ci}
66f857971dSopenharmony_ci
67f857971dSopenharmony_ciint32_t CooperateServer::Disable(CallingContext &context, MessageParcel &data, MessageParcel &reply)
68f857971dSopenharmony_ci{
69f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
70f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
71f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
72f857971dSopenharmony_ci        return ret;
73f857971dSopenharmony_ci    }
74f857971dSopenharmony_ci    DefaultParam param;
75f857971dSopenharmony_ci    if (!param.Unmarshalling(data)) {
76f857971dSopenharmony_ci        FI_HILOGE("DefaultParam::Unmarshalling fail");
77f857971dSopenharmony_ci        return RET_ERR;
78f857971dSopenharmony_ci    }
79f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
80f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
81f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
82f857971dSopenharmony_ci    cooperate->Disable(context.pid, param.userData);
83f857971dSopenharmony_ci    unloadTimerId_ = context_->GetTimerManager().AddTimer(DEFAULT_UNLOAD_COOLING_TIME_MS, REPEAT_ONCE,
84f857971dSopenharmony_ci        []() {
85f857971dSopenharmony_ci            FI_HILOGI("Unload \'cooperate\' module");
86f857971dSopenharmony_ci        });
87f857971dSopenharmony_ci    if (unloadTimerId_ < 0) {
88f857971dSopenharmony_ci        FI_HILOGE("AddTimer failed, will not unload Cooperate");
89f857971dSopenharmony_ci    }
90f857971dSopenharmony_ci    return RET_OK;
91f857971dSopenharmony_ci}
92f857971dSopenharmony_ci
93f857971dSopenharmony_ciint32_t CooperateServer::Start(CallingContext &context, MessageParcel &data, MessageParcel &reply)
94f857971dSopenharmony_ci{
95f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
96f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
97f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
98f857971dSopenharmony_ci        return ret;
99f857971dSopenharmony_ci    }
100f857971dSopenharmony_ci    StartCooperateParam param;
101f857971dSopenharmony_ci    if (!param.Unmarshalling(data)) {
102f857971dSopenharmony_ci        FI_HILOGE("StartCooperateParam::Unmarshalling fail");
103f857971dSopenharmony_ci        return RET_ERR;
104f857971dSopenharmony_ci    }
105f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
106f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
107f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
108f857971dSopenharmony_ci    return cooperate->Start(context.pid, param.userData, param.remoteNetworkId, param.startDeviceId);
109f857971dSopenharmony_ci}
110f857971dSopenharmony_ci
111f857971dSopenharmony_ciint32_t CooperateServer::Stop(CallingContext &context, MessageParcel &data, MessageParcel &reply)
112f857971dSopenharmony_ci{
113f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
114f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
115f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
116f857971dSopenharmony_ci        return ret;
117f857971dSopenharmony_ci    }
118f857971dSopenharmony_ci    StopCooperateParam param;
119f857971dSopenharmony_ci    if (!param.Unmarshalling(data)) {
120f857971dSopenharmony_ci        FI_HILOGE("StopCooperateParam::Unmarshalling fail");
121f857971dSopenharmony_ci        return RET_ERR;
122f857971dSopenharmony_ci    }
123f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
124f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
125f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
126f857971dSopenharmony_ci    return cooperate->Stop(context.pid, param.userData, param.isUnchained);
127f857971dSopenharmony_ci}
128f857971dSopenharmony_ci
129f857971dSopenharmony_ciint32_t CooperateServer::AddWatch(CallingContext &context, uint32_t id, MessageParcel &data, MessageParcel &reply)
130f857971dSopenharmony_ci{
131f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
132f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
133f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
134f857971dSopenharmony_ci        return ret;
135f857971dSopenharmony_ci    }
136f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
137f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
138f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
139f857971dSopenharmony_ci    switch (id) {
140f857971dSopenharmony_ci        case CooperateRequestID::REGISTER_LISTENER: {
141f857971dSopenharmony_ci            return cooperate->RegisterListener(context.pid);
142f857971dSopenharmony_ci        }
143f857971dSopenharmony_ci        case CooperateRequestID::REGISTER_HOTAREA_LISTENER: {
144f857971dSopenharmony_ci            return cooperate->RegisterHotAreaListener(context.pid);
145f857971dSopenharmony_ci        }
146f857971dSopenharmony_ci        case CooperateRequestID::REGISTER_EVENT_LISTENER: {
147f857971dSopenharmony_ci            RegisterEventListenerParam param;
148f857971dSopenharmony_ci            if (!param.Unmarshalling(data)) {
149f857971dSopenharmony_ci                FI_HILOGE("RegisterEventListenerParam::Unmarshalling fail");
150f857971dSopenharmony_ci                return RET_ERR;
151f857971dSopenharmony_ci            }
152f857971dSopenharmony_ci            return cooperate->RegisterEventListener(context.pid, param.networkId);
153f857971dSopenharmony_ci        }
154f857971dSopenharmony_ci        default: {
155f857971dSopenharmony_ci            FI_HILOGE("Unexpected request ID (%{public}u)", id);
156f857971dSopenharmony_ci            return RET_ERR;
157f857971dSopenharmony_ci        }
158f857971dSopenharmony_ci    }
159f857971dSopenharmony_ci}
160f857971dSopenharmony_ci
161f857971dSopenharmony_ciint32_t CooperateServer::RemoveWatch(CallingContext &context, uint32_t id, MessageParcel &data, MessageParcel &reply)
162f857971dSopenharmony_ci{
163f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
164f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
165f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
166f857971dSopenharmony_ci        return ret;
167f857971dSopenharmony_ci    }
168f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
169f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
170f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
171f857971dSopenharmony_ci    switch (id) {
172f857971dSopenharmony_ci        case CooperateRequestID::UNREGISTER_LISTENER: {
173f857971dSopenharmony_ci            return cooperate->UnregisterListener(context.pid);
174f857971dSopenharmony_ci        }
175f857971dSopenharmony_ci        case CooperateRequestID::UNREGISTER_HOTAREA_LISTENER: {
176f857971dSopenharmony_ci            return cooperate->UnregisterHotAreaListener(context.pid);
177f857971dSopenharmony_ci        }
178f857971dSopenharmony_ci        case CooperateRequestID::UNREGISTER_EVENT_LISTENER: {
179f857971dSopenharmony_ci            UnregisterEventListenerParam param;
180f857971dSopenharmony_ci            if (!param.Unmarshalling(data)) {
181f857971dSopenharmony_ci                FI_HILOGE("UnregisterEventListenerParam::Unmarshalling fail");
182f857971dSopenharmony_ci                return RET_ERR;
183f857971dSopenharmony_ci            }
184f857971dSopenharmony_ci            return cooperate->UnregisterEventListener(context.pid, param.networkId);
185f857971dSopenharmony_ci        }
186f857971dSopenharmony_ci        default: {
187f857971dSopenharmony_ci            FI_HILOGE("Unexpected request ID (%{public}u)", id);
188f857971dSopenharmony_ci            return RET_ERR;
189f857971dSopenharmony_ci        }
190f857971dSopenharmony_ci    }
191f857971dSopenharmony_ci}
192f857971dSopenharmony_ci
193f857971dSopenharmony_ciint32_t CooperateServer::SetParam(CallingContext &context, uint32_t id, MessageParcel &data, MessageParcel &reply)
194f857971dSopenharmony_ci{
195f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
196f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
197f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
198f857971dSopenharmony_ci        return ret;
199f857971dSopenharmony_ci    }
200f857971dSopenharmony_ci    if (id != CooperateRequestID::SET_DAMPLING_COEFFICIENT) {
201f857971dSopenharmony_ci        FI_HILOGE("Unexpected request (%{public}u)", id);
202f857971dSopenharmony_ci        return RET_ERR;
203f857971dSopenharmony_ci    }
204f857971dSopenharmony_ci    SetDamplingCoefficientParam param {};
205f857971dSopenharmony_ci    if (!param.Unmarshalling(data)) {
206f857971dSopenharmony_ci        FI_HILOGE("SetDamplingCoefficientParam::Unmarshalling fail");
207f857971dSopenharmony_ci        return RET_ERR;
208f857971dSopenharmony_ci    }
209f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
210f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
211f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
212f857971dSopenharmony_ci    FI_HILOGI("SetDamplingCoefficient(0x%{public}x, %{public}.3f)", param.direction, param.coefficient);
213f857971dSopenharmony_ci    return cooperate->SetDamplingCoefficient(param.direction, param.coefficient);
214f857971dSopenharmony_ci}
215f857971dSopenharmony_ci
216f857971dSopenharmony_ciint32_t CooperateServer::GetParam(CallingContext &context, uint32_t id, MessageParcel &data, MessageParcel &reply)
217f857971dSopenharmony_ci{
218f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
219f857971dSopenharmony_ci    if (int32_t ret = CheckPermission(context); ret != RET_OK) {
220f857971dSopenharmony_ci        FI_HILOGE("CheckPermission failed, ret:%{public}d", ret);
221f857971dSopenharmony_ci        return ret;
222f857971dSopenharmony_ci    }
223f857971dSopenharmony_ci    CHKPR(context_, RET_ERR);
224f857971dSopenharmony_ci    ICooperate* cooperate = context_->GetPluginManager().LoadCooperate();
225f857971dSopenharmony_ci    CHKPR(cooperate, RET_ERR);
226f857971dSopenharmony_ci    auto enterStamp = std::chrono::steady_clock::now();
227f857971dSopenharmony_ci    auto checkParcelValid = [enterStamp] () {
228f857971dSopenharmony_ci        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
229f857971dSopenharmony_ci            std::chrono::steady_clock::now() - enterStamp).count();
230f857971dSopenharmony_ci            return duration < SYNC_TASK_TIMEOUT_DURATION;
231f857971dSopenharmony_ci    };
232f857971dSopenharmony_ci    switch (id) {
233f857971dSopenharmony_ci        case CooperateRequestID::GET_COOPERATE_STATE: {
234f857971dSopenharmony_ci            GetCooperateStateParam param;
235f857971dSopenharmony_ci            if (!param.Unmarshalling(data)) {
236f857971dSopenharmony_ci                FI_HILOGE("GetCooperateStateParam::Unmarshalling fail");
237f857971dSopenharmony_ci                return RET_ERR;
238f857971dSopenharmony_ci            }
239f857971dSopenharmony_ci            return cooperate->GetCooperateState(context.pid, param.userData, param.networkId);
240f857971dSopenharmony_ci        }
241f857971dSopenharmony_ci        case CooperateRequestID::GET_COOPERATE_STATE_SYNC: {
242f857971dSopenharmony_ci            GetCooperateStateSyncParam param;
243f857971dSopenharmony_ci            if (!param.Unmarshalling(data)) {
244f857971dSopenharmony_ci                FI_HILOGE("GetCooperateStateParam::Unmarshalling fail");
245f857971dSopenharmony_ci                return RET_ERR;
246f857971dSopenharmony_ci            }
247f857971dSopenharmony_ci            bool state { false };
248f857971dSopenharmony_ci            if (cooperate->GetCooperateState(param.udId, state) != RET_OK) {
249f857971dSopenharmony_ci                FI_HILOGE("GetCooperateState failed");
250f857971dSopenharmony_ci                return RET_ERR;
251f857971dSopenharmony_ci            }
252f857971dSopenharmony_ci            FI_HILOGI("GetCooperateState for udId:%{public}s successfully, state:%{public}s",
253f857971dSopenharmony_ci                Utility::Anonymize(param.udId).c_str(), state ? "true" : "false");
254f857971dSopenharmony_ci            if (!checkParcelValid()) {
255f857971dSopenharmony_ci                FI_HILOGE("CheckParcelValid failed");
256f857971dSopenharmony_ci                return RET_ERR;
257f857971dSopenharmony_ci            }
258f857971dSopenharmony_ci            if (!BooleanReply(state).Marshalling(reply)) {
259f857971dSopenharmony_ci                FI_HILOGE("Marshalling state failed");
260f857971dSopenharmony_ci                return RET_ERR;
261f857971dSopenharmony_ci            }
262f857971dSopenharmony_ci            return RET_OK;
263f857971dSopenharmony_ci        }
264f857971dSopenharmony_ci        default: {
265f857971dSopenharmony_ci            FI_HILOGE("Unexpected request ID (%{public}u)", id);
266f857971dSopenharmony_ci            return RET_ERR;
267f857971dSopenharmony_ci        }
268f857971dSopenharmony_ci    }
269f857971dSopenharmony_ci}
270f857971dSopenharmony_ci
271f857971dSopenharmony_ciint32_t CooperateServer::Control(CallingContext &context, uint32_t id, MessageParcel &data, MessageParcel &reply)
272f857971dSopenharmony_ci{
273f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
274f857971dSopenharmony_ci    return RET_ERR;
275f857971dSopenharmony_ci}
276f857971dSopenharmony_ci
277f857971dSopenharmony_cibool CooperateServer::CheckCooperatePermission(CallingContext &context)
278f857971dSopenharmony_ci{
279f857971dSopenharmony_ci    CALL_DEBUG_ENTER;
280f857971dSopenharmony_ci    Security::AccessToken::AccessTokenID callerToken = context.tokenId;
281f857971dSopenharmony_ci    int32_t result = Security::AccessToken::AccessTokenKit::VerifyAccessToken(callerToken,
282f857971dSopenharmony_ci        COOPERATE_PERMISSION);
283f857971dSopenharmony_ci    return result == Security::AccessToken::PERMISSION_GRANTED;
284f857971dSopenharmony_ci}
285f857971dSopenharmony_ci
286f857971dSopenharmony_cibool CooperateServer::IsSystemServiceCalling(CallingContext &context)
287f857971dSopenharmony_ci{
288f857971dSopenharmony_ci    const auto flag = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(context.tokenId);
289f857971dSopenharmony_ci    if (flag == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE ||
290f857971dSopenharmony_ci        flag == Security::AccessToken::ATokenTypeEnum::TOKEN_SHELL) {
291f857971dSopenharmony_ci        FI_HILOGD("system service calling, flag:%{public}u", flag);
292f857971dSopenharmony_ci        return true;
293f857971dSopenharmony_ci    }
294f857971dSopenharmony_ci    return false;
295f857971dSopenharmony_ci}
296f857971dSopenharmony_ci
297f857971dSopenharmony_cibool CooperateServer::IsSystemCalling(CallingContext &context)
298f857971dSopenharmony_ci{
299f857971dSopenharmony_ci    if (IsSystemServiceCalling(context)) {
300f857971dSopenharmony_ci        return true;
301f857971dSopenharmony_ci    }
302f857971dSopenharmony_ci    return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(context.fullTokenId);
303f857971dSopenharmony_ci}
304f857971dSopenharmony_ci
305f857971dSopenharmony_ciint32_t CooperateServer::CheckPermission(CallingContext &context)
306f857971dSopenharmony_ci{
307f857971dSopenharmony_ci    if (!IsSystemCalling(context)) {
308f857971dSopenharmony_ci        FI_HILOGE("The caller is not system hap");
309f857971dSopenharmony_ci        return COMMON_NOT_SYSTEM_APP;
310f857971dSopenharmony_ci    }
311f857971dSopenharmony_ci    if (!CheckCooperatePermission(context)) {
312f857971dSopenharmony_ci        FI_HILOGE("The caller has no COOPERATE_MANAGER permission");
313f857971dSopenharmony_ci        return COMMON_PERMISSION_CHECK_ERROR;
314f857971dSopenharmony_ci    }
315f857971dSopenharmony_ci    return RET_OK;
316f857971dSopenharmony_ci}
317f857971dSopenharmony_ci} // namespace DeviceStatus
318f857971dSopenharmony_ci} // namespace Msdp
319f857971dSopenharmony_ci} // namespace OHOS