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