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
26namespace 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:
38        explicit CommonEventForwarder(const CommonEventSubscribeInfo &info, CommonEventHandler handler)
39            : CommonEventSubscriber(info), handler_(handler)
40        {
41        }
42
43        virtual ~CommonEventForwarder() {}
44
45        void UpdateHandler(CommonEventHandler handler)
46        {
47            handler_ = handler;
48        }
49
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:
64        explicit DeathRecipientForwarder(RemoteDiedHandler handler) : handler_(handler) {};
65        ~DeathRecipientForwarder() = default;
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
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
108    void ApiCaller::Call(const ApiCallInfo &call, ApiReplyInfo &result)
109    {
110        DCHECK(handler_ != nullptr);
111        handler_(call, result);
112    }
113
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
124    void ApiCaller::SetCallHandler(ApiCallHandler handler)
125    {
126        handler_ = handler;
127    }
128
129    void ApiCaller::SetBackCallerHandler(function<void(sptr<IRemoteObject>)> handler)
130    {
131        backcallerHandler_ = handler;
132    }
133
134    ApiCallerProxy::ApiCallerProxy(const sptr<IRemoteObject> &impl) : IRemoteProxy<IApiCaller>(impl) {}
135
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
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
178    bool ApiCallerProxy::SetRemoteDeathCallback(const sptr<IRemoteObject::DeathRecipient> &callback)
179    {
180        return Remote()->AddDeathRecipient(callback);
181    }
182
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
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
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
259    ApiTransactor::ApiTransactor(bool asServer) : asServer_(asServer) {};
260
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
270    void ApiTransactor::OnPeerDeath()
271    {
272        LOG_W("Connection with peer died!");
273        connectState_ = DISCONNECTED;
274        if (onDeathCallback_ != nullptr) {
275            onDeathCallback_();
276        }
277    }
278
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
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
337    ConnectionStat ApiTransactor::GetConnectionStat() const
338    {
339        return connectState_;
340    }
341
342    void ApiTransactor::Finalize() {}
343
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;
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
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
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