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