• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "uitest_ffi.h"
17 
18 #include <cstdlib>
19 #include <grp.h>
20 #include <pthread.h>
21 #include <pwd.h>
22 #include <sched.h>
23 #include <future>
24 #include <queue>
25 #include <set>
26 #include <string>
27 #include <sys/resource.h>
28 #include <sys/syscall.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <uv.h>
32 #include "json.hpp"
33 #include "pasteboard_client.h"
34 #include "common_utilities_hpp.h"
35 #include "frontend_api_defines.h"
36 #include "ipc_transactor.h"
37 #include "ui_event_observer_impl.h"
38 
39 namespace OHOS::cjuitest {
40     using namespace nlohmann;
41     using namespace std;
42     using namespace OHOS::uitest;
43 
44     static constexpr size_t BACKEND_OBJ_GC_BATCH = 100;
45     /**For gc usage, records the backend objRefs about to delete. */
46     static queue<string> g_backendObjsAboutToDelete;
47     static mutex g_gcQueueMutex;
48     /**IPC client. */
49     static ApiTransactor g_apiTransactClient(false);
50     static future<void> g_establishConnectionFuture;
51 
MallocCString(const string & origin)52     char *MallocCString(const string &origin)
53     {
54         if (origin.empty()) {
55             return nullptr;
56         }
57         auto len = origin.length() + 1;
58         char *res = static_cast<char *>(malloc(sizeof(char) * len));
59         if (res == nullptr) {
60             return nullptr;
61         }
62         return char_traits<char>::copy(res, origin.c_str(), len);
63     }
64 
65     /**Wait connection result sync if need.*/
WaitForConnectionIfNeed()66     static void WaitForConnectionIfNeed()
67     {
68         if (g_establishConnectionFuture.valid()) {
69             LOG_I("Begin WaitForConnection");
70             g_establishConnectionFuture.get();
71         }
72     }
73 
SetPasteBoardData(string_view text)74     static void SetPasteBoardData(string_view text)
75     {
76         auto pasteBoardMgr = MiscServices::PasteboardClient::GetInstance();
77         pasteBoardMgr->Clear();
78         auto pasteData = MiscServices::PasteboardClient::GetInstance()->CreatePlainTextData(string(text));
79         pasteBoardMgr->SetPasteData(*pasteData);
80     }
81 
PreprocessTransaction(ApiCallInfo & callInfo,ApiCallErr & error)82     void PreprocessTransaction(ApiCallInfo &callInfo, ApiCallErr &error)
83     {
84         auto &paramList = callInfo.paramList_;
85         const auto &id = callInfo.apiId_;
86         if (id == "Component.inputText" && paramList.size() > 0) {
87             if (paramList.at(INDEX_ZERO).type() == nlohmann::detail::value_t::string) {
88                 SetPasteBoardData(paramList.at(INDEX_ZERO).get<string>());
89             }
90         } else if (id  == "Driver.inputText" && paramList.size() > 1) {
91             if (paramList.at(INDEX_ONE).type() == nlohmann::detail::value_t::string) {
92                 SetPasteBoardData(paramList.at(INDEX_ONE).get<string>());
93             }
94         } else if (id == "Driver.screenCap" || id == "UiDriver.screenCap" || id == "Driver.screenCapture") {
95             if (paramList.size() < 1 || paramList.at(0).type() != nlohmann::detail::value_t::string) {
96                 LOG_E("Missing file path argument");
97                 error = ApiCallErr{ERR_INVALID_INPUT, "Missing file path argument"};
98                 return;
99             }
100             auto path = paramList.at(INDEX_ZERO).get<string>();
101             auto fd = open(path.c_str(), O_RDWR | O_CREAT, 0666);
102             if (fd == -1) {
103                 LOG_E("Invalid file path: %{public}s", path.data());
104                 error = ApiCallErr{ERR_INVALID_INPUT, "Invalid file path:" + path};
105                 return;
106             }
107             paramList[INDEX_ZERO] = fd;
108             callInfo.fdParamIndex_ = INDEX_ZERO;
109         } else if (id  == "UIEventObserver.once") {
110             LOG_I("preprocess callback");
111             int64_t callbackId = paramList.at(1).get<int64_t>();
112             UiEventObserverImpl::Get().PreprocessCallOnce(callInfo, callbackId, error);
113         }
114     }
115 
116     /**Call api with parameters out, wait for and return result value or throw raised exception.*/
CJTransact(ApiCallInfo callInfo)117     ApiReplyInfo CJTransact(ApiCallInfo callInfo)
118     {
119         WaitForConnectionIfNeed();
120         LOG_D("TargetApi=%{public}s", callInfo.apiId_.data());
121         auto reply = ApiReplyInfo();
122         g_apiTransactClient.Transact(callInfo, reply);
123         LOG_I("return value: %{public}s", reply.resultValue_.dump().c_str());
124         // notify backend objects deleting
125         if (g_backendObjsAboutToDelete.size() >= BACKEND_OBJ_GC_BATCH) {
126             auto gcCall = ApiCallInfo {.apiId_ = "BackendObjectsCleaner"};
127             unique_lock<mutex> lock(g_gcQueueMutex);
128             for (size_t count = 0; count < BACKEND_OBJ_GC_BATCH; count++) {
129                 gcCall.paramList_.emplace_back(g_backendObjsAboutToDelete.front());
130                 g_backendObjsAboutToDelete.pop();
131             }
132             lock.unlock();
133             auto gcReply = ApiReplyInfo();
134             g_apiTransactClient.Transact(gcCall, gcReply);
135         }
136         return reply;
137     }
138 
GetUid()139     int32_t GetUid()
140     {
141         auto processGetuid = static_cast<int32_t>(getuid());
142         return processGetuid;
143     }
144 
GetPid()145     int32_t GetPid()
146     {
147         auto proPid = static_cast<int32_t>(getpid());
148         return proPid;
149     }
150 
GetTid()151     int32_t GetTid()
152     {
153         auto proTid = static_cast<int32_t>(gettid());
154         return proTid;
155     }
156 
157     extern "C" {
CJ_InitConnection(char * token)158         void CJ_InitConnection(char *token)
159         {
160             string realToken{token};
161             LOG_I("connect token is %{public}s", token);
162             g_establishConnectionFuture = async(launch::async, [realToken]() {
163                 auto &instance = UiEventObserverImpl::Get();
164                 using namespace std::placeholders;
165                 auto callbackHandler = std::bind(&UiEventObserverImpl::HandleEventCallback, &instance, _1, _2);
166                 auto result = g_apiTransactClient.InitAndConnectPeer(realToken, callbackHandler);
167                 LOG_I("End setup transaction connection, result=%{public}d", result);
168             });
169         }
170 
CJ_ApiCall(ApiCallParams params)171         RetDataCString CJ_ApiCall(ApiCallParams params)
172         {
173             RetDataCString ret{.code = uitest::ErrCode::NO_ERROR, .data = nullptr};
174             ApiCallInfo callInfo_;
175             LOG_D("apiId: %{public}s", params.apiId);
176             callInfo_.apiId_ = string{params.apiId};
177             if (params.callerObjRef != nullptr) {
178                 LOG_D("callerObjRef_: %{public}s", params.callerObjRef);
179                 callInfo_.callerObjRef_ = string{params.callerObjRef};
180             }
181             if (params.paramList == nullptr) {
182                 LOG_D("paramList_: \"\"");
183                 callInfo_.paramList_ = "";
184             } else {
185                 LOG_D("paramList_: %{public}s", params.paramList);
186                 callInfo_.paramList_ = nlohmann::json::parse(string{params.paramList});
187             }
188             ApiCallErr err{uitest::ErrCode::NO_ERROR};
189             PreprocessTransaction(callInfo_, err);
190             if (err.code_ != uitest::ErrCode::NO_ERROR) {
191                 ret.code = err.code_;
192                 ret.data = MallocCString(err.message_);
193                 return ret;
194             }
195             auto result = CJTransact(callInfo_);
196             if (callInfo_.fdParamIndex_ >= 0) {
197                 auto fd = callInfo_.paramList_.at(INDEX_ZERO).get<int>();
198                 (void) close(fd);
199             }
200             if (result.exception_.code_ != uitest::ErrCode::NO_ERROR) {
201                 ret.code = result.exception_.code_;
202                 ret.data = MallocCString(result.exception_.message_);
203                 return ret;
204             }
205             ret.data = MallocCString(result.resultValue_.dump());
206             return ret;
207         }
208 
CJ_UITestObjDelete(char * objref)209         void CJ_UITestObjDelete(char *objref)
210         {
211             unique_lock<mutex> lock(g_gcQueueMutex);
212             g_backendObjsAboutToDelete.push(string(objref));
213         }
214 
FfiOHOSProcessManagerGetUid()215         int32_t FfiOHOSProcessManagerGetUid()
216         {
217             auto result = GetUid();
218             return result;
219         }
220 
FfiOHOSProcessManagerGetPid()221         int32_t FfiOHOSProcessManagerGetPid()
222         {
223             auto result = GetPid();
224             return result;
225         }
226 
FfiOHOSProcessManagerGetTid()227         int32_t FfiOHOSProcessManagerGetTid()
228         {
229             auto result = GetTid();
230             return result;
231         }
232     }
233 } // namespace OHOS::uitest
234