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 "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 LOG_I("connect token is %{public}s", token); 159 g_establishConnectionFuture = async(launch::async, [realToken]() { 160 auto &instance = UiEventObserverImpl::Get(); 161 using namespace std::placeholders; 162 auto callbackHandler = std::bind(&UiEventObserverImpl::HandleEventCallback, &instance, _1, _2); 163 auto result = g_apiTransactClient.InitAndConnectPeer(realToken, callbackHandler); 164 LOG_I("End setup transaction connection, result=%{public}d", result); 165 }); 166 } 167 CJ_ApiCall(ApiCallParams params)168 RetDataCString CJ_ApiCall(ApiCallParams params) 169 { 170 RetDataCString ret{.code = uitest::ErrCode::NO_ERROR, .data = nullptr}; 171 ApiCallInfo callInfo_; 172 LOG_D("apiId: %{public}s", params.apiId); 173 callInfo_.apiId_ = string{params.apiId}; 174 if (params.callerObjRef != nullptr) { 175 LOG_D("callerObjRef_: %{public}s", params.callerObjRef); 176 callInfo_.callerObjRef_ = string{params.callerObjRef}; 177 } 178 if (params.paramList == nullptr) { 179 LOG_D("paramList_: \"\""); 180 callInfo_.paramList_ = ""; 181 } else { 182 LOG_D("paramList_: %{public}s", params.paramList); 183 callInfo_.paramList_ = nlohmann::json::parse(string{params.paramList}); 184 } 185 ApiCallErr err{uitest::ErrCode::NO_ERROR}; 186 PreprocessTransaction(callInfo_, err); 187 if (err.code_ != uitest::ErrCode::NO_ERROR) { 188 ret.code = err.code_; 189 ret.data = MallocCString(err.message_); 190 return ret; 191 } 192 auto result = CJTransact(callInfo_); 193 if (callInfo_.fdParamIndex_ >= 0) { 194 auto fd = callInfo_.paramList_.at(INDEX_ZERO).get<int>(); 195 (void) close(fd); 196 } 197 if (result.exception_.code_ != uitest::ErrCode::NO_ERROR) { 198 ret.code = result.exception_.code_; 199 ret.data = MallocCString(result.exception_.message_); 200 return ret; 201 } 202 ret.data = MallocCString(result.resultValue_.dump()); 203 return ret; 204 } 205 CJ_UITestObjDelete(char *objref)206 void CJ_UITestObjDelete(char *objref) 207 { 208 unique_lock<mutex> lock(g_gcQueueMutex); 209 g_backendObjsAboutToDelete.push(string(objref)); 210 } 211 FfiOHOSProcessManagerGetUid()212 int32_t FfiOHOSProcessManagerGetUid() 213 { 214 auto result = GetUid(); 215 return result; 216 } 217 FfiOHOSProcessManagerGetPid()218 int32_t FfiOHOSProcessManagerGetPid() 219 { 220 auto result = GetPid(); 221 return result; 222 } 223 FfiOHOSProcessManagerGetTid()224 int32_t FfiOHOSProcessManagerGetTid() 225 { 226 auto result = GetTid(); 227 return result; 228 } 229 } 230 } // namespace OHOS::uitest 231