• 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) {
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         if (singlenessMode_) {
259             LOG_E("Cannot SetDeathCallback in singleness mode");
260             return;
261         }
262         onDeathCallback_ = callback;
263     }
264 
OnPeerDeath()265     void ApiTransactor::OnPeerDeath()
266     {
267         LOG_W("Connection with peer died!");
268         connectState_ = DISCONNECTED;
269         if (onDeathCallback_ != nullptr) {
270             onDeathCallback_();
271         }
272     }
273 
~ApiTransactor()274     ApiTransactor::~ApiTransactor()
275     {
276         if (connectState_ == UNINIT) {
277             return;
278         }
279         if (remoteCaller_ != nullptr && peerDeathCallback_ != nullptr) {
280             remoteCaller_->UnsetRemoteDeathCallback(peerDeathCallback_);
281         }
282         caller_ = nullptr;
283         remoteCaller_ = nullptr;
284         peerDeathCallback_ = nullptr;
285     }
286 
InitAndConnectPeer(string_view token,ApiCallHandler handler)287     bool ApiTransactor::InitAndConnectPeer(string_view token, ApiCallHandler handler)
288     {
289         LOG_I("Begin");
290         DCHECK(connectState_ == UNINIT);
291         connectState_ = DISCONNECTED;
292         caller_ = new ApiCaller();
293         caller_->SetCallHandler(handler);
294         sptr<IRemoteObject> remoteObject = nullptr;
295         if (asServer_) {
296             // public caller object, and wait for backcaller registration from client
297             remoteObject = PublishCallerAndWaitForBackcaller(caller_, token);
298             if (remoteObject != nullptr) {
299                 remoteCaller_ = new ApiCallerProxy(remoteObject);
300             }
301         } else {
302             // wait for published caller object, then register backcaller to server
303             remoteObject = WaitForPublishedCaller(token);
304             if (remoteObject != nullptr) {
305                 remoteCaller_ = new ApiCallerProxy(remoteObject);
306                 if (!remoteCaller_->SetBackCaller(caller_)) {
307                     LOG_E("Failed to set backcaller to server");
308                     return false;
309                 }
310             }
311         }
312         if (remoteObject == nullptr || remoteCaller_ == nullptr) {
313             LOG_E("Failed to get apiCaller object from peer");
314             return false;
315         }
316         // in singleness mode, C/S runs in the same shell process and the remoteObject is a stub instead of proxy
317         singlenessMode_ = !remoteObject->IsProxyObject();
318         // link connectionState to it to remoteCaller
319         if (!singlenessMode_) {
320             peerDeathCallback_ = new DeathRecipientForwarder([this]() { this->OnPeerDeath(); });
321             if (!remoteCaller_->SetRemoteDeathCallback(peerDeathCallback_)) {
322                 LOG_E("Failed to register remote caller DeathRecipient");
323                 return false;
324             }
325         }
326         // connect done
327         connectState_ = CONNECTED;
328         LOG_I("Done");
329         return true;
330     }
331 
GetConnectionStat() const332     ConnectionStat ApiTransactor::GetConnectionStat() const
333     {
334         return connectState_;
335     }
336 
Finalize()337     void ApiTransactor::Finalize() {}
338 
Transact(const ApiCallInfo & call,ApiReplyInfo & reply)339     void ApiTransactor::Transact(const ApiCallInfo &call, ApiReplyInfo &reply)
340     {
341         // check connection state
342         DCHECK(connectState_ != UNINIT);
343         if (connectState_ == DISCONNECTED) {
344             reply.exception_ = ApiCallErr(ERR_INTERNAL, "ipc connection is dead");
345             return;
346         }
347         // check concurrent call
348         if (!processingApi_.empty()) {
349             constexpr auto msg = "uitest-api dose not allow calling concurrently, current processing:";
350             reply.exception_.code_ = ERR_API_USAGE;
351             reply.exception_.message_ = string(msg) + processingApi_ + ", incoming: " + call.apiId_;
352             return;
353         }
354         processingApi_ = call.apiId_;
355         // forward to peer
356         DCHECK(remoteCaller_ != nullptr);
357         remoteCaller_->Call(call, reply);
358         processingApi_.clear();
359     }
360 
361     // functions for sending/handling broadcast commands
362     BroadcastCommandHandler g_broadcastCommandHandler = nullptr;
363     shared_ptr<CommonEventForwarder> g_broadcastCommandSubscriber = nullptr;
SendBroadcastCommand(const OHOS::AAFwk::Want & cmd,ApiCallErr & err)364     void ApiTransactor::SendBroadcastCommand(const OHOS::AAFwk::Want &cmd, ApiCallErr &err)
365     {
366         LOG_I("Send uitest.broadcast.command begin");
367         CommonEventData event;
368         auto want = OHOS::AAFwk::Want(cmd);
369         want.SetAction("uitest.broadcast.command");
370         event.SetWant(want);
371         if (!CommonEventManager::PublishCommonEvent(event)) {
372             err = ApiCallErr(ERR_INTERNAL, "Failed to publish uitest.broadcast.command");
373             return;
374         }
375         LOG_I("Send uitest.broadcast.command end");
376         MatchingSkills matchingSkills;
377         matchingSkills.AddEvent("uitest.broadcast.command.reply");
378         CommonEventSubscribeInfo info(matchingSkills);
379         mutex mtx;
380         unique_lock<mutex> lock(mtx);
381         condition_variable condition;
382         auto onEvent = [&err, &condition](const CommonEventData &data) {
383             const auto &reply = data.GetWant();
384             auto code = static_cast<ErrCode>(reply.GetIntParam("code", 0));
385             err = ApiCallErr(code, reply.GetStringParam("message"));
386             condition.notify_one();
387         };
388         auto broadcastReplySubscriber = make_shared<CommonEventForwarder>(info, onEvent);
389         if (!CommonEventManager::SubscribeCommonEvent(broadcastReplySubscriber)) {
390             err = ApiCallErr(INTERNAL_ERROR, "Fail to subscribe uitest.broadcast.command.reply");
391         }
392         const auto timeout = chrono::milliseconds(WAIT_CONN_TIMEOUT_MS << 1);
393         if (condition.wait_for(lock, timeout) == cv_status::timeout) {
394             err = ApiCallErr(INTERNAL_ERROR, "Wait for subscribe uitest.broadcast.command.reply timeout");
395         }
396         CommonEventManager::UnSubscribeCommonEvent(broadcastReplySubscriber);
397         LOG_I("Receive uitest.broadcast.command.reply end");
398     }
399 
SetBroadcastCommandHandler(BroadcastCommandHandler handler)400     void ApiTransactor::SetBroadcastCommandHandler(BroadcastCommandHandler handler)
401     {
402         if (handler == nullptr) {
403             LOG_W("BroadcastCommandHandler is null");
404             return;
405         }
406         g_broadcastCommandHandler = handler;
407         if (g_broadcastCommandSubscriber != nullptr) {
408             return;
409         }
410         MatchingSkills matchingSkills;
411         matchingSkills.AddEvent("uitest.broadcast.command");
412         CommonEventSubscribeInfo info(matchingSkills);
413         auto onEvent = [](const CommonEventData &commandData) {
414             auto commandWant = OHOS::AAFwk::Want(commandData.GetWant());
415             // handle command in new thread, do not block in CommonEvent dispatching thread
416             auto _ = async(launch::async, [&commandWant]() {
417                 LOG_I("HandleBroadcastCommand begin");
418                 auto replyWant = OHOS::AAFwk::Want();
419                 ApiCallErr err = ApiCallErr(NO_ERROR);
420                 if (g_broadcastCommandHandler == nullptr) {
421                     err = ApiCallErr(INTERNAL_ERROR, "Received uitest.broadcast.command but handler is null!");
422                 } else {
423                     g_broadcastCommandHandler(commandWant, err);
424                 }
425                 replyWant.SetAction("uitest.broadcast.command.reply");
426                 replyWant.SetParam("code", (int)(err.code_));
427                 replyWant.SetParam("message", err.message_);
428                 CommonEventData replyData;
429                 replyData.SetWant(replyWant);
430                 if (!CommonEventManager::PublishCommonEvent(replyData)) {
431                     LOG_E("Fail to publish uitest.broadcast.command.reply");
432                 }
433                 LOG_I("HandleBroadcastCommand end");
434             });
435         };
436         g_broadcastCommandSubscriber = make_shared<CommonEventForwarder>(info, onEvent);
437         if (!CommonEventManager::SubscribeCommonEvent(g_broadcastCommandSubscriber)) {
438             LOG_E("Fail to subscribe uitest.broadcast.command");
439         }
440     }
441 
UnsetBroadcastCommandHandler()442     void ApiTransactor::UnsetBroadcastCommandHandler()
443     {
444         if (g_broadcastCommandSubscriber != nullptr) {
445             CommonEventManager::UnSubscribeCommonEvent(g_broadcastCommandSubscriber);
446         }
447         if (g_broadcastCommandHandler != nullptr) {
448             g_broadcastCommandHandler = nullptr;
449         }
450     }
451 } // namespace OHOS::uitest