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, reply; 139 // IPC io: verify on write 140 auto ret = data.WriteInterfaceToken(GetDescriptor()) && data.WriteString(call.apiId_) && 141 data.WriteString(call.callerObjRef_) && data.WriteString(call.paramList_.dump()) && 142 data.WriteInt32(call.fdParamIndex_); 143 auto fdIndex = call.fdParamIndex_; 144 if (ret && fdIndex >= 0) { 145 DCHECK(static_cast<size_t>(fdIndex) < call.paramList_.size()); 146 DCHECK(call.paramList_.at(fdIndex).type() == nlohmann::detail::value_t::number_unsigned); 147 if (!data.WriteFileDescriptor(call.paramList_.at(fdIndex).get<uint32_t>())) { 148 ret = false; 149 LOG_E("Failed to write file descriptor param"); 150 } 151 } 152 if (!ret || Remote()->SendRequest(TRANS_ID_CALL, data, reply, option) != 0) { 153 result.exception_ = ApiCallErr(ERR_INTERNAL, "IPC SendRequest failed"); 154 result.resultValue_ = nullptr; 155 } else { 156 result.resultValue_ = json::parse(reply.ReadString(), nullptr, false); 157 DCHECK(!result.resultValue_.is_discarded()); 158 result.exception_.code_ = static_cast<ErrCode>(reply.ReadUint32()); 159 result.exception_.message_ = reply.ReadString(); 160 } 161 } 162 SetBackCaller(const OHOS::sptr<IRemoteObject> & caller)163 bool ApiCallerProxy::SetBackCaller(const OHOS::sptr<IRemoteObject> &caller) 164 { 165 MessageOption option; 166 MessageParcel data, reply; 167 auto writeStat = data.WriteInterfaceToken(GetDescriptor()) && data.WriteRemoteObject(caller); 168 if (!writeStat || (Remote()->SendRequest(TRANS_ID_SET_BACKCALLER, data, reply, option) != 0)) { 169 LOG_E("IPC SendRequest failed"); 170 return false; 171 } 172 return reply.ReadBool(); 173 } 174 SetRemoteDeathCallback(const sptr<IRemoteObject::DeathRecipient> & callback)175 bool ApiCallerProxy::SetRemoteDeathCallback(const sptr<IRemoteObject::DeathRecipient> &callback) 176 { 177 return Remote()->AddDeathRecipient(callback); 178 } 179 UnsetRemoteDeathCallback(const sptr<OHOS::IRemoteObject::DeathRecipient> & callback)180 bool ApiCallerProxy::UnsetRemoteDeathCallback(const sptr<OHOS::IRemoteObject::DeathRecipient> &callback) 181 { 182 return Remote()->RemoveDeathRecipient(callback); 183 } 184 185 constexpr string_view PUBLISH_EVENT_PREFIX = "uitest.api.caller.publish#"; 186 constexpr uint32_t PUBLISH_MAX_RETIES = 10; 187 constexpr uint32_t WAIT_CONN_TIMEOUT_MS = 5000; 188 PublishCallerAndWaitForBackcaller(const sptr<ApiCaller> & caller,string_view token)189 static sptr<IRemoteObject> PublishCallerAndWaitForBackcaller(const sptr<ApiCaller> &caller, string_view token) 190 { 191 CommonEventData event; 192 Want want; 193 want.SetAction(string(PUBLISH_EVENT_PREFIX) + token.data()); 194 want.SetParam(string(token), caller->AsObject()); 195 event.SetWant(want); 196 // wait backcaller object registeration from client 197 mutex mtx; 198 unique_lock<mutex> lock(mtx); 199 condition_variable condition; 200 sptr<IRemoteObject> remoteCallerObject = nullptr; 201 caller->SetBackCallerHandler([&remoteCallerObject, &condition](const sptr<IRemoteObject> &remote) { 202 remoteCallerObject = remote; 203 condition.notify_one(); 204 }); 205 constexpr auto period = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS / PUBLISH_MAX_RETIES); 206 uint32_t tries = 0; 207 do { 208 // publish caller with retries 209 if (!CommonEventManager::PublishCommonEvent(event)) { 210 LOG_E("Pulbish commonEvent failed"); 211 } 212 tries++; 213 } while (tries < PUBLISH_MAX_RETIES && condition.wait_for(lock, period) == cv_status::timeout); 214 caller->SetBackCallerHandler(nullptr); 215 return remoteCallerObject; 216 } 217 WaitForPublishedCaller(string_view token)218 static sptr<IRemoteObject> WaitForPublishedCaller(string_view token) 219 { 220 MatchingSkills matchingSkills; 221 matchingSkills.AddEvent(string(PUBLISH_EVENT_PREFIX) + token.data()); 222 CommonEventSubscribeInfo info(matchingSkills); 223 mutex mtx; 224 unique_lock<mutex> lock(mtx); 225 condition_variable condition; 226 sptr<IRemoteObject> remoteObject = nullptr; 227 auto onEvent = [&condition, &remoteObject, &token](const CommonEventData &data) { 228 LOG_D("Received commonEvent"); 229 const auto &want = data.GetWant(); 230 remoteObject = want.GetRemoteObject(string(token)); 231 if (remoteObject == nullptr) { 232 LOG_W("Not a proxy object!"); 233 remoteObject = nullptr; 234 } else { 235 condition.notify_one(); 236 } 237 }; 238 shared_ptr<CommonEventForwarder> subscriber = make_shared<CommonEventForwarder>(info, onEvent); 239 if (!CommonEventManager::SubscribeCommonEvent(subscriber)) { 240 LOG_E("Fail to subscribe commonEvent"); 241 return nullptr; 242 } 243 const auto timeout = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS); 244 if (condition.wait_for(lock, timeout) == cv_status::timeout) { 245 LOG_E("Wait for ApiCaller publish by server timeout"); 246 } else if (remoteObject == nullptr) { 247 LOG_E("Published ApiCaller object is null"); 248 } 249 subscriber->UpdateHandler(nullptr); // unset handler 250 CommonEventManager::UnSubscribeCommonEvent(subscriber); 251 return remoteObject; 252 } 253 ApiTransactor(bool asServer)254 ApiTransactor::ApiTransactor(bool asServer) : asServer_(asServer) {}; 255 SetDeathCallback(function<void ()> callback)256 void ApiTransactor::SetDeathCallback(function<void()> callback) 257 { 258 if (singlenessMode_) { 259 LOG_E("Cannot SetDeathCallback in singleness mode"); 260 return; 261 } 262 onDeathCallback_ = callback; 263 } 264 OnPeerDeath()265 void ApiTransactor::OnPeerDeath() 266 { 267 LOG_W("Connection with peer died!"); 268 connectState_ = DISCONNECTED; 269 if (onDeathCallback_ != nullptr) { 270 onDeathCallback_(); 271 } 272 } 273 ~ApiTransactor()274 ApiTransactor::~ApiTransactor() 275 { 276 if (connectState_ == UNINIT) { 277 return; 278 } 279 if (remoteCaller_ != nullptr && peerDeathCallback_ != nullptr) { 280 remoteCaller_->UnsetRemoteDeathCallback(peerDeathCallback_); 281 } 282 caller_ = nullptr; 283 remoteCaller_ = nullptr; 284 peerDeathCallback_ = nullptr; 285 } 286 InitAndConnectPeer(string_view token,ApiCallHandler handler)287 bool ApiTransactor::InitAndConnectPeer(string_view token, ApiCallHandler handler) 288 { 289 LOG_I("Begin"); 290 DCHECK(connectState_ == UNINIT); 291 connectState_ = DISCONNECTED; 292 caller_ = new ApiCaller(); 293 caller_->SetCallHandler(handler); 294 sptr<IRemoteObject> remoteObject = nullptr; 295 if (asServer_) { 296 // public caller object, and wait for backcaller registration from client 297 remoteObject = PublishCallerAndWaitForBackcaller(caller_, token); 298 if (remoteObject != nullptr) { 299 remoteCaller_ = new ApiCallerProxy(remoteObject); 300 } 301 } else { 302 // wait for published caller object, then register backcaller to server 303 remoteObject = WaitForPublishedCaller(token); 304 if (remoteObject != nullptr) { 305 remoteCaller_ = new ApiCallerProxy(remoteObject); 306 if (!remoteCaller_->SetBackCaller(caller_)) { 307 LOG_E("Failed to set backcaller to server"); 308 return false; 309 } 310 } 311 } 312 if (remoteObject == nullptr || remoteCaller_ == nullptr) { 313 LOG_E("Failed to get apiCaller object from peer"); 314 return false; 315 } 316 // in singleness mode, C/S runs in the same shell process and the remoteObject is a stub instead of proxy 317 singlenessMode_ = !remoteObject->IsProxyObject(); 318 // link connectionState to it to remoteCaller 319 if (!singlenessMode_) { 320 peerDeathCallback_ = new DeathRecipientForwarder([this]() { this->OnPeerDeath(); }); 321 if (!remoteCaller_->SetRemoteDeathCallback(peerDeathCallback_)) { 322 LOG_E("Failed to register remote caller DeathRecipient"); 323 return false; 324 } 325 } 326 // connect done 327 connectState_ = CONNECTED; 328 LOG_I("Done"); 329 return true; 330 } 331 GetConnectionStat() const332 ConnectionStat ApiTransactor::GetConnectionStat() const 333 { 334 return connectState_; 335 } 336 Finalize()337 void ApiTransactor::Finalize() {} 338 Transact(const ApiCallInfo & call,ApiReplyInfo & reply)339 void ApiTransactor::Transact(const ApiCallInfo &call, ApiReplyInfo &reply) 340 { 341 // check connection state 342 DCHECK(connectState_ != UNINIT); 343 if (connectState_ == DISCONNECTED) { 344 reply.exception_ = ApiCallErr(ERR_INTERNAL, "ipc connection is dead"); 345 return; 346 } 347 // check concurrent call 348 if (!processingApi_.empty()) { 349 constexpr auto msg = "uitest-api dose not allow calling concurrently, current processing:"; 350 reply.exception_.code_ = ERR_API_USAGE; 351 reply.exception_.message_ = string(msg) + processingApi_ + ", incoming: " + call.apiId_; 352 return; 353 } 354 processingApi_ = call.apiId_; 355 // forward to peer 356 DCHECK(remoteCaller_ != nullptr); 357 remoteCaller_->Call(call, reply); 358 processingApi_.clear(); 359 } 360 361 // functions for sending/handling broadcast commands 362 BroadcastCommandHandler g_broadcastCommandHandler = nullptr; 363 shared_ptr<CommonEventForwarder> g_broadcastCommandSubscriber = nullptr; SendBroadcastCommand(const OHOS::AAFwk::Want & cmd,ApiCallErr & err)364 void ApiTransactor::SendBroadcastCommand(const OHOS::AAFwk::Want &cmd, ApiCallErr &err) 365 { 366 LOG_I("Send uitest.broadcast.command begin"); 367 CommonEventData event; 368 auto want = OHOS::AAFwk::Want(cmd); 369 want.SetAction("uitest.broadcast.command"); 370 event.SetWant(want); 371 if (!CommonEventManager::PublishCommonEvent(event)) { 372 err = ApiCallErr(ERR_INTERNAL, "Failed to publish uitest.broadcast.command"); 373 return; 374 } 375 LOG_I("Send uitest.broadcast.command end"); 376 MatchingSkills matchingSkills; 377 matchingSkills.AddEvent("uitest.broadcast.command.reply"); 378 CommonEventSubscribeInfo info(matchingSkills); 379 mutex mtx; 380 unique_lock<mutex> lock(mtx); 381 condition_variable condition; 382 auto onEvent = [&err, &condition](const CommonEventData &data) { 383 const auto &reply = data.GetWant(); 384 auto code = static_cast<ErrCode>(reply.GetIntParam("code", 0)); 385 err = ApiCallErr(code, reply.GetStringParam("message")); 386 condition.notify_one(); 387 }; 388 auto broadcastReplySubscriber = make_shared<CommonEventForwarder>(info, onEvent); 389 if (!CommonEventManager::SubscribeCommonEvent(broadcastReplySubscriber)) { 390 err = ApiCallErr(INTERNAL_ERROR, "Fail to subscribe uitest.broadcast.command.reply"); 391 } 392 const auto timeout = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS << 1); 393 if (condition.wait_for(lock, timeout) == cv_status::timeout) { 394 err = ApiCallErr(INTERNAL_ERROR, "Wait for subscribe uitest.broadcast.command.reply timeout"); 395 } 396 CommonEventManager::UnSubscribeCommonEvent(broadcastReplySubscriber); 397 LOG_I("Receive uitest.broadcast.command.reply end"); 398 } 399 SetBroadcastCommandHandler(BroadcastCommandHandler handler)400 void ApiTransactor::SetBroadcastCommandHandler(BroadcastCommandHandler handler) 401 { 402 if (handler == nullptr) { 403 LOG_W("BroadcastCommandHandler is null"); 404 return; 405 } 406 g_broadcastCommandHandler = handler; 407 if (g_broadcastCommandSubscriber != nullptr) { 408 return; 409 } 410 MatchingSkills matchingSkills; 411 matchingSkills.AddEvent("uitest.broadcast.command"); 412 CommonEventSubscribeInfo info(matchingSkills); 413 auto onEvent = [](const CommonEventData &commandData) { 414 auto commandWant = OHOS::AAFwk::Want(commandData.GetWant()); 415 // handle command in new thread, do not block in CommonEvent dispatching thread 416 auto _ = async(launch::async, [&commandWant]() { 417 LOG_I("HandleBroadcastCommand begin"); 418 auto replyWant = OHOS::AAFwk::Want(); 419 ApiCallErr err = ApiCallErr(NO_ERROR); 420 if (g_broadcastCommandHandler == nullptr) { 421 err = ApiCallErr(INTERNAL_ERROR, "Received uitest.broadcast.command but handler is null!"); 422 } else { 423 g_broadcastCommandHandler(commandWant, err); 424 } 425 replyWant.SetAction("uitest.broadcast.command.reply"); 426 replyWant.SetParam("code", (int)(err.code_)); 427 replyWant.SetParam("message", err.message_); 428 CommonEventData replyData; 429 replyData.SetWant(replyWant); 430 if (!CommonEventManager::PublishCommonEvent(replyData)) { 431 LOG_E("Fail to publish uitest.broadcast.command.reply"); 432 } 433 LOG_I("HandleBroadcastCommand end"); 434 }); 435 }; 436 g_broadcastCommandSubscriber = make_shared<CommonEventForwarder>(info, onEvent); 437 if (!CommonEventManager::SubscribeCommonEvent(g_broadcastCommandSubscriber)) { 438 LOG_E("Fail to subscribe uitest.broadcast.command"); 439 } 440 } 441 UnsetBroadcastCommandHandler()442 void ApiTransactor::UnsetBroadcastCommandHandler() 443 { 444 if (g_broadcastCommandSubscriber != nullptr) { 445 CommonEventManager::UnSubscribeCommonEvent(g_broadcastCommandSubscriber); 446 } 447 if (g_broadcastCommandHandler != nullptr) { 448 g_broadcastCommandHandler = nullptr; 449 } 450 } 451 } // namespace OHOS::uitest