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