1886da342Sopenharmony_ci/*
2886da342Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3886da342Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4886da342Sopenharmony_ci * you may not use this file except in compliance with the License.
5886da342Sopenharmony_ci * You may obtain a copy of the License at
6886da342Sopenharmony_ci *
7886da342Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8886da342Sopenharmony_ci *
9886da342Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10886da342Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11886da342Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12886da342Sopenharmony_ci * See the License for the specific language governing permissions and
13886da342Sopenharmony_ci * limitations under the License.
14886da342Sopenharmony_ci */
15886da342Sopenharmony_ci
16886da342Sopenharmony_ci#include "uitest_ffi.h"
17886da342Sopenharmony_ci
18886da342Sopenharmony_ci#include <cstdlib>
19886da342Sopenharmony_ci#include <grp.h>
20886da342Sopenharmony_ci#include <pthread.h>
21886da342Sopenharmony_ci#include <pwd.h>
22886da342Sopenharmony_ci#include <sched.h>
23886da342Sopenharmony_ci#include <future>
24886da342Sopenharmony_ci#include <queue>
25886da342Sopenharmony_ci#include <set>
26886da342Sopenharmony_ci#include <string>
27886da342Sopenharmony_ci#include <sys/resource.h>
28886da342Sopenharmony_ci#include <sys/syscall.h>
29886da342Sopenharmony_ci#include <sys/types.h>
30886da342Sopenharmony_ci#include <unistd.h>
31886da342Sopenharmony_ci#include "json.hpp"
32886da342Sopenharmony_ci#include "fcntl.h"
33886da342Sopenharmony_ci#include "common_utilities_hpp.h"
34886da342Sopenharmony_ci#include "frontend_api_defines.h"
35886da342Sopenharmony_ci#include "ipc_transactor.h"
36886da342Sopenharmony_ci#include "ui_event_observer_impl.h"
37886da342Sopenharmony_ci#include "test_server_client.h"
38886da342Sopenharmony_ci
39886da342Sopenharmony_cinamespace OHOS::cjuitest {
40886da342Sopenharmony_ci    using namespace nlohmann;
41886da342Sopenharmony_ci    using namespace std;
42886da342Sopenharmony_ci    using namespace OHOS::uitest;
43886da342Sopenharmony_ci
44886da342Sopenharmony_ci    static constexpr size_t BACKEND_OBJ_GC_BATCH = 100;
45886da342Sopenharmony_ci    /**For gc usage, records the backend objRefs about to delete. */
46886da342Sopenharmony_ci    static queue<string> g_backendObjsAboutToDelete;
47886da342Sopenharmony_ci    static mutex g_gcQueueMutex;
48886da342Sopenharmony_ci    /**IPC client. */
49886da342Sopenharmony_ci    static ApiTransactor g_apiTransactClient(false);
50886da342Sopenharmony_ci    static future<void> g_establishConnectionFuture;
51886da342Sopenharmony_ci
52886da342Sopenharmony_ci    char *MallocCString(const string &origin)
53886da342Sopenharmony_ci    {
54886da342Sopenharmony_ci        if (origin.empty()) {
55886da342Sopenharmony_ci            return nullptr;
56886da342Sopenharmony_ci        }
57886da342Sopenharmony_ci        auto len = origin.length() + 1;
58886da342Sopenharmony_ci        char *res = static_cast<char *>(malloc(sizeof(char) * len));
59886da342Sopenharmony_ci        if (res == nullptr) {
60886da342Sopenharmony_ci            return nullptr;
61886da342Sopenharmony_ci        }
62886da342Sopenharmony_ci        return char_traits<char>::copy(res, origin.c_str(), len);
63886da342Sopenharmony_ci    }
64886da342Sopenharmony_ci
65886da342Sopenharmony_ci    /**Wait connection result sync if need.*/
66886da342Sopenharmony_ci    static void WaitForConnectionIfNeed()
67886da342Sopenharmony_ci    {
68886da342Sopenharmony_ci        if (g_establishConnectionFuture.valid()) {
69886da342Sopenharmony_ci            LOG_I("Begin WaitForConnection");
70886da342Sopenharmony_ci            g_establishConnectionFuture.get();
71886da342Sopenharmony_ci        }
72886da342Sopenharmony_ci    }
73886da342Sopenharmony_ci
74886da342Sopenharmony_ci    static void SetPasteBoardData(string_view text)
75886da342Sopenharmony_ci    {
76886da342Sopenharmony_ci        OHOS::testserver::TestServerClient::GetInstance().SetPasteData(string(text));
77886da342Sopenharmony_ci    }
78886da342Sopenharmony_ci
79886da342Sopenharmony_ci    void PreprocessTransaction(ApiCallInfo &callInfo, ApiCallErr &error)
80886da342Sopenharmony_ci    {
81886da342Sopenharmony_ci        auto &paramList = callInfo.paramList_;
82886da342Sopenharmony_ci        const auto &id = callInfo.apiId_;
83886da342Sopenharmony_ci        if (id == "Component.inputText" && paramList.size() > 0) {
84886da342Sopenharmony_ci            if (paramList.at(INDEX_ZERO).type() == nlohmann::detail::value_t::string) {
85886da342Sopenharmony_ci                SetPasteBoardData(paramList.at(INDEX_ZERO).get<string>());
86886da342Sopenharmony_ci            }
87886da342Sopenharmony_ci        } else if (id  == "Driver.inputText" && paramList.size() > 1) {
88886da342Sopenharmony_ci            if (paramList.at(INDEX_ONE).type() == nlohmann::detail::value_t::string) {
89886da342Sopenharmony_ci                SetPasteBoardData(paramList.at(INDEX_ONE).get<string>());
90886da342Sopenharmony_ci            }
91886da342Sopenharmony_ci        } else if (id == "Driver.screenCap" || id == "UiDriver.screenCap" || id == "Driver.screenCapture") {
92886da342Sopenharmony_ci            if (paramList.size() < 1 || paramList.at(0).type() != nlohmann::detail::value_t::string) {
93886da342Sopenharmony_ci                LOG_E("Missing file path argument");
94886da342Sopenharmony_ci                error = ApiCallErr{ERR_INVALID_INPUT, "Missing file path argument"};
95886da342Sopenharmony_ci                return;
96886da342Sopenharmony_ci            }
97886da342Sopenharmony_ci            auto path = paramList.at(INDEX_ZERO).get<string>();
98886da342Sopenharmony_ci            auto fd = open(path.c_str(), O_RDWR | O_CREAT, 0666);
99886da342Sopenharmony_ci            if (fd == -1) {
100886da342Sopenharmony_ci                LOG_E("Invalid file path: %{public}s", path.data());
101886da342Sopenharmony_ci                error = ApiCallErr{ERR_INVALID_INPUT, "Invalid file path:" + path};
102886da342Sopenharmony_ci                return;
103886da342Sopenharmony_ci            }
104886da342Sopenharmony_ci            paramList[INDEX_ZERO] = fd;
105886da342Sopenharmony_ci            callInfo.fdParamIndex_ = INDEX_ZERO;
106886da342Sopenharmony_ci        } else if (id  == "UIEventObserver.once") {
107886da342Sopenharmony_ci            LOG_I("preprocess callback");
108886da342Sopenharmony_ci            int64_t callbackId = paramList.at(1).get<int64_t>();
109886da342Sopenharmony_ci            UiEventObserverImpl::Get().PreprocessCallOnce(callInfo, callbackId, error);
110886da342Sopenharmony_ci        }
111886da342Sopenharmony_ci    }
112886da342Sopenharmony_ci
113886da342Sopenharmony_ci    /**Call api with parameters out, wait for and return result value or throw raised exception.*/
114886da342Sopenharmony_ci    ApiReplyInfo CJTransact(ApiCallInfo callInfo)
115886da342Sopenharmony_ci    {
116886da342Sopenharmony_ci        WaitForConnectionIfNeed();
117886da342Sopenharmony_ci        LOG_D("TargetApi=%{public}s", callInfo.apiId_.data());
118886da342Sopenharmony_ci        auto reply = ApiReplyInfo();
119886da342Sopenharmony_ci        g_apiTransactClient.Transact(callInfo, reply);
120886da342Sopenharmony_ci        LOG_I("return value: %{public}s", reply.resultValue_.dump().c_str());
121886da342Sopenharmony_ci        // notify backend objects deleting
122886da342Sopenharmony_ci        if (g_backendObjsAboutToDelete.size() >= BACKEND_OBJ_GC_BATCH) {
123886da342Sopenharmony_ci            auto gcCall = ApiCallInfo {.apiId_ = "BackendObjectsCleaner"};
124886da342Sopenharmony_ci            unique_lock<mutex> lock(g_gcQueueMutex);
125886da342Sopenharmony_ci            for (size_t count = 0; count < BACKEND_OBJ_GC_BATCH; count++) {
126886da342Sopenharmony_ci                gcCall.paramList_.emplace_back(g_backendObjsAboutToDelete.front());
127886da342Sopenharmony_ci                g_backendObjsAboutToDelete.pop();
128886da342Sopenharmony_ci            }
129886da342Sopenharmony_ci            lock.unlock();
130886da342Sopenharmony_ci            auto gcReply = ApiReplyInfo();
131886da342Sopenharmony_ci            g_apiTransactClient.Transact(gcCall, gcReply);
132886da342Sopenharmony_ci        }
133886da342Sopenharmony_ci        return reply;
134886da342Sopenharmony_ci    }
135886da342Sopenharmony_ci
136886da342Sopenharmony_ci    int32_t GetUid()
137886da342Sopenharmony_ci    {
138886da342Sopenharmony_ci        auto processGetuid = static_cast<int32_t>(getuid());
139886da342Sopenharmony_ci        return processGetuid;
140886da342Sopenharmony_ci    }
141886da342Sopenharmony_ci
142886da342Sopenharmony_ci    int32_t GetPid()
143886da342Sopenharmony_ci    {
144886da342Sopenharmony_ci        auto proPid = static_cast<int32_t>(getpid());
145886da342Sopenharmony_ci        return proPid;
146886da342Sopenharmony_ci    }
147886da342Sopenharmony_ci
148886da342Sopenharmony_ci    int32_t GetTid()
149886da342Sopenharmony_ci    {
150886da342Sopenharmony_ci        auto proTid = static_cast<int32_t>(gettid());
151886da342Sopenharmony_ci        return proTid;
152886da342Sopenharmony_ci    }
153886da342Sopenharmony_ci
154886da342Sopenharmony_ci    extern "C" {
155886da342Sopenharmony_ci        void CJ_InitConnection(char *token)
156886da342Sopenharmony_ci        {
157886da342Sopenharmony_ci            string realToken{token};
158886da342Sopenharmony_ci            LOG_I("connect token is %{public}s", token);
159886da342Sopenharmony_ci            g_establishConnectionFuture = async(launch::async, [realToken]() {
160886da342Sopenharmony_ci                auto &instance = UiEventObserverImpl::Get();
161886da342Sopenharmony_ci                using namespace std::placeholders;
162886da342Sopenharmony_ci                auto callbackHandler = std::bind(&UiEventObserverImpl::HandleEventCallback, &instance, _1, _2);
163886da342Sopenharmony_ci                auto result = g_apiTransactClient.InitAndConnectPeer(realToken, callbackHandler);
164886da342Sopenharmony_ci                LOG_I("End setup transaction connection, result=%{public}d", result);
165886da342Sopenharmony_ci            });
166886da342Sopenharmony_ci        }
167886da342Sopenharmony_ci
168886da342Sopenharmony_ci        RetDataCString CJ_ApiCall(ApiCallParams params)
169886da342Sopenharmony_ci        {
170886da342Sopenharmony_ci            RetDataCString ret{.code = uitest::ErrCode::NO_ERROR, .data = nullptr};
171886da342Sopenharmony_ci            ApiCallInfo callInfo_;
172886da342Sopenharmony_ci            LOG_D("apiId: %{public}s", params.apiId);
173886da342Sopenharmony_ci            callInfo_.apiId_ = string{params.apiId};
174886da342Sopenharmony_ci            if (params.callerObjRef != nullptr) {
175886da342Sopenharmony_ci                LOG_D("callerObjRef_: %{public}s", params.callerObjRef);
176886da342Sopenharmony_ci                callInfo_.callerObjRef_ = string{params.callerObjRef};
177886da342Sopenharmony_ci            }
178886da342Sopenharmony_ci            if (params.paramList == nullptr) {
179886da342Sopenharmony_ci                LOG_D("paramList_: \"\"");
180886da342Sopenharmony_ci                callInfo_.paramList_ = "";
181886da342Sopenharmony_ci            } else {
182886da342Sopenharmony_ci                LOG_D("paramList_: %{public}s", params.paramList);
183886da342Sopenharmony_ci                callInfo_.paramList_ = nlohmann::json::parse(string{params.paramList});
184886da342Sopenharmony_ci            }
185886da342Sopenharmony_ci            ApiCallErr err{uitest::ErrCode::NO_ERROR};
186886da342Sopenharmony_ci            PreprocessTransaction(callInfo_, err);
187886da342Sopenharmony_ci            if (err.code_ != uitest::ErrCode::NO_ERROR) {
188886da342Sopenharmony_ci                ret.code = err.code_;
189886da342Sopenharmony_ci                ret.data = MallocCString(err.message_);
190886da342Sopenharmony_ci                return ret;
191886da342Sopenharmony_ci            }
192886da342Sopenharmony_ci            auto result = CJTransact(callInfo_);
193886da342Sopenharmony_ci            if (callInfo_.fdParamIndex_ >= 0) {
194886da342Sopenharmony_ci                auto fd = callInfo_.paramList_.at(INDEX_ZERO).get<int>();
195886da342Sopenharmony_ci                (void) close(fd);
196886da342Sopenharmony_ci            }
197886da342Sopenharmony_ci            if (result.exception_.code_ != uitest::ErrCode::NO_ERROR) {
198886da342Sopenharmony_ci                ret.code = result.exception_.code_;
199886da342Sopenharmony_ci                ret.data = MallocCString(result.exception_.message_);
200886da342Sopenharmony_ci                return ret;
201886da342Sopenharmony_ci            }
202886da342Sopenharmony_ci            ret.data = MallocCString(result.resultValue_.dump());
203886da342Sopenharmony_ci            return ret;
204886da342Sopenharmony_ci        }
205886da342Sopenharmony_ci
206886da342Sopenharmony_ci        void CJ_UITestObjDelete(char *objref)
207886da342Sopenharmony_ci        {
208886da342Sopenharmony_ci            unique_lock<mutex> lock(g_gcQueueMutex);
209886da342Sopenharmony_ci            g_backendObjsAboutToDelete.push(string(objref));
210886da342Sopenharmony_ci        }
211886da342Sopenharmony_ci
212886da342Sopenharmony_ci        int32_t FfiOHOSProcessManagerGetUid()
213886da342Sopenharmony_ci        {
214886da342Sopenharmony_ci            auto result = GetUid();
215886da342Sopenharmony_ci            return result;
216886da342Sopenharmony_ci        }
217886da342Sopenharmony_ci
218886da342Sopenharmony_ci        int32_t FfiOHOSProcessManagerGetPid()
219886da342Sopenharmony_ci        {
220886da342Sopenharmony_ci            auto result = GetPid();
221886da342Sopenharmony_ci            return result;
222886da342Sopenharmony_ci        }
223886da342Sopenharmony_ci
224886da342Sopenharmony_ci        int32_t FfiOHOSProcessManagerGetTid()
225886da342Sopenharmony_ci        {
226886da342Sopenharmony_ci            auto result = GetTid();
227886da342Sopenharmony_ci            return result;
228886da342Sopenharmony_ci        }
229886da342Sopenharmony_ci    }
230886da342Sopenharmony_ci} // namespace OHOS::uitest
231