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