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