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 || !remoteObject->IsProxyObject()) { 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 onDeathCallback_ = callback; 259 } 260 OnPeerDeath()261 void ApiTransactor::OnPeerDeath() 262 { 263 LOG_W("Connection with peer died!"); 264 connectState_ = DISCONNECTED; 265 if (onDeathCallback_ != nullptr) { 266 onDeathCallback_(); 267 } 268 } 269 ~ApiTransactor()270 ApiTransactor::~ApiTransactor() 271 { 272 if (connectState_ == UNINIT) { 273 return; 274 } 275 if (remoteCaller_ != nullptr && peerDeathCallback_ != nullptr) { 276 remoteCaller_->UnsetRemoteDeathCallback(peerDeathCallback_); 277 } 278 caller_ = nullptr; 279 remoteCaller_ = nullptr; 280 peerDeathCallback_ = nullptr; 281 } 282 InitAndConnectPeer(string_view token,ApiCallHandler handler)283 bool ApiTransactor::InitAndConnectPeer(string_view token, ApiCallHandler handler) 284 { 285 LOG_I("Begin"); 286 DCHECK(connectState_ == UNINIT); 287 connectState_ = DISCONNECTED; 288 caller_ = new ApiCaller(); 289 caller_->SetCallHandler(handler); 290 if (asServer_) { 291 // public caller object, and wait for backcaller registration from client 292 auto remoteObject = PublishCallerAndWaitForBackcaller(caller_, token); 293 if (remoteObject != nullptr) { 294 remoteCaller_ = new ApiCallerProxy(remoteObject); 295 } 296 } else { 297 // wait for published caller object, then register backcaller to server 298 auto remoteObject = WaitForPublishedCaller(token); 299 if (remoteObject != nullptr) { 300 remoteCaller_ = new ApiCallerProxy(remoteObject); 301 if (!remoteCaller_->SetBackCaller(caller_)) { 302 LOG_E("Failed to set backcaller to server"); 303 return false; 304 } 305 } 306 } 307 if (remoteCaller_ == nullptr) { 308 LOG_E("Failed to get apiCaller object from peer"); 309 return false; 310 } 311 // link connectionState to it to remoteCaller 312 peerDeathCallback_ = new DeathRecipientForwarder([this]() { this->OnPeerDeath(); }); 313 if (!remoteCaller_->SetRemoteDeathCallback(peerDeathCallback_)) { 314 LOG_E("Failed to register remote caller DeathRecipient"); 315 return false; 316 } 317 // connect done 318 connectState_ = CONNECTED; 319 LOG_I("Done"); 320 return true; 321 } 322 GetConnectionStat() const323 ConnectionStat ApiTransactor::GetConnectionStat() const 324 { 325 return connectState_; 326 } 327 Finalize()328 void ApiTransactor::Finalize() {} 329 Transact(const ApiCallInfo & call,ApiReplyInfo & reply)330 void ApiTransactor::Transact(const ApiCallInfo &call, ApiReplyInfo &reply) 331 { 332 // check connection state 333 DCHECK(connectState_ != UNINIT); 334 if (connectState_ == DISCONNECTED) { 335 reply.exception_ = ApiCallErr(ERR_INTERNAL, "ipc connection is dead"); 336 return; 337 } 338 // check concurrent call 339 if (!processingApi_.empty()) { 340 constexpr auto msg = "uitest-api dose not allow calling concurrently, current processing:"; 341 reply.exception_.code_ = ERR_API_USAGE; 342 reply.exception_.message_ = string(msg) + processingApi_ + ", incoming: " + call.apiId_; 343 return; 344 } 345 processingApi_ = call.apiId_; 346 // forward to peer 347 DCHECK(remoteCaller_ != nullptr); 348 remoteCaller_->Call(call, reply); 349 processingApi_.clear(); 350 } 351 } // namespace OHOS::uitest