1 /* 2 * Copyright (c) 2025 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 <unistd.h> 17 #include "common_utils.h" 18 #include "api_caller_client.h" 19 20 namespace OHOS::perftest { 21 using namespace std; 22 using namespace chrono; 23 using namespace OHOS; 24 using namespace OHOS::AAFwk; 25 using namespace OHOS::EventFwk; 26 ~ApiCallerClient()27 ApiCallerClient::~ApiCallerClient() 28 { 29 if (connectState_ == UNINIT) { 30 return; 31 } 32 if (remoteCaller_ != nullptr && peerDeathCallback_ != nullptr) { 33 remoteCaller_->UnsetRemoteDeathCallback(peerDeathCallback_); 34 } 35 caller_ = nullptr; 36 remoteCaller_ = nullptr; 37 peerDeathCallback_ = nullptr; 38 } 39 InitAndConnectPeer(string_view token,ApiCallHandler handler)40 bool ApiCallerClient::InitAndConnectPeer(string_view token, ApiCallHandler handler) 41 { 42 LOG_I("InitAndConnectPeer Begin"); 43 if (connectState_ == CONNECTED) { 44 LOG_I("InitAndConnectPeer, client has connected with server"); 45 return true; 46 } 47 DCHECK(connectState_ == UNINIT); 48 connectState_ = DISCONNECTED; 49 caller_ = new ApiCallerStub(); 50 caller_->SetCallHandler(handler); 51 // wait for published caller object, then register backcaller to server 52 sptr<IRemoteObject> remoteObject = WaitForPublishedCaller(token); 53 if (remoteObject != nullptr) { 54 remoteCaller_ = new ApiCallerProxy(remoteObject); 55 if (!remoteCaller_->SetBackCaller(caller_)) { 56 LOG_E("Failed to set backcaller to server"); 57 return false; 58 } 59 } 60 if (remoteObject == nullptr || remoteCaller_ == nullptr) { 61 LOG_E("Failed to get apiCaller object from peer"); 62 return false; 63 } 64 // link connectionState to it to remoteCaller 65 peerDeathCallback_ = new DeathRecipientForwarder([this]() { this->OnPeerDeath(); }); 66 if (!remoteCaller_->SetRemoteDeathCallback(peerDeathCallback_)) { 67 LOG_E("Failed to register remote caller DeathRecipient"); 68 return false; 69 } 70 // connect done 71 connectState_ = CONNECTED; 72 LOG_I("ApiCallerClient InitAndConnectPeer Done"); 73 return true; 74 } 75 Transact(const ApiCallInfo & call,ApiReplyInfo & reply)76 void ApiCallerClient::Transact(const ApiCallInfo &call, ApiReplyInfo &reply) 77 { 78 // check connection state 79 DCHECK(connectState_ != UNINIT); 80 if (connectState_ == DISCONNECTED) { 81 reply.exception_ = ApiCallErr(ERR_INTERNAL, "ipc connection is dead"); 82 return; 83 } 84 DCHECK(remoteCaller_ != nullptr); 85 // check concurrent call 86 if (!processingApi_.empty()) { 87 constexpr auto msg = "perftest-api dose not allow calling concurrently, current processing:"; 88 reply.exception_.code_ = ERR_API_USAGE; 89 reply.exception_.message_ = string(msg) + processingApi_ + ", incoming: " + call.apiId_; 90 return; 91 } 92 processingApi_ = call.apiId_; 93 // forward to peer 94 remoteCaller_->Call(call, reply); 95 processingApi_.clear(); 96 } 97 SetDeathCallback(function<void ()> callback)98 void ApiCallerClient::SetDeathCallback(function<void()> callback) 99 { 100 onDeathCallback_ = callback; 101 } 102 GetConnectionStat() const103 ConnectionStat ApiCallerClient::GetConnectionStat() const 104 { 105 return connectState_; 106 } 107 WaitForPublishedCaller(string_view token)108 sptr<IRemoteObject> ApiCallerClient::WaitForPublishedCaller(string_view token) 109 { 110 MatchingSkills matchingSkills; 111 matchingSkills.AddEvent(string(PUBLISH_EVENT_PREFIX) + token.data()); 112 CommonEventSubscribeInfo info(matchingSkills); 113 mutex mtx; 114 unique_lock<mutex> lock(mtx); 115 condition_variable condition; 116 sptr<IRemoteObject> remoteObject = nullptr; 117 auto onEvent = [&condition, &remoteObject, &token](const CommonEventData &data) { 118 LOG_I("Received commonEvent"); 119 const auto &want = data.GetWant(); 120 remoteObject = want.GetRemoteObject(string(token)); 121 if (remoteObject == nullptr) { 122 LOG_W("Not a proxy object!"); 123 remoteObject = nullptr; 124 } else { 125 condition.notify_one(); 126 } 127 }; 128 shared_ptr<CommonEventForwarder> subscriber = make_shared<CommonEventForwarder>(info, onEvent); 129 if (!CommonEventManager::SubscribeCommonEvent(subscriber)) { 130 LOG_E("Fail to subscribe commonEvent"); 131 return nullptr; 132 } 133 const auto timeout = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS); 134 auto ret = condition.wait_for(lock, timeout); 135 CommonEventManager::UnSubscribeCommonEvent(subscriber); 136 subscriber->UpdateHandler(nullptr); // unset handler 137 if (ret == cv_status::timeout) { 138 LOG_E("Wait for ApiCaller publish by server timeout"); 139 } else if (remoteObject == nullptr) { 140 LOG_E("Published ApiCaller object is null"); 141 } 142 return remoteObject; 143 } 144 OnPeerDeath()145 void ApiCallerClient::OnPeerDeath() 146 { 147 LOG_W("Connection with peer died!"); 148 connectState_ = DISCONNECTED; 149 if (onDeathCallback_ != nullptr) { 150 onDeathCallback_(); 151 } 152 } 153 UpdateHandler(CommonEventHandler handler)154 void CommonEventForwarder::UpdateHandler(CommonEventHandler handler) 155 { 156 handler_ = handler; 157 } 158 OnReceiveEvent(const CommonEventData & data)159 void CommonEventForwarder::OnReceiveEvent(const CommonEventData &data) 160 { 161 if (handler_ != nullptr) { 162 handler_(data); 163 } 164 } 165 } // namespace OHOS::perftest