• 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     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