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