• 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 "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