1 /* 2 * Copyright (c) 2021-2022 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 <atomic> 17 #include <chrono> 18 #include <fstream> 19 #include <memory> 20 #include <iostream> 21 #include <thread> 22 #include <utility> 23 #include <condition_variable> 24 #include <sys/mman.h> 25 #ifdef HIDUMPER_ENABLED 26 #include <iservice_registry.h> 27 #include <system_ability_load_callback_stub.h> 28 #include "idump_broker.h" 29 #include "system_ability_definition.h" 30 #endif 31 #include "pasteboard_client.h" 32 #include "accessibility_event_info.h" 33 #include "accessibility_ui_test_ability.h" 34 #include "ability_manager_client.h" 35 #include "display_manager.h" 36 #include "screen_manager.h" 37 #include "input_manager.h" 38 #include "png.h" 39 #include "wm_common.h" 40 #include "element_node_iterator_impl.h" 41 #include "system_ui_controller.h" 42 43 using namespace std; 44 using namespace chrono; 45 46 namespace OHOS::uitest { 47 using namespace std; 48 using namespace nlohmann; 49 using namespace OHOS::MMI; 50 using namespace OHOS::Accessibility; 51 using namespace OHOS::Rosen; 52 using namespace OHOS::Media; 53 using namespace OHOS::HiviewDFX; 54 using namespace OHOS; 55 56 class UiEventMonitor final : public AccessibleAbilityListener { 57 public: 58 virtual ~UiEventMonitor() override = default; 59 60 void OnAbilityConnected() override; 61 62 void OnAbilityDisconnected() override; 63 64 void OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) override; 65 66 void SetOnAbilityConnectCallback(function<void()> onConnectCb); 67 68 void SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb); 69 OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> & keyEvent)70 bool OnKeyPressEvent(const shared_ptr<MMI::KeyEvent> &keyEvent) override 71 { 72 return false; 73 } 74 75 uint64_t GetLastEventMillis(); 76 77 bool WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs); 78 79 void WaitScrollCompelete(); 80 81 void RegisterUiEventListener(shared_ptr<UiEventListener> listerner); 82 83 private: 84 function<void()> onConnectCallback_ = nullptr; 85 function<void()> onDisConnectCallback_ = nullptr; 86 atomic<uint64_t> lastEventMillis_ = 0; 87 atomic<uint64_t> lastScrollBeginEventMillis_ = 0; 88 atomic<bool> scrollCompelete_ = true; 89 vector<shared_ptr<UiEventListener>> listeners_; 90 }; 91 92 struct EventSpec { 93 std::string_view componentTyep; 94 int32_t eventType; 95 std::string_view event; 96 }; 97 98 static constexpr EventSpec WATCHED_EVENTS[] = { 99 {"Toast", WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE, "toastShow"}, 100 {"AlertDialog", WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE, "dialogShow"} 101 }; 102 GetWatchedEvent(const AccessibilityEventInfo & eventInfo)103 static std::string GetWatchedEvent(const AccessibilityEventInfo &eventInfo) 104 { 105 for (unsigned long index = 0; index < sizeof(WATCHED_EVENTS) / sizeof(EventSpec); index++) { 106 if (WATCHED_EVENTS[index].componentTyep == eventInfo.GetComponentType() && 107 WATCHED_EVENTS[index].eventType == eventInfo.GetWindowContentChangeTypes()) { 108 LOG_W("Capture event: %{public}s", WATCHED_EVENTS[index].event.data()); 109 return string(WATCHED_EVENTS[index].event); 110 } 111 } 112 return "undefine"; 113 } 114 115 // UiEventMonitor instance. 116 static shared_ptr<UiEventMonitor> g_monitorInstance_ = make_shared<UiEventMonitor>(); 117 SetOnAbilityConnectCallback(function<void ()> onConnectCb)118 void UiEventMonitor::SetOnAbilityConnectCallback(function<void()> onConnectCb) 119 { 120 onConnectCallback_ = std::move(onConnectCb); 121 } 122 SetOnAbilityDisConnectCallback(function<void ()> onDisConnectCb)123 void UiEventMonitor::SetOnAbilityDisConnectCallback(function<void()> onDisConnectCb) 124 { 125 onDisConnectCallback_ = std::move(onDisConnectCb); 126 } 127 OnAbilityConnected()128 void UiEventMonitor::OnAbilityConnected() 129 { 130 if (onConnectCallback_ != nullptr) { 131 onConnectCallback_(); 132 } 133 } 134 OnAbilityDisconnected()135 void UiEventMonitor::OnAbilityDisconnected() 136 { 137 if (onDisConnectCallback_ != nullptr) { 138 onDisConnectCallback_(); 139 } 140 } 141 142 // the monitored events 143 static constexpr uint32_t EVENT_MASK = EventType::TYPE_VIEW_TEXT_UPDATE_EVENT | 144 EventType::TYPE_PAGE_STATE_UPDATE | 145 EventType::TYPE_PAGE_CONTENT_UPDATE | 146 EventType::TYPE_VIEW_SCROLLED_EVENT | 147 EventType::TYPE_WINDOW_UPDATE; 148 RegisterUiEventListener(std::shared_ptr<UiEventListener> listerner)149 void UiEventMonitor::RegisterUiEventListener(std::shared_ptr<UiEventListener> listerner) 150 { 151 listeners_.emplace_back(listerner); 152 } 153 OnAccessibilityEvent(const AccessibilityEventInfo & eventInfo)154 void UiEventMonitor::OnAccessibilityEvent(const AccessibilityEventInfo &eventInfo) 155 { 156 auto eventType = eventInfo.GetEventType(); 157 LOG_W("OnEvent:0x%{public}x", eventType); 158 auto capturedEvent = GetWatchedEvent(eventInfo); 159 if (eventType == Accessibility::EventType::TYPE_VIEW_SCROLLED_START) { 160 LOG_I("Capture scroll begin"); 161 scrollCompelete_.store(false); 162 lastScrollBeginEventMillis_.store(GetCurrentMillisecond()); 163 } 164 if (eventType == Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT) { 165 LOG_I("Capture scroll end"); 166 scrollCompelete_.store(true); 167 } 168 if (capturedEvent != "undefine") { 169 auto bundleName = eventInfo.GetBundleName(); 170 auto contentList = eventInfo.GetContentList(); 171 auto text = !contentList.empty() ? contentList[0] : ""; 172 auto type = eventInfo.GetComponentType(); 173 UiEventSourceInfo uiEventSourceInfo = {bundleName, text, type}; 174 for (auto &listener : listeners_) { 175 listener->OnEvent(capturedEvent, uiEventSourceInfo); 176 } 177 } 178 if ((eventInfo.GetEventType() & EVENT_MASK) > 0) { 179 lastEventMillis_.store(GetCurrentMillisecond()); 180 } 181 } 182 GetLastEventMillis()183 uint64_t UiEventMonitor::GetLastEventMillis() 184 { 185 if (lastEventMillis_.load() <= 0) { 186 lastEventMillis_.store(GetCurrentMillisecond()); 187 } 188 return lastEventMillis_.load(); 189 } 190 WaitScrollCompelete()191 void UiEventMonitor::WaitScrollCompelete() 192 { 193 if (scrollCompelete_.load()) { 194 return; 195 } 196 const auto currentMs = GetCurrentMillisecond(); 197 if (lastScrollBeginEventMillis_.load() <= 0) { 198 lastScrollBeginEventMillis_.store(currentMs); 199 } 200 const auto idleThresholdMs = 10000; 201 if (currentMs - lastScrollBeginEventMillis_.load() >= idleThresholdMs) { 202 LOG_E("wai for scrollEnd event timeout."); 203 scrollCompelete_.store(true); 204 return; 205 } 206 static constexpr auto sliceMs = 10; 207 this_thread::sleep_for(chrono::milliseconds(sliceMs)); 208 return WaitScrollCompelete(); 209 } 210 WaitEventIdle(uint32_t idleThresholdMs,uint32_t timeoutMs)211 bool UiEventMonitor::WaitEventIdle(uint32_t idleThresholdMs, uint32_t timeoutMs) 212 { 213 const auto currentMs = GetCurrentMillisecond(); 214 if (lastEventMillis_.load() <= 0) { 215 lastEventMillis_.store(currentMs); 216 } 217 if (currentMs - lastEventMillis_.load() >= idleThresholdMs) { 218 return true; 219 } 220 static constexpr auto sliceMs = 10; 221 this_thread::sleep_for(chrono::milliseconds(sliceMs)); 222 if (timeoutMs <= sliceMs) { 223 return false; 224 } 225 return WaitEventIdle(idleThresholdMs, timeoutMs - sliceMs); 226 } 227 SysUiController()228 SysUiController::SysUiController() : UiController() {} 229 ~SysUiController()230 SysUiController::~SysUiController() 231 { 232 DisConnectFromSysAbility(); 233 } 234 Initialize()235 bool SysUiController::Initialize() 236 { 237 return this->ConnectToSysAbility(); 238 } 239 GetVisibleRect(Rect windowBounds,Accessibility::Rect nodeBounds)240 static Rect GetVisibleRect(Rect windowBounds, Accessibility::Rect nodeBounds) 241 { 242 auto leftX = nodeBounds.GetLeftTopXScreenPostion(); 243 auto topY = nodeBounds.GetLeftTopYScreenPostion(); 244 auto rightX = nodeBounds.GetRightBottomXScreenPostion(); 245 auto bottomY = nodeBounds.GetRightBottomYScreenPostion(); 246 Rect newBounds((leftX < windowBounds.left_) ? windowBounds.left_ : leftX, 247 (rightX > windowBounds.right_) ? windowBounds.right_ : rightX, 248 (topY < windowBounds.top_) ? windowBounds.top_ : topY, 249 (bottomY > windowBounds.bottom_) ? windowBounds.bottom_ : bottomY); 250 return newBounds; 251 } 252 InflateWindowInfo(AccessibilityWindowInfo & node,Window & info)253 static void InflateWindowInfo(AccessibilityWindowInfo& node, Window& info) 254 { 255 info.focused_ = node.IsFocused(); 256 info.actived_ = node.IsActive(); 257 info.decoratorEnabled_ = node.IsDecorEnable(); 258 // get bundle name by root node 259 AccessibilityElementInfo element; 260 LOG_D("Start Get Bundle Name by WindowId %{public}d", node.GetWindowId()); 261 if (AccessibilityUITestAbility::GetInstance()->GetRootByWindow(node, element) != RET_OK) { 262 LOG_E("Failed Get Bundle Name by WindowId %{public}d", node.GetWindowId()); 263 } else { 264 std::string app = element.GetBundleName(); 265 LOG_I("End Get Bundle Name by WindowId %{public}d, app is %{public}s", node.GetWindowId(), app.data()); 266 info.bundleName_ = app; 267 const auto foreAbility = AAFwk::AbilityManagerClient::GetInstance()->GetTopAbility(); 268 info.abilityName_ = (app == foreAbility.GetBundleName()) ? foreAbility.GetAbilityName() : ""; 269 info.pagePath_ = (app == foreAbility.GetBundleName()) ? element.GetPagePath() : ""; 270 } 271 info.mode_ = WindowMode::UNKNOWN; 272 const auto origMode = static_cast<OHOS::Rosen::WindowMode>(node.GetWindowMode()); 273 switch (origMode) { 274 case OHOS::Rosen::WindowMode::WINDOW_MODE_FULLSCREEN: 275 info.mode_ = WindowMode::FULLSCREEN; 276 break; 277 case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_PRIMARY: 278 info.mode_ = WindowMode::SPLIT_PRIMARY; 279 break; 280 case OHOS::Rosen::WindowMode::WINDOW_MODE_SPLIT_SECONDARY: 281 info.mode_ = WindowMode::SPLIT_SECONDARY; 282 break; 283 case OHOS::Rosen::WindowMode::WINDOW_MODE_FLOATING: 284 info.mode_ = WindowMode::FLOATING; 285 break; 286 case OHOS::Rosen::WindowMode::WINDOW_MODE_PIP: 287 info.mode_ = WindowMode::PIP; 288 break; 289 default: 290 info.mode_ = WindowMode::UNKNOWN; 291 break; 292 } 293 } 294 GetAamsWindowInfos(vector<AccessibilityWindowInfo> & windows)295 static bool GetAamsWindowInfos(vector<AccessibilityWindowInfo> &windows) 296 { 297 auto ability = AccessibilityUITestAbility::GetInstance(); 298 g_monitorInstance_->WaitScrollCompelete(); 299 if (ability->GetWindows(windows) != RET_OK) { 300 LOG_W("GetWindows from AccessibilityUITestAbility failed"); 301 return false; 302 } 303 sort(windows.begin(), windows.end(), [](auto &w1, auto &w2) -> bool { 304 return w1.GetWindowLayer() > w2.GetWindowLayer(); 305 }); 306 return true; 307 } 308 GetUiWindows(std::vector<Window> & out)309 void SysUiController::GetUiWindows(std::vector<Window> &out) 310 { 311 std::lock_guard<std::mutex> dumpLocker(dumpMtx); // disallow concurrent dumpUi 312 if (!connected_ && !ConnectToSysAbility()) { 313 LOG_W("Connect to AccessibilityUITestAbility failed"); 314 return; 315 } 316 vector<AccessibilityWindowInfo> windows; 317 LOG_I("Get Window root info"); 318 if (!GetAamsWindowInfos(windows)) { 319 return; 320 } 321 LOG_D("End Get Window root info"); 322 auto screenSize = GetDisplaySize(); 323 auto screenRect = Rect(0, screenSize.px_, 0, screenSize.py_); 324 std::vector<Rect> overplays; 325 // window wrapper 326 for (auto &win : windows) { 327 Rect winRectInScreen = GetVisibleRect(screenRect, win.GetRectInScreen()); 328 Rect visibleArea = winRectInScreen; 329 if (!RectAlgorithm::ComputeMaxVisibleRegion(winRectInScreen, overplays, visibleArea)) { 330 LOG_I("window is covered, windowId : %{public}d, layer is %{public}d", win.GetWindowId(), 331 win.GetWindowLayer()); 332 continue; 333 } 334 LOG_I("window is visible, windowId: %{public}d, active: %{public}d, focus: %{public}d, layer: %{public}d", 335 win.GetWindowId(), win.IsActive(), win.IsFocused(), win.GetWindowLayer()); 336 Window winWrapper{win.GetWindowId()}; 337 InflateWindowInfo(win, winWrapper); 338 winWrapper.bounds_ = winRectInScreen; 339 for (const auto &overWin : overplays) { 340 Rect intersectionRect{0, 0, 0, 0}; 341 if (RectAlgorithm::ComputeIntersection(winRectInScreen, overWin, intersectionRect)) { 342 winWrapper.invisibleBoundsVec_.emplace_back(overWin); 343 } 344 } 345 overplays.emplace_back(winRectInScreen); 346 out.emplace_back(std::move(winWrapper)); 347 } 348 } 349 GetWidgetsInWindow(const Window & winInfo,unique_ptr<ElementNodeIterator> & elementIterator)350 bool SysUiController::GetWidgetsInWindow(const Window &winInfo, unique_ptr<ElementNodeIterator> &elementIterator) 351 { 352 std::lock_guard<std::mutex> dumpLocker(dumpMtx); // disallow concurrent dumpUi 353 if (!connected_) { 354 LOG_W("Connect to AccessibilityUITestAbility failed"); 355 return false; 356 } 357 std::vector<AccessibilityElementInfo> elementInfos; 358 AccessibilityWindowInfo window; 359 LOG_D("Get Window by WindowId %{public}d", winInfo.id_); 360 if (AccessibilityUITestAbility::GetInstance()->GetWindow(winInfo.id_, window) != RET_OK) { 361 LOG_E("GetWindowInfo failed, windowId: %{public}d", winInfo.id_); 362 return false; 363 } 364 LOG_I("Start Get nodes from window by WindowId %{public}d", winInfo.id_); 365 if (AccessibilityUITestAbility::GetInstance()->GetRootByWindowBatch(window, elementInfos) != RET_OK) { 366 LOG_E("GetRootByWindowBatch failed, windowId: %{public}d", winInfo.id_); 367 return false; 368 } else { 369 LOG_I("End Get nodes from window by WindowId %{public}d, node size is %{public}zu, appId: %{public}s", 370 winInfo.id_, elementInfos.size(), winInfo.bundleName_.data()); 371 elementIterator = std::make_unique<ElementNodeIteratorImpl>(elementInfos); 372 } 373 return true; 374 } 375 InjectTouchEventSequence(const PointerMatrix & events) const376 void SysUiController::InjectTouchEventSequence(const PointerMatrix &events) const 377 { 378 for (uint32_t step = 0; step < events.GetSteps(); step++) { 379 auto pointerEvent = PointerEvent::Create(); 380 for (uint32_t finger = 0; finger < events.GetFingers(); finger++) { 381 pointerEvent->SetPointerId(finger); 382 PointerEvent::PointerItem pinterItem; 383 pinterItem.SetPointerId(finger); 384 pinterItem.SetDisplayX(events.At(finger, step).point_.px_); 385 pinterItem.SetDisplayY(events.At(finger, step).point_.py_); 386 switch (events.At(finger, step).stage_) { 387 case ActionStage::DOWN: 388 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_DOWN); 389 break; 390 case ActionStage::MOVE: 391 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_MOVE); 392 break; 393 case ActionStage::UP: 394 pointerEvent->SetPointerAction(PointerEvent::POINTER_ACTION_UP); 395 break; 396 default: 397 break; 398 } 399 pinterItem.SetPressed(events.At(finger, step).stage_ != ActionStage::UP); 400 pointerEvent->AddPointerItem(pinterItem); 401 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_TOUCHSCREEN); 402 DisplayManager &displayMgr = DisplayManager::GetInstance(); 403 pointerEvent->SetTargetDisplayId(displayMgr.GetDefaultDisplayId()); 404 InputManager::GetInstance()->SimulateInputEvent(pointerEvent); 405 if (events.At(finger, step).holdMs_ > 0) { 406 this_thread::sleep_for(chrono::milliseconds(events.At(finger, step).holdMs_)); 407 } 408 } 409 } 410 } 411 SetMousePointerItemAttr(const MouseEvent & event,PointerEvent::PointerItem & item)412 static void SetMousePointerItemAttr(const MouseEvent &event, PointerEvent::PointerItem &item) 413 { 414 item.SetPointerId(0); 415 item.SetToolType(PointerEvent::TOOL_TYPE_MOUSE); 416 item.SetDisplayX(event.point_.px_); 417 item.SetDisplayY(event.point_.py_); 418 item.SetPressed(false); 419 item.SetDownTime(0); 420 } 421 InjectMouseEvent(const MouseEvent & event) const422 void SysUiController::InjectMouseEvent(const MouseEvent &event) const 423 { 424 auto pointerEvent = PointerEvent::Create(); 425 PointerEvent::PointerItem item; 426 pointerEvent->SetSourceType(PointerEvent::SOURCE_TYPE_MOUSE); 427 pointerEvent->SetPointerId(0); 428 pointerEvent->SetButtonId(event.button_); 429 SetMousePointerItemAttr(event, item); 430 constexpr double axialValue = 15; 431 static bool flag = true; 432 auto injectAxialValue = axialValue; 433 switch (event.stage_) { 434 case ActionStage::DOWN: 435 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN); 436 pointerEvent->SetButtonId(event.button_); 437 pointerEvent->SetButtonPressed(event.button_); 438 item.SetPressed(true); 439 break; 440 case ActionStage::MOVE: 441 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_MOVE); 442 break; 443 case ActionStage::UP: 444 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_BUTTON_UP); 445 pointerEvent->SetButtonId(event.button_); 446 pointerEvent->SetButtonPressed(event.button_); 447 break; 448 case ActionStage::AXIS_UP: 449 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_BEGIN); 450 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, -axialValue); 451 flag = false; 452 break; 453 case ActionStage::AXIS_DOWN: 454 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_BEGIN); 455 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, axialValue); 456 flag = true; 457 break; 458 case ActionStage::AXIS_STOP: 459 pointerEvent->SetPointerAction(OHOS::MMI::PointerEvent::POINTER_ACTION_AXIS_END); 460 injectAxialValue = flag ? axialValue : -axialValue; 461 pointerEvent->SetAxisValue(OHOS::MMI::PointerEvent::AXIS_TYPE_SCROLL_VERTICAL, injectAxialValue); 462 break; 463 default: 464 break; 465 } 466 pointerEvent->AddPointerItem(item); 467 InputManager::GetInstance()->SimulateInputEvent(pointerEvent); 468 this_thread::sleep_for(chrono::milliseconds(event.holdMs_)); 469 } 470 InjectMouseEventSequence(const vector<MouseEvent> & events) const471 void SysUiController::InjectMouseEventSequence(const vector<MouseEvent> &events) const 472 { 473 for (auto &event : events) { 474 auto keyEvents = event.keyEvents_; 475 if (!keyEvents.empty() && keyEvents.front().stage_ == ActionStage::DOWN) { 476 InjectKeyEventSequence(keyEvents); 477 InjectMouseEvent(event); 478 } else { 479 InjectMouseEvent(event); 480 InjectKeyEventSequence(keyEvents); 481 } 482 } 483 } 484 InjectKeyEventSequence(const vector<KeyEvent> & events) const485 void SysUiController::InjectKeyEventSequence(const vector<KeyEvent> &events) const 486 { 487 static vector<int32_t> downKeys; 488 for (auto &event : events) { 489 if (event.code_ == KEYCODE_NONE) { 490 continue; 491 } 492 if (event.stage_ == ActionStage::UP) { 493 auto iter = std::find(downKeys.begin(), downKeys.end(), event.code_); 494 if (iter == downKeys.end()) { 495 LOG_W("Cannot release a not-pressed key: %{public}d", event.code_); 496 continue; 497 } 498 downKeys.erase(iter); 499 auto keyEvent = OHOS::MMI::KeyEvent::Create(); 500 keyEvent->SetKeyCode(event.code_); 501 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_UP); 502 OHOS::MMI::KeyEvent::KeyItem keyItem; 503 keyItem.SetKeyCode(event.code_); 504 keyItem.SetPressed(true); 505 keyEvent->AddKeyItem(keyItem); 506 InputManager::GetInstance()->SimulateInputEvent(keyEvent); 507 } else { 508 downKeys.push_back(event.code_); 509 auto keyEvent = OHOS::MMI::KeyEvent::Create(); 510 for (auto downKey : downKeys) { 511 keyEvent->SetKeyCode(downKey); 512 keyEvent->SetKeyAction(OHOS::MMI::KeyEvent::KEY_ACTION_DOWN); 513 OHOS::MMI::KeyEvent::KeyItem keyItem; 514 keyItem.SetKeyCode(downKey); 515 keyItem.SetPressed(true); 516 keyEvent->AddKeyItem(keyItem); 517 } 518 InputManager::GetInstance()->SimulateInputEvent(keyEvent); 519 if (event.holdMs_ > 0) { 520 this_thread::sleep_for(chrono::milliseconds(event.holdMs_)); 521 } 522 } 523 } 524 // check not released keys 525 for (auto downKey : downKeys) { 526 LOG_W("Key event sequence injections done with not-released key: %{public}d", downKey); 527 } 528 } 529 PutTextToClipboard(string_view text) const530 void SysUiController::PutTextToClipboard(string_view text) const 531 { 532 auto pasteBoardMgr = MiscServices::PasteboardClient::GetInstance(); 533 pasteBoardMgr->Clear(); 534 auto pasteData = pasteBoardMgr->CreatePlainTextData(string(text)); 535 pasteBoardMgr->SetPasteData(*pasteData); 536 } 537 IsWorkable() const538 bool SysUiController::IsWorkable() const 539 { 540 return connected_; 541 } 542 GetCharKeyCode(char ch,int32_t & code,int32_t & ctrlCode) const543 bool SysUiController::GetCharKeyCode(char ch, int32_t &code, int32_t &ctrlCode) const 544 { 545 ctrlCode = KEYCODE_NONE; 546 if (ch >= 'a' && ch <= 'z') { 547 code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'a'); 548 } else if (ch >= 'A' && ch <= 'Z') { 549 ctrlCode = OHOS::MMI::KeyEvent::KEYCODE_SHIFT_LEFT; 550 code = OHOS::MMI::KeyEvent::KEYCODE_A + static_cast<int32_t>(ch - 'A'); 551 } else if (ch >= '0' && ch <= '9') { 552 code = OHOS::MMI::KeyEvent::KEYCODE_0 + static_cast<int32_t>(ch - '0'); 553 } else { 554 return false; 555 } 556 return true; 557 } 558 TakeScreenCap(int32_t fd,std::stringstream & errReceiver,Rect rect) const559 bool SysUiController::TakeScreenCap(int32_t fd, std::stringstream &errReceiver, Rect rect) const 560 { 561 DisplayManager &displayMgr = DisplayManager::GetInstance(); 562 // get PixelMap from DisplayManager API 563 shared_ptr<PixelMap> pixelMap; 564 if (rect.GetWidth() == 0) { 565 pixelMap = displayMgr.GetScreenshot(displayMgr.GetDefaultDisplayId()); 566 } else { 567 Media::Rect region = {.left = rect.left_, .top = rect.top_, 568 .width = rect.right_ - rect.left_, .height = rect.bottom_ - rect.top_}; 569 Media::Size size = {.width = rect.right_ - rect.left_, .height = rect.bottom_ - rect.top_}; 570 pixelMap = displayMgr.GetScreenshot(displayMgr.GetDefaultDisplayId(), region, size, 0); 571 } 572 if (pixelMap == nullptr) { 573 errReceiver << "Failed to get display pixelMap"; 574 return false; 575 } 576 FILE *fp = fdopen(fd, "wb"); 577 if (fp == nullptr) { 578 perror("File opening failed"); 579 errReceiver << "File opening failed"; 580 return false; 581 } 582 png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 583 if (pngStruct == nullptr) { 584 fclose(fp); 585 return false; 586 } 587 png_infop pngInfo = png_create_info_struct(pngStruct); 588 if (pngInfo == nullptr) { 589 fclose(fp); 590 png_destroy_write_struct(&pngStruct, nullptr); 591 return false; 592 } 593 png_init_io(pngStruct, fp); 594 auto width = static_cast<uint32_t>(pixelMap->GetWidth()); 595 auto height = static_cast<uint32_t>(pixelMap->GetHeight()); 596 auto data = pixelMap->GetPixels(); 597 auto stride = static_cast<uint32_t>(pixelMap->GetRowBytes()); 598 // set png header 599 static constexpr int bitmapDepth = 8; 600 png_set_IHDR(pngStruct, pngInfo, width, height, bitmapDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, 601 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); 602 png_set_packing(pngStruct); // set packing info 603 png_write_info(pngStruct, pngInfo); // write to header 604 for (uint32_t column = 0; column < height; column++) { 605 png_write_row(pngStruct, data + (column * stride)); 606 } 607 // free/close 608 png_write_end(pngStruct, pngInfo); 609 png_destroy_write_struct(&pngStruct, &pngInfo); 610 (void)fclose(fp); 611 return true; 612 } 613 ConnectToSysAbility()614 bool SysUiController::ConnectToSysAbility() 615 { 616 if (connected_) { 617 return true; 618 } 619 mutex mtx; 620 unique_lock<mutex> uLock(mtx); 621 std::shared_ptr<condition_variable> condition = make_shared<condition_variable>(); 622 auto onConnectCallback = [condition]() { 623 LOG_I("Success connect to AccessibilityUITestAbility"); 624 condition->notify_all(); 625 }; 626 auto onDisConnectCallback = [this]() { this->connected_ = false; }; 627 if (g_monitorInstance_ == nullptr) { 628 g_monitorInstance_ = make_shared<UiEventMonitor>(); 629 } 630 g_monitorInstance_->SetOnAbilityConnectCallback(onConnectCallback); 631 g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback); 632 auto ability = AccessibilityUITestAbility::GetInstance(); 633 if (ability->RegisterAbilityListener(g_monitorInstance_) != RET_OK) { 634 LOG_E("Failed to register UiEventMonitor"); 635 return false; 636 } 637 auto ret = ability->Connect(); 638 switch (ret) { 639 case (RET_ERR_INVALID_PARAM): 640 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_INVALID_PARAM"); 641 return false; 642 case (RET_ERR_NULLPTR): 643 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_NULLPTR"); 644 return false; 645 case (RET_ERR_CONNECTION_EXIST): 646 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_CONNECTION_EXIST"); 647 return false; 648 case (RET_ERR_IPC_FAILED): 649 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_IPC_FAILED"); 650 return false; 651 case (RET_ERR_SAMGR): 652 LOG_E("Failed to connect to AccessibilityUITestAbility, RET_ERR_SAMGR"); 653 return false; 654 default: 655 break; 656 } 657 const auto timeout = chrono::milliseconds(1000); 658 if (condition->wait_for(uLock, timeout) == cv_status::timeout) { 659 LOG_E("Wait connection to AccessibilityUITestAbility timed out"); 660 return false; 661 } 662 connected_ = true; 663 return true; 664 } 665 RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) const666 void SysUiController::RegisterUiEventListener(std::shared_ptr<UiEventListener> listener) const 667 { 668 g_monitorInstance_->RegisterUiEventListener(listener); 669 } 670 WaitForUiSteady(uint32_t idleThresholdMs,uint32_t timeoutMs) const671 bool SysUiController::WaitForUiSteady(uint32_t idleThresholdMs, uint32_t timeoutMs) const 672 { 673 return g_monitorInstance_->WaitEventIdle(idleThresholdMs, timeoutMs); 674 } 675 DisConnectFromSysAbility()676 void SysUiController::DisConnectFromSysAbility() 677 { 678 if (!connected_ || g_monitorInstance_ == nullptr) { 679 return; 680 } 681 connected_ = false; 682 mutex mtx; 683 unique_lock<mutex> uLock(mtx); 684 condition_variable condition; 685 auto onDisConnectCallback = [&condition]() { 686 LOG_I("Success disconnect from AccessibilityUITestAbility"); 687 condition.notify_all(); 688 }; 689 g_monitorInstance_->SetOnAbilityDisConnectCallback(onDisConnectCallback); 690 auto ability = AccessibilityUITestAbility::GetInstance(); 691 LOG_I("Start disconnect from AccessibilityUITestAbility"); 692 if (ability->Disconnect() != RET_OK) { 693 LOG_E("Failed to disconnect from AccessibilityUITestAbility"); 694 return; 695 } 696 const auto timeout = chrono::milliseconds(200); 697 if (condition.wait_for(uLock, timeout) == cv_status::timeout) { 698 LOG_E("Wait disconnection from AccessibilityUITestAbility timed out"); 699 return; 700 } 701 } 702 SetDisplayRotation(DisplayRotation rotation) const703 void SysUiController::SetDisplayRotation(DisplayRotation rotation) const 704 { 705 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 706 if (display == nullptr) { 707 LOG_E("DisplayManager init fail"); 708 return; 709 } 710 auto screenId = display->GetScreenId(); 711 ScreenManager &screenMgr = ScreenManager::GetInstance(); 712 DCHECK(screenMgr); 713 bool isLocked = false; 714 screenMgr.IsScreenRotationLocked(isLocked); 715 if (isLocked) { 716 screenMgr.SetScreenRotationLocked(false); 717 } 718 auto screen = screenMgr.GetScreenById(screenId); 719 if (screen == nullptr) { 720 LOG_E("ScreenManager init fail"); 721 return; 722 } 723 switch (rotation) { 724 case ROTATION_0 : 725 screen->SetOrientation(Orientation::VERTICAL); 726 break; 727 case ROTATION_90 : 728 screen->SetOrientation(Orientation::HORIZONTAL); 729 break; 730 case ROTATION_180 : 731 screen->SetOrientation(Orientation::REVERSE_VERTICAL); 732 break; 733 case ROTATION_270 : 734 screen->SetOrientation(Orientation::REVERSE_HORIZONTAL); 735 break; 736 default : 737 break; 738 } 739 } 740 GetDisplayRotation() const741 DisplayRotation SysUiController::GetDisplayRotation() const 742 { 743 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 744 if (display == nullptr) { 745 LOG_E("DisplayManager init fail"); 746 return DisplayRotation::ROTATION_0; 747 } 748 auto rotation = (DisplayRotation)display->GetRotation(); 749 return rotation; 750 } 751 SetDisplayRotationEnabled(bool enabled) const752 void SysUiController::SetDisplayRotationEnabled(bool enabled) const 753 { 754 ScreenManager &screenMgr = ScreenManager::GetInstance(); 755 DCHECK(screenMgr); 756 screenMgr.SetScreenRotationLocked(!enabled); 757 } 758 GetDisplaySize() const759 Point SysUiController::GetDisplaySize() const 760 { 761 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 762 if (display == nullptr) { 763 LOG_E("DisplayManager init fail"); 764 return {0, 0}; 765 } 766 auto width = display->GetWidth(); 767 auto height = display->GetHeight(); 768 Point result(width, height); 769 return result; 770 } 771 GetDisplayDensity() const772 Point SysUiController::GetDisplayDensity() const 773 { 774 auto display = DisplayManager::GetInstance().GetDefaultDisplay(); 775 if (display == nullptr) { 776 LOG_E("DisplayManager init fail"); 777 return {0, 0}; 778 } 779 auto rate = display->GetVirtualPixelRatio(); 780 Point displaySize = GetDisplaySize(); 781 Point result(displaySize.px_ * rate, displaySize.py_ * rate); 782 return result; 783 } 784 IsScreenOn() const785 bool SysUiController::IsScreenOn() const 786 { 787 DisplayManager &displayMgr = DisplayManager::GetInstance(); 788 DCHECK(displayMgr); 789 auto displayId = displayMgr.GetDefaultDisplayId(); 790 auto state = displayMgr.GetDisplayState(displayId); 791 return (state != DisplayState::OFF); 792 } 793 794 class OnSaLoadCallback : public SystemAbilityLoadCallbackStub { 795 public: OnSaLoadCallback(mutex & mutex)796 explicit OnSaLoadCallback(mutex &mutex): mutex_(mutex) {}; ~OnSaLoadCallback()797 ~OnSaLoadCallback() {}; OnLoadSystemAbilitySuccess(int32_t systemAbilityId,const sptr<IRemoteObject> & remoteObject)798 void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr<IRemoteObject>& remoteObject) override 799 { 800 if (systemAbilityId == OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID) { 801 remoteObject_ = remoteObject; 802 mutex_.unlock(); 803 } 804 } OnLoadSystemAbilityFail(int32_t systemAbilityId)805 void OnLoadSystemAbilityFail(int32_t systemAbilityId) override 806 { 807 if (systemAbilityId == OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID) { 808 mutex_.unlock(); 809 } 810 } 811 GetSaObject()812 sptr<IRemoteObject> GetSaObject() 813 { 814 return remoteObject_; 815 } 816 817 private: 818 mutex &mutex_; 819 sptr<IRemoteObject> remoteObject_ = nullptr; 820 }; 821 GetHidumperInfo(std::string windowId,char ** buf,size_t & len)822 void SysUiController::GetHidumperInfo(std::string windowId, char **buf, size_t &len) 823 { 824 #ifdef HIDUMPER_ENABLED 825 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 826 if (sam == nullptr) { 827 LOG_E("Get samgr failed"); 828 return; 829 } 830 auto remoteObject = sam->CheckSystemAbility(OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID); 831 if (remoteObject == nullptr) { 832 mutex lock; 833 lock.lock(); 834 sptr<OnSaLoadCallback> loadCallback = new OnSaLoadCallback(lock); 835 int32_t result = sam->LoadSystemAbility(OHOS::DFX_HI_DUMPER_SERVICE_ABILITY_ID, loadCallback); 836 if (result != ERR_OK) { 837 LOG_E("Schedule LoadSystemAbility failed"); 838 return; 839 } 840 LOG_E("Schedule LoadSystemAbility succeed"); 841 lock.lock(); 842 remoteObject = loadCallback->GetSaObject(); 843 LOG_E("LoadSystemAbility callbacked, result = %{public}s", remoteObject == nullptr ? "FAIL" : "SUCCESS"); 844 } 845 if (remoteObject == nullptr) { 846 LOG_E("remoteObject is null"); 847 return; 848 } 849 // run dump command 850 sptr<IDumpBroker> client = iface_cast<IDumpBroker>(remoteObject); 851 auto fd = memfd_create("dummy_file", 2); 852 ftruncate(fd, 0); 853 vector<u16string> args; 854 args.emplace_back(u"hidumper"); 855 args.emplace_back(u"-s"); 856 args.emplace_back(u"WindowManagerService"); 857 args.emplace_back(u"-a"); 858 auto winIdInUtf16 = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t > {}.from_bytes(windowId); 859 auto arg = u16string(u"-w ").append(winIdInUtf16).append(u" -element -c -lastpage"); 860 args.emplace_back(move(arg)); 861 client->Request(args, fd); 862 auto size = lseek(fd, 0, SEEK_END); 863 char *tempBuf = new char[size + 1]; 864 lseek(fd, 0, SEEK_SET); 865 read(fd, tempBuf, size); 866 *buf = tempBuf; 867 len = size; 868 close(fd); 869 #else 870 *buf = nullptr; 871 len = 0; 872 #endif 873 } 874 } // namespace OHOS::uitest