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