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