1 /* 2 * Copyright (c) 2021-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 <common_event_manager.h> 17 #include <common_event_subscribe_info.h> 18 #include <functional> 19 #include <future> 20 #include <unistd.h> 21 #include "common_utilities_hpp.h" 22 #include "json.hpp" 23 #include "ipc_transactor.h" 24 25 namespace OHOS::uitest { 26 using namespace std; 27 using namespace chrono; 28 using namespace nlohmann; 29 using namespace OHOS; 30 using namespace OHOS::AAFwk; 31 using namespace OHOS::EventFwk; 32 using Message = MessageParcel &; 33 34 using CommonEventHandler = function<void(const CommonEventData &)>; 35 class CommonEventForwarder : public CommonEventSubscriber { 36 public: CommonEventForwarder(const CommonEventSubscribeInfo & info,CommonEventHandler handler)37 explicit CommonEventForwarder(const CommonEventSubscribeInfo &info, CommonEventHandler handler) 38 : CommonEventSubscriber(info), handler_(handler) 39 { 40 } 41 ~CommonEventForwarder()42 virtual ~CommonEventForwarder() {} 43 UpdateHandler(CommonEventHandler handler)44 void UpdateHandler(CommonEventHandler handler) 45 { 46 handler_ = handler; 47 } 48 OnReceiveEvent(const CommonEventData & data)49 void OnReceiveEvent(const CommonEventData &data) override 50 { 51 if (handler_ != nullptr) { 52 handler_(data); 53 } 54 } 55 56 private: 57 CommonEventHandler handler_ = nullptr; 58 }; 59 60 using RemoteDiedHandler = function<void()>; 61 class DeathRecipientForwarder : public IRemoteObject::DeathRecipient { 62 public: DeathRecipientForwarder(RemoteDiedHandler handler)63 explicit DeathRecipientForwarder(RemoteDiedHandler handler) : handler_(handler) {}; 64 ~DeathRecipientForwarder() = default; OnRemoteDied(const wptr<IRemoteObject> & remote)65 void OnRemoteDied(const wptr<IRemoteObject> &remote) override 66 { 67 if (handler_ != nullptr) { 68 handler_(); 69 } 70 } 71 72 private: 73 const RemoteDiedHandler handler_; 74 }; 75 OnRemoteRequest(uint32_t code,Message data,Message reply,MessageOption & option)76 int ApiCaller::OnRemoteRequest(uint32_t code, Message data, Message reply, MessageOption &option) 77 { 78 if (data.ReadInterfaceToken() != GetDescriptor()) { 79 return -1; 80 } 81 if (code == TRANS_ID_CALL) { 82 // IPC io: verify on write 83 ApiCallInfo call; 84 string paramListStr; 85 call.apiId_ = data.ReadString(); 86 call.callerObjRef_ = data.ReadString(); 87 paramListStr = data.ReadString(); 88 call.fdParamIndex_ = data.ReadInt32(); 89 call.paramList_ = nlohmann::json::parse(paramListStr, nullptr, false); 90 DCHECK(!call.paramList_.is_discarded()); 91 if (call.fdParamIndex_ >= 0) { 92 call.paramList_.at(call.fdParamIndex_) = data.ReadFileDescriptor(); 93 } 94 ApiReplyInfo result; 95 Call(call, result); 96 auto ret = reply.WriteString(result.resultValue_.dump()) && reply.WriteUint32(result.exception_.code_) && 97 reply.WriteString(result.exception_.message_); 98 return ret ? 0 : -1; 99 } else if (code == TRANS_ID_SET_BACKCALLER) { 100 reply.WriteBool(SetBackCaller(data.ReadRemoteObject())); 101 return 0; 102 } else { 103 return IPCObjectStub::OnRemoteRequest(code, data, reply, option); 104 } 105 } 106 Call(const ApiCallInfo & call,ApiReplyInfo & result)107 void ApiCaller::Call(const ApiCallInfo &call, ApiReplyInfo &result) 108 { 109 DCHECK(handler_ != nullptr); 110 handler_(call, result); 111 } 112 SetBackCaller(const sptr<IRemoteObject> & caller)113 bool ApiCaller::SetBackCaller(const sptr<IRemoteObject> &caller) 114 { 115 if (backcallerHandler_ == nullptr) { 116 LOG_W("No backcallerHandler set!"); 117 return false; 118 } 119 backcallerHandler_(caller); 120 return true; 121 } 122 SetCallHandler(ApiCallHandler handler)123 void ApiCaller::SetCallHandler(ApiCallHandler handler) 124 { 125 handler_ = handler; 126 } 127 SetBackCallerHandler(function<void (sptr<IRemoteObject>)> handler)128 void ApiCaller::SetBackCallerHandler(function<void(sptr<IRemoteObject>)> handler) 129 { 130 backcallerHandler_ = handler; 131 } 132 ApiCallerProxy(const sptr<IRemoteObject> & impl)133 ApiCallerProxy::ApiCallerProxy(const sptr<IRemoteObject> &impl) : IRemoteProxy<IApiCaller>(impl) {} 134 Call(const ApiCallInfo & call,ApiReplyInfo & result)135 void ApiCallerProxy::Call(const ApiCallInfo &call, ApiReplyInfo &result) 136 { 137 MessageOption option; 138 MessageParcel data; 139 MessageParcel reply; 140 // IPC io: verify on write 141 auto ret = data.WriteInterfaceToken(GetDescriptor()) && data.WriteString(call.apiId_) && 142 data.WriteString(call.callerObjRef_) && data.WriteString(call.paramList_.dump()) && 143 data.WriteInt32(call.fdParamIndex_); 144 auto fdIndex = call.fdParamIndex_; 145 if (ret && fdIndex >= 0) { 146 DCHECK(static_cast<size_t>(fdIndex) < call.paramList_.size()); 147 DCHECK(call.paramList_.at(fdIndex).type() == nlohmann::detail::value_t::number_unsigned); 148 if (!data.WriteFileDescriptor(call.paramList_.at(fdIndex).get<uint32_t>())) { 149 ret = false; 150 LOG_E("Failed to write file descriptor param"); 151 } 152 } 153 if (!ret || Remote()->SendRequest(TRANS_ID_CALL, data, reply, option) != 0) { 154 result.exception_ = ApiCallErr(ERR_INTERNAL, "IPC SendRequest failed"); 155 result.resultValue_ = nullptr; 156 } else { 157 result.resultValue_ = json::parse(reply.ReadString(), nullptr, false); 158 DCHECK(!result.resultValue_.is_discarded()); 159 result.exception_.code_ = static_cast<ErrCode>(reply.ReadUint32()); 160 result.exception_.message_ = reply.ReadString(); 161 } 162 } 163 SetBackCaller(const OHOS::sptr<IRemoteObject> & caller)164 bool ApiCallerProxy::SetBackCaller(const OHOS::sptr<IRemoteObject> &caller) 165 { 166 MessageOption option; 167 MessageParcel data; 168 MessageParcel reply; 169 auto writeStat = data.WriteInterfaceToken(GetDescriptor()) && data.WriteRemoteObject(caller); 170 if (!writeStat || (Remote()->SendRequest(TRANS_ID_SET_BACKCALLER, data, reply, option) != 0)) { 171 LOG_E("IPC SendRequest failed"); 172 return false; 173 } 174 return reply.ReadBool(); 175 } 176 SetRemoteDeathCallback(const sptr<IRemoteObject::DeathRecipient> & callback)177 bool ApiCallerProxy::SetRemoteDeathCallback(const sptr<IRemoteObject::DeathRecipient> &callback) 178 { 179 return Remote()->AddDeathRecipient(callback); 180 } 181 UnsetRemoteDeathCallback(const sptr<OHOS::IRemoteObject::DeathRecipient> & callback)182 bool ApiCallerProxy::UnsetRemoteDeathCallback(const sptr<OHOS::IRemoteObject::DeathRecipient> &callback) 183 { 184 return Remote()->RemoveDeathRecipient(callback); 185 } 186 187 constexpr string_view PUBLISH_EVENT_PREFIX = "uitest.api.caller.publish#"; 188 constexpr uint32_t PUBLISH_MAX_RETIES = 10; 189 constexpr uint32_t WAIT_CONN_TIMEOUT_MS = 5000; 190 PublishCallerAndWaitForBackcaller(const sptr<ApiCaller> & caller,string_view token)191 static sptr<IRemoteObject> PublishCallerAndWaitForBackcaller(const sptr<ApiCaller> &caller, string_view token) 192 { 193 CommonEventData event; 194 Want want; 195 want.SetAction(string(PUBLISH_EVENT_PREFIX) + token.data()); 196 want.SetParam(string(token), caller->AsObject()); 197 event.SetWant(want); 198 // wait backcaller object registeration from client 199 mutex mtx; 200 unique_lock<mutex> lock(mtx); 201 condition_variable condition; 202 sptr<IRemoteObject> remoteCallerObject = nullptr; 203 caller->SetBackCallerHandler([&remoteCallerObject, &condition](const sptr<IRemoteObject> &remote) { 204 remoteCallerObject = remote; 205 condition.notify_one(); 206 }); 207 constexpr auto period = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS / PUBLISH_MAX_RETIES); 208 uint32_t tries = 0; 209 do { 210 // publish caller with retries 211 if (!CommonEventManager::PublishCommonEvent(event)) { 212 LOG_E("Pulbish commonEvent failed"); 213 } 214 tries++; 215 } while (tries < PUBLISH_MAX_RETIES && condition.wait_for(lock, period) == cv_status::timeout); 216 caller->SetBackCallerHandler(nullptr); 217 return remoteCallerObject; 218 } 219 WaitForPublishedCaller(string_view token)220 static sptr<IRemoteObject> WaitForPublishedCaller(string_view token) 221 { 222 MatchingSkills matchingSkills; 223 matchingSkills.AddEvent(string(PUBLISH_EVENT_PREFIX) + token.data()); 224 CommonEventSubscribeInfo info(matchingSkills); 225 mutex mtx; 226 unique_lock<mutex> lock(mtx); 227 condition_variable condition; 228 sptr<IRemoteObject> remoteObject = nullptr; 229 auto onEvent = [&condition, &remoteObject, &token](const CommonEventData &data) { 230 LOG_D("Received commonEvent"); 231 const auto &want = data.GetWant(); 232 remoteObject = want.GetRemoteObject(string(token)); 233 if (remoteObject == nullptr) { 234 LOG_W("Not a proxy object!"); 235 remoteObject = nullptr; 236 } else { 237 condition.notify_one(); 238 } 239 }; 240 shared_ptr<CommonEventForwarder> subscriber = make_shared<CommonEventForwarder>(info, onEvent); 241 if (!CommonEventManager::SubscribeCommonEvent(subscriber)) { 242 LOG_E("Fail to subscribe commonEvent"); 243 return nullptr; 244 } 245 const auto timeout = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS); 246 if (condition.wait_for(lock, timeout) == cv_status::timeout) { 247 LOG_E("Wait for ApiCaller publish by server timeout"); 248 } else if (remoteObject == nullptr) { 249 LOG_E("Published ApiCaller object is null"); 250 } 251 subscriber->UpdateHandler(nullptr); // unset handler 252 CommonEventManager::UnSubscribeCommonEvent(subscriber); 253 return remoteObject; 254 } 255 ApiTransactor(bool asServer)256 ApiTransactor::ApiTransactor(bool asServer) : asServer_(asServer) {}; 257 SetDeathCallback(function<void ()> callback)258 void ApiTransactor::SetDeathCallback(function<void()> callback) 259 { 260 if (singlenessMode_) { 261 LOG_E("Cannot SetDeathCallback in singleness mode"); 262 return; 263 } 264 onDeathCallback_ = callback; 265 } 266 OnPeerDeath()267 void ApiTransactor::OnPeerDeath() 268 { 269 LOG_W("Connection with peer died!"); 270 connectState_ = DISCONNECTED; 271 if (onDeathCallback_ != nullptr) { 272 onDeathCallback_(); 273 } 274 } 275 ~ApiTransactor()276 ApiTransactor::~ApiTransactor() 277 { 278 if (connectState_ == UNINIT) { 279 return; 280 } 281 if (remoteCaller_ != nullptr && peerDeathCallback_ != nullptr) { 282 remoteCaller_->UnsetRemoteDeathCallback(peerDeathCallback_); 283 } 284 caller_ = nullptr; 285 remoteCaller_ = nullptr; 286 peerDeathCallback_ = nullptr; 287 } 288 InitAndConnectPeer(string_view token,ApiCallHandler handler)289 bool ApiTransactor::InitAndConnectPeer(string_view token, ApiCallHandler handler) 290 { 291 LOG_I("Begin"); 292 DCHECK(connectState_ == UNINIT); 293 connectState_ = DISCONNECTED; 294 caller_ = new ApiCaller(); 295 caller_->SetCallHandler(handler); 296 sptr<IRemoteObject> remoteObject = nullptr; 297 if (asServer_) { 298 // public caller object, and wait for backcaller registration from client 299 remoteObject = PublishCallerAndWaitForBackcaller(caller_, token); 300 if (remoteObject != nullptr) { 301 remoteCaller_ = new ApiCallerProxy(remoteObject); 302 } 303 } else { 304 // wait for published caller object, then register backcaller to server 305 remoteObject = WaitForPublishedCaller(token); 306 if (remoteObject != nullptr) { 307 remoteCaller_ = new ApiCallerProxy(remoteObject); 308 if (!remoteCaller_->SetBackCaller(caller_)) { 309 LOG_E("Failed to set backcaller to server"); 310 return false; 311 } 312 } 313 } 314 if (remoteObject == nullptr || remoteCaller_ == nullptr) { 315 LOG_E("Failed to get apiCaller object from peer"); 316 return false; 317 } 318 // in singleness mode, C/S runs in the same shell process and the remoteObject is a stub instead of proxy 319 singlenessMode_ = !remoteObject->IsProxyObject(); 320 // link connectionState to it to remoteCaller 321 if (!singlenessMode_) { 322 peerDeathCallback_ = new DeathRecipientForwarder([this]() { this->OnPeerDeath(); }); 323 if (!remoteCaller_->SetRemoteDeathCallback(peerDeathCallback_)) { 324 LOG_E("Failed to register remote caller DeathRecipient"); 325 return false; 326 } 327 } 328 // connect done 329 connectState_ = CONNECTED; 330 LOG_I("Done"); 331 return true; 332 } 333 GetConnectionStat() const334 ConnectionStat ApiTransactor::GetConnectionStat() const 335 { 336 return connectState_; 337 } 338 Finalize()339 void ApiTransactor::Finalize() {} 340 Transact(const ApiCallInfo & call,ApiReplyInfo & reply)341 void ApiTransactor::Transact(const ApiCallInfo &call, ApiReplyInfo &reply) 342 { 343 // check connection state 344 DCHECK(connectState_ != UNINIT); 345 if (connectState_ == DISCONNECTED) { 346 reply.exception_ = ApiCallErr(ERR_INTERNAL, "ipc connection is dead"); 347 return; 348 } 349 // check concurrent call 350 if (!processingApi_.empty()) { 351 constexpr auto msg = "uitest-api dose not allow calling concurrently, current processing:"; 352 reply.exception_.code_ = ERR_API_USAGE; 353 reply.exception_.message_ = string(msg) + processingApi_ + ", incoming: " + call.apiId_; 354 return; 355 } 356 processingApi_ = call.apiId_; 357 // forward to peer 358 DCHECK(remoteCaller_ != nullptr); 359 remoteCaller_->Call(call, reply); 360 processingApi_.clear(); 361 } 362 363 // functions for sending/handling broadcast commands 364 BroadcastCommandHandler g_broadcastCommandHandler = nullptr; 365 shared_ptr<CommonEventForwarder> g_broadcastCommandSubscriber = nullptr; SendBroadcastCommand(const OHOS::AAFwk::Want & cmd,ApiCallErr & err)366 void ApiTransactor::SendBroadcastCommand(const OHOS::AAFwk::Want &cmd, ApiCallErr &err) 367 { 368 LOG_I("Send uitest.broadcast.command begin"); 369 CommonEventData event; 370 auto want = OHOS::AAFwk::Want(cmd); 371 want.SetAction("uitest.broadcast.command"); 372 event.SetWant(want); 373 if (!CommonEventManager::PublishCommonEvent(event)) { 374 err = ApiCallErr(ERR_INTERNAL, "Failed to publish uitest.broadcast.command"); 375 return; 376 } 377 LOG_I("Send uitest.broadcast.command end"); 378 MatchingSkills matchingSkills; 379 matchingSkills.AddEvent("uitest.broadcast.command.reply"); 380 CommonEventSubscribeInfo info(matchingSkills); 381 mutex mtx; 382 unique_lock<mutex> lock(mtx); 383 condition_variable condition; 384 auto onEvent = [&err, &condition](const CommonEventData &data) { 385 const auto &reply = data.GetWant(); 386 auto code = static_cast<ErrCode>(reply.GetIntParam("code", 0)); 387 err = ApiCallErr(code, reply.GetStringParam("message")); 388 condition.notify_one(); 389 }; 390 auto broadcastReplySubscriber = make_shared<CommonEventForwarder>(info, onEvent); 391 if (!CommonEventManager::SubscribeCommonEvent(broadcastReplySubscriber)) { 392 err = ApiCallErr(INTERNAL_ERROR, "Fail to subscribe uitest.broadcast.command.reply"); 393 } 394 const auto timeout = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS << 1); 395 if (condition.wait_for(lock, timeout) == cv_status::timeout) { 396 err = ApiCallErr(INTERNAL_ERROR, "Wait for subscribe uitest.broadcast.command.reply timeout"); 397 } 398 CommonEventManager::UnSubscribeCommonEvent(broadcastReplySubscriber); 399 LOG_I("Receive uitest.broadcast.command.reply end"); 400 } 401 SetBroadcastCommandHandler(BroadcastCommandHandler handler)402 void ApiTransactor::SetBroadcastCommandHandler(BroadcastCommandHandler handler) 403 { 404 if (handler == nullptr) { 405 LOG_W("BroadcastCommandHandler is null"); 406 return; 407 } 408 g_broadcastCommandHandler = handler; 409 if (g_broadcastCommandSubscriber != nullptr) { 410 return; 411 } 412 MatchingSkills matchingSkills; 413 matchingSkills.AddEvent("uitest.broadcast.command"); 414 CommonEventSubscribeInfo info(matchingSkills); 415 auto onEvent = [](const CommonEventData &commandData) { 416 auto commandWant = OHOS::AAFwk::Want(commandData.GetWant()); 417 // handle command in new thread, do not block in CommonEvent dispatching thread 418 auto _ = async(launch::async, [&commandWant]() { 419 LOG_I("HandleBroadcastCommand begin"); 420 auto replyWant = OHOS::AAFwk::Want(); 421 ApiCallErr err = ApiCallErr(NO_ERROR); 422 if (g_broadcastCommandHandler == nullptr) { 423 err = ApiCallErr(INTERNAL_ERROR, "Received uitest.broadcast.command but handler is null!"); 424 } else { 425 g_broadcastCommandHandler(commandWant, err); 426 } 427 replyWant.SetAction("uitest.broadcast.command.reply"); 428 replyWant.SetParam("code", (int)(err.code_)); 429 replyWant.SetParam("message", err.message_); 430 CommonEventData replyData; 431 replyData.SetWant(replyWant); 432 if (!CommonEventManager::PublishCommonEvent(replyData)) { 433 LOG_E("Fail to publish uitest.broadcast.command.reply"); 434 } 435 LOG_I("HandleBroadcastCommand end"); 436 }); 437 }; 438 g_broadcastCommandSubscriber = make_shared<CommonEventForwarder>(info, onEvent); 439 if (!CommonEventManager::SubscribeCommonEvent(g_broadcastCommandSubscriber)) { 440 LOG_E("Fail to subscribe uitest.broadcast.command"); 441 } 442 } 443 UnsetBroadcastCommandHandler()444 void ApiTransactor::UnsetBroadcastCommandHandler() 445 { 446 if (g_broadcastCommandSubscriber != nullptr) { 447 CommonEventManager::UnSubscribeCommonEvent(g_broadcastCommandSubscriber); 448 } 449 if (g_broadcastCommandHandler != nullptr) { 450 g_broadcastCommandHandler = nullptr; 451 } 452 } 453 } // namespace OHOS::uitest