1 /*
2 * Copyright (c) 2022 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 "remote_command_executor.h"
17 #include "constant_common.h"
18 #include "device_info_manager.h"
19 #include "singleton.h"
20 #include "soft_bus_channel.h"
21 #include "token_sync_event_handler.h"
22 #include "token_sync_manager_service.h"
23
24 namespace OHOS {
25 namespace Security {
26 namespace AccessToken {
27 namespace {
28 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "RemoteCommandExecutor"};
29 static const std::string TASK_NAME = "RemoteCommandExecutor::ProcessBufferedCommandsWithThread";
30 } // namespace
RemoteCommandExecutor(const std::string & targetNodeId)31 RemoteCommandExecutor::RemoteCommandExecutor(const std::string &targetNodeId)
32 : targetNodeId_(targetNodeId), ptrChannel_(nullptr), mutex_(), commands_(), running_(false)
33 {
34 ACCESSTOKEN_LOG_DEBUG(LABEL, "RemoteCommandExecutor()");
35 }
36
~RemoteCommandExecutor()37 RemoteCommandExecutor::~RemoteCommandExecutor()
38 {
39 ACCESSTOKEN_LOG_DEBUG(LABEL, "~RemoteCommandExecutor() begin");
40 running_ = false;
41 }
42
CreateChannel(const std::string & targetNodeId)43 const std::shared_ptr<RpcChannel> RemoteCommandExecutor::CreateChannel(const std::string &targetNodeId)
44 {
45 ACCESSTOKEN_LOG_DEBUG(LABEL, "CreateChannel: targetNodeId=%{public}s",
46 ConstantCommon::EncryptDevId(targetNodeId).c_str());
47 // only consider SoftBusChannel
48 std::shared_ptr<RpcChannel> ptrChannel = std::make_shared<SoftBusChannel>(targetNodeId);
49 return ptrChannel;
50 }
51
52 /*
53 * called by RemoteCommandExecutor, RemoteCommandManager
54 */
ProcessOneCommand(const std::shared_ptr<BaseRemoteCommand> & ptrCommand)55 int RemoteCommandExecutor::ProcessOneCommand(const std::shared_ptr<BaseRemoteCommand>& ptrCommand)
56 {
57 if (ptrCommand == nullptr) {
58 ACCESSTOKEN_LOG_WARN(LABEL, "targetNodeId %{public}s, attempt to process on null command.",
59 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
60 return Constant::SUCCESS;
61 }
62 const std::string uniqueId = ptrCommand->remoteProtocol_.uniqueId;
63 ACCESSTOKEN_LOG_INFO(LABEL, "targetNodeId %{public}s, process one command start, uniqueId: %{public}s",
64 ConstantCommon::EncryptDevId(targetNodeId_).c_str(), uniqueId.c_str());
65
66 ptrCommand->Prepare();
67 int status = ptrCommand->remoteProtocol_.statusCode;
68 if (status != Constant::SUCCESS) {
69 ACCESSTOKEN_LOG_ERROR(LABEL,
70 "targetNodeId %{public}s, process one command error, uniqueId: %{public}s, message: "
71 "prepare failure code %{public}d", ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
72 uniqueId.c_str(), status);
73 return status;
74 }
75
76 std::string localUdid = ConstantCommon::GetLocalDeviceId();
77 if (targetNodeId_ == localUdid) {
78 return ExecuteRemoteCommand(ptrCommand, false);
79 }
80
81 // otherwise a remote device
82 CreateChannelIfNeeded();
83 if (ptrChannel_ == nullptr) {
84 ACCESSTOKEN_LOG_ERROR(LABEL, "targetNodeId %{public}s, channel is null.",
85 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
86 return Constant::FAILURE;
87 }
88 if (ptrChannel_->BuildConnection() != Constant::SUCCESS) {
89 ACCESSTOKEN_LOG_ERROR(LABEL, "targetNodeId %{public}s, channel is not ready.",
90 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
91 return Constant::FAILURE;
92 }
93
94 return ExecuteRemoteCommand(ptrCommand, true);
95 }
96
97 /*
98 * called by RemoteCommandManager
99 */
AddCommand(const std::shared_ptr<BaseRemoteCommand> & ptrCommand)100 int RemoteCommandExecutor::AddCommand(const std::shared_ptr<BaseRemoteCommand>& ptrCommand)
101 {
102 if (ptrCommand == nullptr) {
103 ACCESSTOKEN_LOG_DEBUG(LABEL, "targetNodeId %{public}s, attempt to add an empty command.",
104 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
105 return Constant::INVALID_COMMAND;
106 }
107
108 const std::string uniqueId = ptrCommand->remoteProtocol_.uniqueId;
109 ACCESSTOKEN_LOG_DEBUG(LABEL, "targetNodeId %{public}s, add uniqueId %{public}s",
110 ConstantCommon::EncryptDevId(targetNodeId_).c_str(), uniqueId.c_str());
111
112 std::unique_lock<std::recursive_mutex> lock(mutex_);
113
114 // make sure do not have the same command in the command buffer
115 if (std::any_of(commands_.begin(), commands_.end(),
116 [uniqueId](const auto& buffCommand) {return buffCommand->remoteProtocol_.uniqueId == uniqueId; })) {
117 ACCESSTOKEN_LOG_WARN(LABEL,
118 "targetNodeId %{public}s, add uniqueId %{public}s, already exist in the buffer, skip",
119 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
120 uniqueId.c_str());
121 return Constant::SUCCESS;
122 }
123
124 commands_.push_back(ptrCommand);
125 return Constant::SUCCESS;
126 }
127
128 /*
129 * called by RemoteCommandExecutor.ProcessCommandThread, RemoteCommandManager
130 */
ProcessBufferedCommands(bool standalone)131 int RemoteCommandExecutor::ProcessBufferedCommands(bool standalone)
132 {
133 ACCESSTOKEN_LOG_INFO(LABEL, "begin, targetNodeId: %{public}s, standalone: %{public}d",
134 ConstantCommon::EncryptDevId(targetNodeId_).c_str(), standalone);
135
136 std::unique_lock<std::recursive_mutex> lock(mutex_);
137
138 if (commands_.empty()) {
139 ACCESSTOKEN_LOG_WARN(LABEL, "no command, targetNodeId %{public}s",
140 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
141 running_ = false;
142 return Constant::SUCCESS;
143 }
144
145 running_ = true;
146 while (true) {
147 // interrupt
148 if (!running_) {
149 ACCESSTOKEN_LOG_INFO(LABEL, "end with running flag == false, targetNodeId: %{public}s",
150 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
151 return Constant::FAILURE;
152 }
153 // end
154 if (commands_.empty()) {
155 running_ = false;
156 ACCESSTOKEN_LOG_INFO(LABEL, "end, no command left, targetNodeId: %{public}s",
157 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
158 return Constant::SUCCESS;
159 }
160
161 // consume queue to execute
162 const std::shared_ptr<BaseRemoteCommand> bufferedCommand = commands_.front();
163 int status = ProcessOneCommand(bufferedCommand);
164 if (status == Constant::SUCCESS) {
165 commands_.pop_front();
166 continue;
167 } else if (status == Constant::FAILURE_BUT_CAN_RETRY) {
168 ACCESSTOKEN_LOG_WARN(LABEL,
169 "execute failed and wait to retry, targetNodeId: %{public}s, message: %{public}s, and will retry ",
170 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
171 bufferedCommand->remoteProtocol_.message.c_str());
172
173 // now, the retry at once will have no effective because the network problem
174 // so if the before the step, one command is added, and run this function
175 // it should also not need to restart to process the commands buffer at once.
176 running_ = false;
177 return Constant::FAILURE;
178 } else {
179 // this command failed, move on to execute next command
180 commands_.pop_front();
181 ACCESSTOKEN_LOG_ERROR(LABEL,
182 "execute failed, targetNodeId: %{public}s, commandName: %{public}s, message: %{public}s",
183 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
184 bufferedCommand->remoteProtocol_.commandName.c_str(),
185 bufferedCommand->remoteProtocol_.message.c_str());
186 }
187 }
188 }
189
190 /*
191 * called by RemoteCommandManager
192 */
ProcessBufferedCommandsWithThread()193 void RemoteCommandExecutor::ProcessBufferedCommandsWithThread()
194 {
195 ACCESSTOKEN_LOG_INFO(LABEL, "begin, targetNodeId: %{public}s", ConstantCommon::EncryptDevId(targetNodeId_).c_str());
196
197 std::unique_lock<std::recursive_mutex> lock(mutex_);
198
199 if (commands_.empty()) {
200 ACCESSTOKEN_LOG_INFO(LABEL, "No buffered commands. targetNodeId: %{public}s",
201 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
202 return;
203 }
204 if (running_) {
205 // task is running, do not need to start one more
206 ACCESSTOKEN_LOG_WARN(LABEL, "task busy. targetNodeId: %{public}s",
207 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
208 return;
209 }
210
211 running_ = true;
212 const std::function<void()> runner = std::bind(&RemoteCommandExecutor::ProcessBufferedCommands, this, true);
213
214 std::shared_ptr<TokenSyncEventHandler> handler =
215 DelayedSingleton<TokenSyncManagerService>::GetInstance()->GetSendEventHandler();
216 if (handler == nullptr) {
217 ACCESSTOKEN_LOG_ERROR(LABEL, "fail to get EventHandler");
218 return;
219 }
220 bool result = handler->ProxyPostTask(runner, TASK_NAME);
221 if (!result) {
222 ACCESSTOKEN_LOG_ERROR(LABEL, "post task failed, targetNodeId: %{public}s",
223 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
224 }
225 ACCESSTOKEN_LOG_INFO(LABEL,
226 "post task succeed, targetNodeId: %{public}s, taskName: %{public}s",
227 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
228 TASK_NAME.c_str());
229 }
230
ExecuteRemoteCommand(const std::shared_ptr<BaseRemoteCommand> & ptrCommand,const bool isRemote)231 int RemoteCommandExecutor::ExecuteRemoteCommand(
232 const std::shared_ptr<BaseRemoteCommand>& ptrCommand, const bool isRemote)
233 {
234 std::string uniqueId = ptrCommand->remoteProtocol_.uniqueId;
235 ACCESSTOKEN_LOG_INFO(LABEL,
236 "targetNodeId %{public}s, uniqueId %{public}s, remote %{public}d: start to execute",
237 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
238 uniqueId.c_str(),
239 isRemote);
240
241 ptrCommand->remoteProtocol_.statusCode = Constant::STATUS_CODE_BEFORE_RPC;
242
243 if (!isRemote) {
244 // Local device, play myself.
245 ptrCommand->Execute();
246 int code = ClientProcessResult(ptrCommand);
247 ACCESSTOKEN_LOG_DEBUG(LABEL,
248 "command finished with status: %{public}d, message: %{public}s",
249 ptrCommand->remoteProtocol_.statusCode,
250 ptrCommand->remoteProtocol_.message.c_str());
251 return code;
252 }
253
254 std::string responseString =
255 ptrChannel_->ExecuteCommand(ptrCommand->remoteProtocol_.commandName, ptrCommand->ToJsonPayload());
256 ACCESSTOKEN_LOG_INFO(LABEL, "command executed uniqueId %{public}s", uniqueId.c_str());
257 if (responseString.empty()) {
258 ACCESSTOKEN_LOG_WARN(LABEL,
259 "targetNodeId %{public}s, uniqueId %{public}s, execute remote command error, response is empty.",
260 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
261 uniqueId.c_str());
262 // if command send failed, also try to close session
263 if (commands_.empty()) {
264 ptrChannel_->CloseConnection();
265 }
266 return Constant::FAILURE;
267 }
268
269 std::shared_ptr<BaseRemoteCommand> ptrResponseCommand =
270 RemoteCommandFactory::GetInstance().NewRemoteCommandFromJson(
271 ptrCommand->remoteProtocol_.commandName, responseString);
272 if (ptrResponseCommand == nullptr) {
273 ACCESSTOKEN_LOG_ERROR(LABEL, "targetNodeId %{public}s, get null response command!",
274 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
275 return Constant::FAILURE;
276 }
277 int32_t result = ClientProcessResult(ptrResponseCommand);
278 if (commands_.empty()) {
279 ptrChannel_->CloseConnection();
280 }
281 ACCESSTOKEN_LOG_DEBUG(LABEL,
282 "command finished with status: %{public}d, message: %{public}s",
283 ptrResponseCommand->remoteProtocol_.statusCode,
284 ptrResponseCommand->remoteProtocol_.message.c_str());
285 return result;
286 }
287
CreateChannelIfNeeded()288 void RemoteCommandExecutor::CreateChannelIfNeeded()
289 {
290 std::unique_lock<std::recursive_mutex> lock(mutex_);
291 if (ptrChannel_ != nullptr) {
292 ACCESSTOKEN_LOG_INFO(LABEL, "targetNodeId %{public}s, channel is exist.",
293 ConstantCommon::EncryptDevId(targetNodeId_).c_str());
294 return;
295 }
296
297 ptrChannel_ = CreateChannel(targetNodeId_);
298 }
299
ClientProcessResult(const std::shared_ptr<BaseRemoteCommand> & ptrCommand)300 int RemoteCommandExecutor::ClientProcessResult(const std::shared_ptr<BaseRemoteCommand>& ptrCommand)
301 {
302 std::string uniqueId = ptrCommand->remoteProtocol_.uniqueId;
303 if (ptrCommand->remoteProtocol_.statusCode == Constant::STATUS_CODE_BEFORE_RPC) {
304 ACCESSTOKEN_LOG_ERROR(LABEL,
305 "targetNodeId %{public}s, uniqueId %{public}s, status code after RPC is same as before, the remote side "
306 "may not "
307 "support this command",
308 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
309 uniqueId.c_str());
310 return Constant::FAILURE;
311 }
312
313 ptrCommand->Finish();
314 int status = ptrCommand->remoteProtocol_.statusCode;
315 if (status != Constant::SUCCESS) {
316 ACCESSTOKEN_LOG_ERROR(LABEL,
317 "targetNodeId %{public}s, uniqueId %{public}s, execute failed, message: %{public}s",
318 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
319 uniqueId.c_str(),
320 ptrCommand->remoteProtocol_.message.c_str());
321 } else {
322 ACCESSTOKEN_LOG_INFO(LABEL,
323 "targetNodeId %{public}s, uniqueId %{public}s, execute succeed.",
324 ConstantCommon::EncryptDevId(targetNodeId_).c_str(),
325 uniqueId.c_str());
326 }
327 return status;
328 }
329 } // namespace AccessToken
330 } // namespace Security
331 } // namespace OHOS
332