1e0dac50fSopenharmony_ci/* 2e0dac50fSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 3e0dac50fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4e0dac50fSopenharmony_ci * you may not use this file except in compliance with the License. 5e0dac50fSopenharmony_ci * You may obtain a copy of the License at 6e0dac50fSopenharmony_ci * 7e0dac50fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8e0dac50fSopenharmony_ci * 9e0dac50fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10e0dac50fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11e0dac50fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12e0dac50fSopenharmony_ci * See the License for the specific language governing permissions and 13e0dac50fSopenharmony_ci * limitations under the License. 14e0dac50fSopenharmony_ci */ 15e0dac50fSopenharmony_ci 16e0dac50fSopenharmony_ci#include "window_dumper.h" 17e0dac50fSopenharmony_ci 18e0dac50fSopenharmony_ci#include <cinttypes> 19e0dac50fSopenharmony_ci#include <csignal> 20e0dac50fSopenharmony_ci#include <iomanip> 21e0dac50fSopenharmony_ci#include <map> 22e0dac50fSopenharmony_ci#include <sstream> 23e0dac50fSopenharmony_ci 24e0dac50fSopenharmony_ci#include "display_manager_service_inner.h" 25e0dac50fSopenharmony_ci#include "string_ex.h" 26e0dac50fSopenharmony_ci#include "unique_fd.h" 27e0dac50fSopenharmony_ci#include "display_group_info.h" 28e0dac50fSopenharmony_ci#include "window_manager_hilog.h" 29e0dac50fSopenharmony_ci#include "window_manager_service.h" 30e0dac50fSopenharmony_ci#include "wm_common.h" 31e0dac50fSopenharmony_ci 32e0dac50fSopenharmony_cinamespace OHOS { 33e0dac50fSopenharmony_cinamespace Rosen { 34e0dac50fSopenharmony_cinamespace { 35e0dac50fSopenharmony_ciconstexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Dumper"}; 36e0dac50fSopenharmony_ci 37e0dac50fSopenharmony_ciconstexpr int WINDOW_NAME_MAX_LENGTH = 20; 38e0dac50fSopenharmony_ciconst std::string ARG_DUMP_HELP = "-h"; 39e0dac50fSopenharmony_ciconst std::string ARG_DUMP_ALL = "-a"; 40e0dac50fSopenharmony_ciconst std::string ARG_DUMP_WINDOW = "-w"; 41e0dac50fSopenharmony_ci} 42e0dac50fSopenharmony_ci 43e0dac50fSopenharmony_ciWMError WindowDumper::Dump(int fd, const std::vector<std::u16string>& args) 44e0dac50fSopenharmony_ci{ 45e0dac50fSopenharmony_ci WLOGI("Dump begin fd: %{public}d", fd); 46e0dac50fSopenharmony_ci if (fd < 0) { 47e0dac50fSopenharmony_ci return WMError::WM_ERROR_INVALID_PARAM; 48e0dac50fSopenharmony_ci } 49e0dac50fSopenharmony_ci (void) signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE crash 50e0dac50fSopenharmony_ci UniqueFd ufd = UniqueFd(fd); // auto close 51e0dac50fSopenharmony_ci fd = ufd.Get(); 52e0dac50fSopenharmony_ci std::vector<std::string> params; 53e0dac50fSopenharmony_ci for (auto& arg : args) { 54e0dac50fSopenharmony_ci params.emplace_back(Str16ToStr8(arg)); 55e0dac50fSopenharmony_ci } 56e0dac50fSopenharmony_ci 57e0dac50fSopenharmony_ci std::string dumpInfo; 58e0dac50fSopenharmony_ci if (params.empty()) { 59e0dac50fSopenharmony_ci ShowHelpInfo(dumpInfo); 60e0dac50fSopenharmony_ci } else if (params.size() == 1 && params[0] == ARG_DUMP_HELP) { // 1: params num 61e0dac50fSopenharmony_ci ShowHelpInfo(dumpInfo); 62e0dac50fSopenharmony_ci } else { 63e0dac50fSopenharmony_ci WMError errCode = DumpWindowInfo(params, dumpInfo); 64e0dac50fSopenharmony_ci if (errCode != WMError::WM_OK) { 65e0dac50fSopenharmony_ci ShowIllegalArgsInfo(dumpInfo, errCode); 66e0dac50fSopenharmony_ci } 67e0dac50fSopenharmony_ci } 68e0dac50fSopenharmony_ci int ret = dprintf(fd, "%s\n", dumpInfo.c_str()); 69e0dac50fSopenharmony_ci if (ret < 0) { 70e0dac50fSopenharmony_ci WLOGFE("dprintf error"); 71e0dac50fSopenharmony_ci return WMError::WM_ERROR_INVALID_OPERATION; 72e0dac50fSopenharmony_ci } 73e0dac50fSopenharmony_ci WLOGI("Dump end"); 74e0dac50fSopenharmony_ci return WMError::WM_OK; 75e0dac50fSopenharmony_ci} 76e0dac50fSopenharmony_ci 77e0dac50fSopenharmony_ciWMError WindowDumper::DumpScreenGroupWindowInfo(ScreenId screenGroupId, 78e0dac50fSopenharmony_ci const sptr<WindowNodeContainer>& windowNodeContainer, std::string& dumpInfo) 79e0dac50fSopenharmony_ci{ 80e0dac50fSopenharmony_ci if (windowNodeContainer == nullptr) { 81e0dac50fSopenharmony_ci WLOGFE("windowNodeContainer is null"); 82e0dac50fSopenharmony_ci return WMError::WM_ERROR_NULLPTR; 83e0dac50fSopenharmony_ci } 84e0dac50fSopenharmony_ci std::ostringstream oss; 85e0dac50fSopenharmony_ci oss << "-------------------------------------ScreenGroup " << screenGroupId 86e0dac50fSopenharmony_ci << "-------------------------------------" 87e0dac50fSopenharmony_ci << std::endl; 88e0dac50fSopenharmony_ci oss << "WindowName DisplayId Pid WinId Type Mode Flag ZOrd Orientation [ x y w h ]" 89e0dac50fSopenharmony_ci << std::endl; 90e0dac50fSopenharmony_ci std::vector<sptr<WindowNode>> windowNodes; 91e0dac50fSopenharmony_ci windowNodeContainer->TraverseContainer(windowNodes); 92e0dac50fSopenharmony_ci int zOrder = static_cast<int32_t>(windowNodes.size()); 93e0dac50fSopenharmony_ci windowRoot_->GetBackgroundNodesByScreenId(screenGroupId, windowNodes); 94e0dac50fSopenharmony_ci for (auto& windowNode : windowNodes) { 95e0dac50fSopenharmony_ci if (zOrder < 0) { 96e0dac50fSopenharmony_ci zOrder = 0; 97e0dac50fSopenharmony_ci } else if (zOrder == 0) { 98e0dac50fSopenharmony_ci oss << "---------------------------------------------------------------------------------------" 99e0dac50fSopenharmony_ci << std::endl; 100e0dac50fSopenharmony_ci } 101e0dac50fSopenharmony_ci if (windowNode == nullptr) { 102e0dac50fSopenharmony_ci --zOrder; 103e0dac50fSopenharmony_ci break; 104e0dac50fSopenharmony_ci } 105e0dac50fSopenharmony_ci --zOrder; 106e0dac50fSopenharmony_ci AppendWindowNodeInfo(windowNode, zOrder, oss); 107e0dac50fSopenharmony_ci } 108e0dac50fSopenharmony_ci oss << "Focus window: " << windowNodeContainer->GetFocusWindow() << std::endl; 109e0dac50fSopenharmony_ci oss << "total window num: " << windowRoot_->GetTotalWindowNum()<< std::endl; 110e0dac50fSopenharmony_ci dumpInfo.append(oss.str()); 111e0dac50fSopenharmony_ci return WMError::WM_OK; 112e0dac50fSopenharmony_ci} 113e0dac50fSopenharmony_ci 114e0dac50fSopenharmony_civoid WindowDumper::AppendWindowNodeInfo(const sptr<WindowNode>& windowNode, int zOrder, std::ostringstream& oss) 115e0dac50fSopenharmony_ci{ 116e0dac50fSopenharmony_ci Rect rect = windowNode->GetWindowRect(); 117e0dac50fSopenharmony_ci const std::string& windowName = windowNode->GetWindowName().size() <= WINDOW_NAME_MAX_LENGTH ? 118e0dac50fSopenharmony_ci windowNode->GetWindowName() : windowNode->GetWindowName().substr(0, WINDOW_NAME_MAX_LENGTH); 119e0dac50fSopenharmony_ci // std::setw is used to set the output width and different width values are set to keep the format aligned. 120e0dac50fSopenharmony_ci oss << std::left << std::setw(21) << windowName // 21 is width 121e0dac50fSopenharmony_ci << std::left << std::setw(10) << windowNode->GetDisplayId() // 10 is width 122e0dac50fSopenharmony_ci << std::left << std::setw(8) << windowNode->GetCallingPid() // 8 is width 123e0dac50fSopenharmony_ci << std::left << std::setw(6) << windowNode->GetWindowId() // 6 is width 124e0dac50fSopenharmony_ci << std::left << std::setw(5) << static_cast<uint32_t>(windowNode->GetWindowType()) // 5 is width 125e0dac50fSopenharmony_ci << std::left << std::setw(5) << static_cast<uint32_t>(windowNode->GetWindowMode()) // 5 is width 126e0dac50fSopenharmony_ci << std::left << std::setw(5) << windowNode->GetWindowFlags() // 5 is width 127e0dac50fSopenharmony_ci << std::left << std::setw(5) << zOrder // 5 is width 128e0dac50fSopenharmony_ci << std::left << std::setw(12) << static_cast<uint32_t>(windowNode->GetRequestedOrientation()) // 12 is width 129e0dac50fSopenharmony_ci << "[ " 130e0dac50fSopenharmony_ci << std::left << std::setw(5) << rect.posX_ // 5 is width 131e0dac50fSopenharmony_ci << std::left << std::setw(5) << rect.posY_ // 5 is width 132e0dac50fSopenharmony_ci << std::left << std::setw(5) << rect.width_ // 5 is width 133e0dac50fSopenharmony_ci << std::left << std::setw(5) << rect.height_ // 5 is width 134e0dac50fSopenharmony_ci << "]" 135e0dac50fSopenharmony_ci << std::endl; 136e0dac50fSopenharmony_ci} 137e0dac50fSopenharmony_ci 138e0dac50fSopenharmony_ciWMError WindowDumper::DumpAllWindowInfo(std::string& dumpInfo) 139e0dac50fSopenharmony_ci{ 140e0dac50fSopenharmony_ci std::map<ScreenId, sptr<WindowNodeContainer>> windowNodeContainers; 141e0dac50fSopenharmony_ci std::vector<DisplayId> displayIds = DisplayGroupInfo::GetInstance().GetAllDisplayIds(); 142e0dac50fSopenharmony_ci for (DisplayId displayId : displayIds) { 143e0dac50fSopenharmony_ci auto windowNodeContainer = windowRoot_->GetOrCreateWindowNodeContainer(displayId); 144e0dac50fSopenharmony_ci if (!windowNodeContainer) { 145e0dac50fSopenharmony_ci return WMError::WM_ERROR_NULLPTR; 146e0dac50fSopenharmony_ci } 147e0dac50fSopenharmony_ci ScreenId screenGroupId = DisplayManagerServiceInner::GetInstance().GetScreenGroupIdByDisplayId(displayId); 148e0dac50fSopenharmony_ci if (windowNodeContainers.count(screenGroupId) == 0) { 149e0dac50fSopenharmony_ci windowNodeContainers.insert(std::make_pair(screenGroupId, windowNodeContainer)); 150e0dac50fSopenharmony_ci } 151e0dac50fSopenharmony_ci } 152e0dac50fSopenharmony_ci for (auto it = windowNodeContainers.begin(); it != windowNodeContainers.end(); it++) { 153e0dac50fSopenharmony_ci WMError ret = DumpScreenGroupWindowInfo(it->first, it->second, dumpInfo); 154e0dac50fSopenharmony_ci if (ret != WMError::WM_OK) { 155e0dac50fSopenharmony_ci return ret; 156e0dac50fSopenharmony_ci } 157e0dac50fSopenharmony_ci } 158e0dac50fSopenharmony_ci return WMError::WM_OK; 159e0dac50fSopenharmony_ci} 160e0dac50fSopenharmony_ci 161e0dac50fSopenharmony_cibool WindowDumper::IsValidDigitString(const std::string& windowIdStr) 162e0dac50fSopenharmony_ci{ 163e0dac50fSopenharmony_ci if (windowIdStr.empty()) { 164e0dac50fSopenharmony_ci return false; 165e0dac50fSopenharmony_ci } 166e0dac50fSopenharmony_ci for (char ch : windowIdStr) { 167e0dac50fSopenharmony_ci if ((ch >= '0' && ch <= '9')) { 168e0dac50fSopenharmony_ci continue; 169e0dac50fSopenharmony_ci } 170e0dac50fSopenharmony_ci WLOGFE("invalid window id"); 171e0dac50fSopenharmony_ci return false; 172e0dac50fSopenharmony_ci } 173e0dac50fSopenharmony_ci return true; 174e0dac50fSopenharmony_ci} 175e0dac50fSopenharmony_ci 176e0dac50fSopenharmony_ciWMError WindowDumper::DumpSpecifiedWindowInfo(uint32_t windowId, const std::vector<std::string>& params, 177e0dac50fSopenharmony_ci std::string& dumpInfo) 178e0dac50fSopenharmony_ci{ 179e0dac50fSopenharmony_ci auto node = windowRoot_->GetWindowNode(windowId); 180e0dac50fSopenharmony_ci if (node == nullptr) { 181e0dac50fSopenharmony_ci WLOGFE("invalid window"); 182e0dac50fSopenharmony_ci return WMError::WM_ERROR_NULLPTR; 183e0dac50fSopenharmony_ci } 184e0dac50fSopenharmony_ci std::ostringstream oss; 185e0dac50fSopenharmony_ci AppendSpecifiedWindowNodeInfo(node, oss); 186e0dac50fSopenharmony_ci dumpInfo.append(oss.str()); 187e0dac50fSopenharmony_ci if (node->GetWindowToken() != nullptr) { 188e0dac50fSopenharmony_ci std::vector<std::string> resetParams; 189e0dac50fSopenharmony_ci resetParams.assign(params.begin() + 2, params.end()); // 2: params num 190e0dac50fSopenharmony_ci if (resetParams.empty()) { 191e0dac50fSopenharmony_ci WLOGI("do not dump ui info"); 192e0dac50fSopenharmony_ci return WMError::WM_OK; 193e0dac50fSopenharmony_ci } 194e0dac50fSopenharmony_ci dumpInfoFuture_.ResetLock({}); 195e0dac50fSopenharmony_ci node->GetWindowToken()->DumpInfo(resetParams); 196e0dac50fSopenharmony_ci auto infos = dumpInfoFuture_.GetResult(2000); // 2000: wait for 2000ms 197e0dac50fSopenharmony_ci for (auto& info: infos) { 198e0dac50fSopenharmony_ci dumpInfo.append(info).append("\n"); 199e0dac50fSopenharmony_ci } 200e0dac50fSopenharmony_ci } 201e0dac50fSopenharmony_ci return WMError::WM_OK; 202e0dac50fSopenharmony_ci} 203e0dac50fSopenharmony_ci 204e0dac50fSopenharmony_civoid WindowDumper::AppendSpecifiedWindowNodeInfo(const sptr<WindowNode>& node, std::ostringstream& oss) 205e0dac50fSopenharmony_ci{ 206e0dac50fSopenharmony_ci Rect rect = node->GetWindowRect(); 207e0dac50fSopenharmony_ci std::string isShown_ = node->startingWindowShown_ ? "true" : "false"; 208e0dac50fSopenharmony_ci std::string visibilityState = std::to_string(node->GetVisibilityState()); 209e0dac50fSopenharmony_ci std::string Focusable = node->GetWindowProperty()->GetFocusable() ? "true" : "false"; 210e0dac50fSopenharmony_ci std::string DecoStatus = node->GetWindowProperty()->GetDecoStatus() ? "true" : "false"; 211e0dac50fSopenharmony_ci bool PrivacyMode = node->GetWindowProperty()->GetSystemPrivacyMode() || 212e0dac50fSopenharmony_ci node->GetWindowProperty()->GetPrivacyMode(); 213e0dac50fSopenharmony_ci bool isSnapshotSkip = node->GetWindowProperty()->GetSnapshotSkip(); 214e0dac50fSopenharmony_ci std::string isPrivacyMode = PrivacyMode ? "true" : "false"; 215e0dac50fSopenharmony_ci oss << "WindowName: " << node->GetWindowName() << std::endl; 216e0dac50fSopenharmony_ci oss << "DisplayId: " << node->GetDisplayId() << std::endl; 217e0dac50fSopenharmony_ci oss << "WinId: " << node->GetWindowId() << std::endl; 218e0dac50fSopenharmony_ci oss << "Pid: " << node->GetCallingPid() << std::endl; 219e0dac50fSopenharmony_ci oss << "Type: " << static_cast<uint32_t>(node->GetWindowType()) << std::endl; 220e0dac50fSopenharmony_ci oss << "Mode: " << static_cast<uint32_t>(node->GetWindowMode()) << std::endl; 221e0dac50fSopenharmony_ci oss << "Flag: " << node->GetWindowFlags() << std::endl; 222e0dac50fSopenharmony_ci oss << "Orientation: " << static_cast<uint32_t>(node->GetRequestedOrientation()) << std::endl; 223e0dac50fSopenharmony_ci oss << "IsStartingWindow: " << isShown_ << std::endl; 224e0dac50fSopenharmony_ci oss << "FirstFrameCallbackCalled: " << node->firstFrameAvailable_ << std::endl; 225e0dac50fSopenharmony_ci oss << "VisibilityState: " << visibilityState << std::endl; 226e0dac50fSopenharmony_ci oss << "Focusable: " << Focusable << std::endl; 227e0dac50fSopenharmony_ci oss << "DecoStatus: " << DecoStatus << std::endl; 228e0dac50fSopenharmony_ci oss << "IsPrivacyMode: " << isPrivacyMode << std::endl; 229e0dac50fSopenharmony_ci oss << "isSnapshotSkip: " << isSnapshotSkip << std::endl; 230e0dac50fSopenharmony_ci oss << "WindowRect: " << "[ " 231e0dac50fSopenharmony_ci << rect.posX_ << ", " << rect.posY_ << ", " << rect.width_ << ", " << rect.height_ 232e0dac50fSopenharmony_ci << " ]" << std::endl; 233e0dac50fSopenharmony_ci oss << "TouchHotAreas: "; 234e0dac50fSopenharmony_ci std::vector<Rect> touchHotAreas; 235e0dac50fSopenharmony_ci node->GetTouchHotAreas(touchHotAreas); 236e0dac50fSopenharmony_ci int index = 0; 237e0dac50fSopenharmony_ci for (const auto& area : touchHotAreas) { 238e0dac50fSopenharmony_ci oss << "[ " << area.posX_ << ", " << area.posY_ << ", " << area.width_ << ", " << area.height_ << " ]"; 239e0dac50fSopenharmony_ci index++; 240e0dac50fSopenharmony_ci if (index < static_cast<int32_t>(touchHotAreas.size())) { 241e0dac50fSopenharmony_ci oss <<", "; 242e0dac50fSopenharmony_ci } 243e0dac50fSopenharmony_ci } 244e0dac50fSopenharmony_ci oss << std::endl; 245e0dac50fSopenharmony_ci} 246e0dac50fSopenharmony_ci 247e0dac50fSopenharmony_ciWMError WindowDumper::DumpWindowInfo(const std::vector<std::string>& args, std::string& dumpInfo) 248e0dac50fSopenharmony_ci{ 249e0dac50fSopenharmony_ci if (args.empty()) { 250e0dac50fSopenharmony_ci return WMError::WM_ERROR_INVALID_PARAM; 251e0dac50fSopenharmony_ci } 252e0dac50fSopenharmony_ci if (args.size() == 1 && args[0] == ARG_DUMP_ALL) { // 1: params num 253e0dac50fSopenharmony_ci return DumpAllWindowInfo(dumpInfo); 254e0dac50fSopenharmony_ci } else if (args.size() >= 2 && args[0] == ARG_DUMP_WINDOW && IsValidDigitString(args[1])) { // 2: params num 255e0dac50fSopenharmony_ci uint32_t windowId = std::stoul(args[1]); 256e0dac50fSopenharmony_ci return DumpSpecifiedWindowInfo(windowId, args, dumpInfo); 257e0dac50fSopenharmony_ci } else { 258e0dac50fSopenharmony_ci return WMError::WM_ERROR_INVALID_PARAM; 259e0dac50fSopenharmony_ci } 260e0dac50fSopenharmony_ci} 261e0dac50fSopenharmony_ci 262e0dac50fSopenharmony_civoid WindowDumper::ShowIllegalArgsInfo(std::string& dumpInfo, WMError errCode) 263e0dac50fSopenharmony_ci{ 264e0dac50fSopenharmony_ci switch (errCode) { 265e0dac50fSopenharmony_ci case WMError::WM_ERROR_INVALID_PARAM: 266e0dac50fSopenharmony_ci dumpInfo.append("The arguments are illegal and you can enter '-h' for help."); 267e0dac50fSopenharmony_ci break; 268e0dac50fSopenharmony_ci case WMError::WM_ERROR_NULLPTR: 269e0dac50fSopenharmony_ci dumpInfo.append("The window is invalid, you can enter '-a' to get valid window id."); 270e0dac50fSopenharmony_ci break; 271e0dac50fSopenharmony_ci default: 272e0dac50fSopenharmony_ci break; 273e0dac50fSopenharmony_ci } 274e0dac50fSopenharmony_ci} 275e0dac50fSopenharmony_ci 276e0dac50fSopenharmony_civoid WindowDumper::ShowHelpInfo(std::string& dumpInfo) 277e0dac50fSopenharmony_ci{ 278e0dac50fSopenharmony_ci dumpInfo.append("Usage:\n") 279e0dac50fSopenharmony_ci .append(" -h ") 280e0dac50fSopenharmony_ci .append("|help text for the tool\n") 281e0dac50fSopenharmony_ci .append(" -a ") 282e0dac50fSopenharmony_ci .append("|dump all window information in the system\n") 283e0dac50fSopenharmony_ci .append(" -w {window id} [ArkUI Option] ") 284e0dac50fSopenharmony_ci .append("|dump specified window information\n") 285e0dac50fSopenharmony_ci .append(" ------------------------------------[ArkUI Option]------------------------------------ \n"); 286e0dac50fSopenharmony_ci ShowAceDumpHelp(dumpInfo); 287e0dac50fSopenharmony_ci} 288e0dac50fSopenharmony_ci 289e0dac50fSopenharmony_civoid WindowDumper::ShowAceDumpHelp(std::string& dumpInfo) 290e0dac50fSopenharmony_ci{ 291e0dac50fSopenharmony_ci auto node = windowRoot_->GetWindowForDumpAceHelpInfo(); 292e0dac50fSopenharmony_ci if (node == nullptr) { 293e0dac50fSopenharmony_ci WLOGFE("invalid window"); 294e0dac50fSopenharmony_ci return; 295e0dac50fSopenharmony_ci } 296e0dac50fSopenharmony_ci if (node->GetWindowToken() != nullptr) { 297e0dac50fSopenharmony_ci std::vector<std::string> params; 298e0dac50fSopenharmony_ci params.emplace_back(ARG_DUMP_HELP); 299e0dac50fSopenharmony_ci dumpInfoFuture_.ResetLock({}); 300e0dac50fSopenharmony_ci node->GetWindowToken()->DumpInfo(params); 301e0dac50fSopenharmony_ci auto infos = dumpInfoFuture_.GetResult(2000); // 2000: wait for 2000ms 302e0dac50fSopenharmony_ci for (auto& info: infos) { 303e0dac50fSopenharmony_ci dumpInfo.append(info).append("\n"); 304e0dac50fSopenharmony_ci } 305e0dac50fSopenharmony_ci } 306e0dac50fSopenharmony_ci} 307e0dac50fSopenharmony_ci} 308e0dac50fSopenharmony_ci}