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 ¶mList = 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