• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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