• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "res_sched_exe_client.h"
16 
17 #include <new>
18 #include <string>
19 #include <unistd.h>
20 #include <unordered_map>
21 #include <utility>
22 
23 #include "if_system_ability_manager.h"
24 #include "iremote_broker.h"
25 #include "iservice_registry.h"
26 #include "system_ability_definition.h"
27 
28 #include "res_common_util.h"
29 #include "res_exe_type.h"
30 #include "res_json_type.h"
31 #include "res_sched_exe_constants.h"
32 #include "res_sched_exe_log.h"
33 
34 namespace OHOS {
35 namespace ResourceSchedule {
36 const int32_t MAX_IPC_MESSAGE_SIZE = 200000;
37 const int32_t IPC_BATCHES_SIZE = 180000;
38 
GetInstance()39 ResSchedExeClient& ResSchedExeClient::GetInstance()
40 {
41     static ResSchedExeClient instance;
42     return instance;
43 }
44 
~ResSchedExeClient()45 ResSchedExeClient::~ResSchedExeClient()
46 {
47     StopRemoteObject();
48 }
49 
SendRequestSync(uint32_t resType,int64_t value,const nlohmann::json & context,nlohmann::json & reply)50 int32_t ResSchedExeClient::SendRequestSync(uint32_t resType, int64_t value,
51     const nlohmann::json& context, nlohmann::json& reply)
52 {
53     if (resType == ResExeType::RES_TYPE_EXECUTOR_PLUGIN_INIT) {
54         std::vector<nlohmann::json> splitContext;
55         if (ProcessJson(context, splitContext, resType)) {
56             return SendRequestBatches(true, resType, splitContext, value, reply);
57         }
58     }
59     return SendRequestInner(true, resType, value, context, reply);
60 }
61 
SendRequestAsync(uint32_t resType,int64_t value,const nlohmann::json & context)62 void ResSchedExeClient::SendRequestAsync(uint32_t resType, int64_t value,
63     const nlohmann::json& context)
64 {
65     nlohmann::json reply;
66     if (resType == ResExeType::RES_TYPE_EXECUTOR_PLUGIN_INIT) {
67         std::vector<nlohmann::json> splitContext;
68         if (ProcessJson(context, splitContext, resType)) {
69             SendRequestBatches(false, resType, splitContext, value, reply);
70             return;
71         }
72     }
73     SendRequestInner(false, resType, value, context, reply);
74 }
75 
SendRequestBatches(bool isSync,uint32_t resType,const std::vector<nlohmann::json> & splitContext,int64_t value,nlohmann::json & reply)76 int32_t ResSchedExeClient::SendRequestBatches(bool isSync, uint32_t resType,
77     const std::vector<nlohmann::json>& splitContext, int64_t value, nlohmann::json& reply)
78 {
79     int32_t ret = ResErrCode::RSSEXE_NO_ERR;
80     RSSEXE_LOGI("ipc messages exceed the limit and are transmitted in batches.");
81     for (const nlohmann::json& jsonMsg : splitContext) {
82         RSSEXE_LOGD("ipc messages index: %{public}d", jsonMsg["MESSAGE_INDEX"].get<int>());
83         ret = SendRequestInner(isSync, resType, value, jsonMsg, reply);
84         if (ret != ResErrCode::RSSEXE_NO_ERR) {
85             RSSEXE_LOGE("SendRequestInner failed.");
86             break;
87         }
88     }
89     return ret;
90 }
91 
KillProcess(pid_t pid)92 int32_t ResSchedExeClient::KillProcess(pid_t pid)
93 {
94     RSSEXE_LOGD("kill process receive pid = %{public}d", pid);
95     auto proxy = GetProxy();
96     if (proxy == nullptr) {
97         RSSEXE_LOGE("fail to get resource schedule executor");
98         return ResIpcErrCode::RSSEXE_CONNECT_FAIL;
99     }
100     int32_t funcResult = ResIpcErrCode::RSSEXE_GET_SERVICE_FAIL;
101     proxy->KillProcess(static_cast<uint32_t>(pid), funcResult);
102     return funcResult;
103 }
104 
SendRequestInner(bool isSync,uint32_t resType,int64_t value,const nlohmann::json & context,nlohmann::json & reply)105 int32_t ResSchedExeClient::SendRequestInner(bool isSync, uint32_t resType, int64_t value,
106     const nlohmann::json& context, nlohmann::json& reply)
107 {
108     RSSEXE_LOGD("receive resType = %{public}u, value = %{public}lld.", resType, (long long)value);
109     auto proxy = GetProxy();
110     if (proxy == nullptr) {
111         RSSEXE_LOGE("fail to get resource schedule executor.");
112         return ResIpcErrCode::RSSEXE_CONNECT_FAIL;
113     }
114 
115     ResJsonType jsonTypeContext;
116     jsonTypeContext.jsonContext = context;
117     if (isSync) {
118         RSSEXE_LOGD("ResSchedExeClient send sync request, resType = %{public}u", resType);
119         ResJsonType jsonTypeReply;
120         int32_t funcResult;
121         proxy->SendRequestSync(resType, value, jsonTypeContext, jsonTypeReply, funcResult);
122         reply = jsonTypeReply.jsonContext;
123         return funcResult;
124     } else {
125         RSSEXE_LOGD("ResSchedExeClient send async request, resType = %{public}u", resType);
126         proxy->SendRequestAsync(resType, value, jsonTypeContext);
127         return ResErrCode::RSSEXE_NO_ERR;
128     }
129 }
130 
ProcessJson(const nlohmann::json & context,std::vector<nlohmann::json> & splitContext,int32_t resType)131 bool ResSchedExeClient::ProcessJson(const nlohmann::json& context, std::vector<nlohmann::json>& splitContext,
132     int32_t resType)
133 {
134     std::string dumpJsonStr = context.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace);
135     size_t dumpJsonStrSize = dumpJsonStr.size();
136     if (dumpJsonStrSize > MAX_IPC_MESSAGE_SIZE) {
137         RSSEXE_LOGI("ResSchedExeClient need to split the json in restype %{public}d.", resType);
138         std::vector<std::string> messageValue;
139         for (size_t idx = 0; idx < dumpJsonStrSize; idx += IPC_BATCHES_SIZE) {
140             size_t end = std::min(idx + IPC_BATCHES_SIZE, dumpJsonStrSize);
141             messageValue.push_back(dumpJsonStr.substr(idx, end - idx));
142         }
143 
144         int messageIndex = 0;
145         for (std::string msg : messageValue) {
146             nlohmann::json jsonIpc = {
147                 {"IPC_MESSAGE", msg},
148                 {"MESSAGE_INDEX", messageIndex},
149                 {"MESSAGE_NUMBER", static_cast<int>(messageValue.size())}
150             };
151             splitContext.push_back(jsonIpc);
152             messageIndex++;
153         }
154         return true;
155     }
156     return false;
157 }
158 
SendDebugCommand(bool isSync)159 void ResSchedExeClient::SendDebugCommand(bool isSync)
160 {
161     nlohmann::json tempJson;
162     SendRequestInner(isSync, ResExeType::RES_TYPE_DEBUG, 0, tempJson, tempJson);
163 }
164 
GetProxy()165 sptr<IResSchedExeService> ResSchedExeClient::GetProxy()
166 {
167     if (TryConnect() == ResErrCode::RSSEXE_NO_ERR) {
168         std::lock_guard<std::mutex> lock(mutex_);
169         return resSchedExe_;
170     }
171     return nullptr;
172 }
173 
TryConnect()174 ErrCode ResSchedExeClient::TryConnect()
175 {
176     std::lock_guard<std::mutex> lock(mutex_);
177     if (resSchedExe_) {
178         return ResErrCode::RSSEXE_NO_ERR;
179     }
180 
181     sptr<ISystemAbilityManager> systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
182     if (!systemManager) {
183         RSSEXE_LOGE("Fail to get registry.");
184         return ResIpcErrCode::RSSEXE_GET_SERVICE_FAIL;
185     }
186 
187     remoteObject_ = systemManager->CheckSystemAbility(RES_SCHED_EXE_ABILITY_ID);
188     if (!remoteObject_) {
189         RSSEXE_LOGE("Fail to connect resource schedule executor.");
190         return ResIpcErrCode::RSSEXE_GET_SERVICE_FAIL;
191     }
192 
193     resSchedExe_ = iface_cast<IResSchedExeService>(remoteObject_);
194     if (!resSchedExe_) {
195         return ResIpcErrCode::RSSEXE_GET_SERVICE_FAIL;
196     }
197     recipient_ = new (std::nothrow) ResSchedExeDeathRecipient(*this);
198     if (!recipient_) {
199         RSSEXE_LOGE("New ResSchedDeathRecipient failed.");
200         return ResIpcErrCode::RSSEXE_GET_SERVICE_FAIL;
201     }
202     resSchedExe_->AsObject()->AddDeathRecipient(recipient_);
203     RSSEXE_LOGD("Connect resource schedule executor success.");
204     return ResErrCode::RSSEXE_NO_ERR;
205 }
206 
StopRemoteObject()207 void ResSchedExeClient::StopRemoteObject()
208 {
209     std::lock_guard<std::mutex> lock(mutex_);
210     if (resSchedExe_ && resSchedExe_->AsObject()) {
211         resSchedExe_->AsObject()->RemoveDeathRecipient(recipient_);
212     }
213     resSchedExe_ = nullptr;
214 }
215 
ResSchedExeDeathRecipient(ResSchedExeClient & resSchedExeClient)216 ResSchedExeClient::ResSchedExeDeathRecipient::ResSchedExeDeathRecipient(ResSchedExeClient& resSchedExeClient)
217     : resSchedExeClient_(resSchedExeClient) {}
218 
~ResSchedExeDeathRecipient()219 ResSchedExeClient::ResSchedExeDeathRecipient::~ResSchedExeDeathRecipient() {}
220 
OnRemoteDied(const wptr<IRemoteObject> & remote)221 void ResSchedExeClient::ResSchedExeDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remote)
222 {
223     resSchedExeClient_.StopRemoteObject();
224 }
225 } // namespace ResourceSchedule
226 } // namespace OHOS
227