• 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 "nlohmann/json.hpp"
32 #include "fcntl.h"
33 #include "common_utilities_hpp.h"
34 #include "frontend_api_defines.h"
35 #include "ipc_transactor.h"
36 #include "ui_event_observer_impl.h"
37 #include "test_server_client.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         OHOS::testserver::TestServerClient::GetInstance().SetPasteData(string(text));
77     }
78 
PreprocessTransaction(ApiCallInfo & callInfo,ApiCallErr & error)79     void PreprocessTransaction(ApiCallInfo &callInfo, ApiCallErr &error)
80     {
81         auto &paramList = callInfo.paramList_;
82         const auto &id = callInfo.apiId_;
83         if (id == "Component.inputText" && paramList.size() > 0) {
84             if (paramList.at(INDEX_ZERO).type() == nlohmann::detail::value_t::string) {
85                 SetPasteBoardData(paramList.at(INDEX_ZERO).get<string>());
86             }
87         } else if (id  == "Driver.inputText" && paramList.size() > 1) {
88             if (paramList.at(INDEX_ONE).type() == nlohmann::detail::value_t::string) {
89                 SetPasteBoardData(paramList.at(INDEX_ONE).get<string>());
90             }
91         } else if (id == "Driver.screenCap" || id == "UiDriver.screenCap" || id == "Driver.screenCapture") {
92             if (paramList.size() < 1 || paramList.at(0).type() != nlohmann::detail::value_t::string) {
93                 LOG_E("Missing file path argument");
94                 error = ApiCallErr{ERR_INVALID_INPUT, "Missing file path argument"};
95                 return;
96             }
97             auto path = paramList.at(INDEX_ZERO).get<string>();
98             auto fd = open(path.c_str(), O_RDWR | O_CREAT, 0666);
99             if (fd == -1) {
100                 LOG_E("Invalid file path: %{public}s", path.data());
101                 error = ApiCallErr{ERR_INVALID_INPUT, "Invalid file path:" + path};
102                 return;
103             }
104             paramList[INDEX_ZERO] = fd;
105             callInfo.fdParamIndex_ = INDEX_ZERO;
106         } else if (id  == "UIEventObserver.once") {
107             LOG_I("preprocess callback");
108             int64_t callbackId = paramList.at(1).get<int64_t>();
109             UiEventObserverImpl::Get().PreprocessCallOnce(callInfo, callbackId, error);
110         }
111     }
112 
113     /**Call api with parameters out, wait for and return result value or throw raised exception.*/
CJTransact(ApiCallInfo callInfo)114     ApiReplyInfo CJTransact(ApiCallInfo callInfo)
115     {
116         WaitForConnectionIfNeed();
117         LOG_D("TargetApi=%{public}s", callInfo.apiId_.data());
118         auto reply = ApiReplyInfo();
119         g_apiTransactClient.Transact(callInfo, reply);
120         LOG_I("return value: %{public}s", reply.resultValue_.dump().c_str());
121         // notify backend objects deleting
122         if (g_backendObjsAboutToDelete.size() >= BACKEND_OBJ_GC_BATCH) {
123             auto gcCall = ApiCallInfo {.apiId_ = "BackendObjectsCleaner"};
124             unique_lock<mutex> lock(g_gcQueueMutex);
125             for (size_t count = 0; count < BACKEND_OBJ_GC_BATCH; count++) {
126                 gcCall.paramList_.emplace_back(g_backendObjsAboutToDelete.front());
127                 g_backendObjsAboutToDelete.pop();
128             }
129             lock.unlock();
130             auto gcReply = ApiReplyInfo();
131             g_apiTransactClient.Transact(gcCall, gcReply);
132         }
133         return reply;
134     }
135 
GetUid()136     int32_t GetUid()
137     {
138         auto processGetuid = static_cast<int32_t>(getuid());
139         return processGetuid;
140     }
141 
GetPid()142     int32_t GetPid()
143     {
144         auto proPid = static_cast<int32_t>(getpid());
145         return proPid;
146     }
147 
GetTid()148     int32_t GetTid()
149     {
150         auto proTid = static_cast<int32_t>(gettid());
151         return proTid;
152     }
153 
154     extern "C" {
CJ_InitConnection(char * token)155         void CJ_InitConnection(char *token)
156         {
157             string realToken{token};
158             g_establishConnectionFuture = async(launch::async, [realToken]() {
159                 auto &instance = UiEventObserverImpl::Get();
160                 using namespace std::placeholders;
161                 auto callbackHandler = std::bind(&UiEventObserverImpl::HandleEventCallback, &instance, _1, _2);
162                 auto result = g_apiTransactClient.InitAndConnectPeer(realToken, callbackHandler);
163                 LOG_I("End setup transaction connection, result=%{public}d", result);
164             });
165         }
166 
CJ_ApiCall(ApiCallParams params)167         RetDataCString CJ_ApiCall(ApiCallParams params)
168         {
169             RetDataCString ret{.code = uitest::ErrCode::NO_ERROR, .data = nullptr};
170             ApiCallInfo callInfo_;
171             LOG_D("apiId: %{public}s", params.apiId);
172             callInfo_.apiId_ = string{params.apiId};
173             if (params.callerObjRef != nullptr) {
174                 LOG_D("callerObjRef_: %{public}s", params.callerObjRef);
175                 callInfo_.callerObjRef_ = string{params.callerObjRef};
176             }
177             if (params.paramList == nullptr) {
178                 LOG_D("paramList_: \"\"");
179                 callInfo_.paramList_ = "";
180             } else {
181                 LOG_D("paramList_: %{public}s", params.paramList);
182                 callInfo_.paramList_ = nlohmann::json::parse(string{params.paramList});
183             }
184             ApiCallErr err{uitest::ErrCode::NO_ERROR};
185             PreprocessTransaction(callInfo_, err);
186             if (err.code_ != uitest::ErrCode::NO_ERROR) {
187                 ret.code = err.code_;
188                 ret.data = MallocCString(err.message_);
189                 return ret;
190             }
191             auto result = CJTransact(callInfo_);
192             if (callInfo_.fdParamIndex_ >= 0) {
193                 auto fd = callInfo_.paramList_.at(INDEX_ZERO).get<int>();
194                 (void) close(fd);
195             }
196             if (result.exception_.code_ != uitest::ErrCode::NO_ERROR) {
197                 ret.code = result.exception_.code_;
198                 ret.data = MallocCString(result.exception_.message_);
199                 return ret;
200             }
201             ret.data = MallocCString(result.resultValue_.dump());
202             return ret;
203         }
204 
CJ_UITestObjDelete(char * objref)205         void CJ_UITestObjDelete(char *objref)
206         {
207             unique_lock<mutex> lock(g_gcQueueMutex);
208             g_backendObjsAboutToDelete.push(string(objref));
209         }
210 
FfiOHOSProcessManagerGetUid()211         int32_t FfiOHOSProcessManagerGetUid()
212         {
213             auto result = GetUid();
214             return result;
215         }
216 
FfiOHOSProcessManagerGetPid()217         int32_t FfiOHOSProcessManagerGetPid()
218         {
219             auto result = GetPid();
220             return result;
221         }
222 
FfiOHOSProcessManagerGetTid()223         int32_t FfiOHOSProcessManagerGetTid()
224         {
225             auto result = GetTid();
226             return result;
227         }
228     }
229 } // namespace OHOS::uitest
230