1/* 2 * Copyright (c) 2023 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 "active_key_event.h" 17 18#include <vector> 19 20#include "event_log_task.h" 21#include "file_util.h" 22#include "hiview_logger.h" 23#include "sys_event.h" 24#include "time_util.h" 25#include "trace_collector.h" 26namespace OHOS { 27namespace HiviewDFX { 28namespace { 29 static const inline char* CMD_LIST[] = { 30 "cmd:w", 31 "cmd:rs", 32 "cmd:a", 33 "k:SysRqFile", 34 "cmd:p", 35 "cmd:d", 36 "cmd:c", 37 }; 38} 39DEFINE_LOG_LABEL(0xD002D01, "EventLogger-ActiveKeyEvent"); 40ActiveKeyEvent::ActiveKeyEvent() 41{ 42 triggeringTime_ = 0; 43 logStore_ = nullptr; 44} 45 46ActiveKeyEvent::~ActiveKeyEvent() 47{ 48 std::unique_lock<ffrt::mutex> uniqueLock(mutex_); 49 for (auto it = subscribeIds_.begin(); it != subscribeIds_.end(); it = subscribeIds_.erase(it)) { 50 if (*it >= 0) { 51 MMI::InputManager::GetInstance()->UnsubscribeKeyEvent(*it); 52 HIVIEW_LOGI("~ActiveKeyEvent subscribeId_: %{public}d", *it); 53 } 54 } 55} 56 57int64_t ActiveKeyEvent::SystemTimeMillisecond() 58{ 59 struct timespec t; 60 t.tv_sec = 0; 61 t.tv_nsec = 0; 62 clock_gettime(CLOCK_MONOTONIC, &t); 63 return (int64_t)((t.tv_sec) * TimeUtil::SEC_TO_NANOSEC + t.tv_nsec) / TimeUtil::SEC_TO_MICROSEC; 64} 65 66void ActiveKeyEvent::InitSubscribe(std::set<int32_t> preKeys, int32_t finalKey, int32_t count, int32_t holdTime) 67{ 68 const int32_t maxCount = 5; 69 if (++count > maxCount) { 70 return; 71 } 72 std::shared_ptr<MMI::KeyOption> keyOption = std::make_shared<MMI::KeyOption>(); 73 if (keyOption == nullptr) { 74 HIVIEW_LOGE("Invalid key option"); 75 return; 76 } 77 78 keyOption->SetPreKeys(preKeys); 79 keyOption->SetFinalKey(finalKey); 80 keyOption->SetFinalKeyDown(true); 81 keyOption->SetFinalKeyDownDuration(holdTime); 82 auto keyEventCallBack = [this] (std::shared_ptr<MMI::KeyEvent> keyEvent) { 83 this->CombinationKeyCallback(keyEvent); 84 }; 85 int32_t subscribeId = MMI::InputManager::GetInstance()->SubscribeKeyEvent(keyOption, keyEventCallBack); 86 if (subscribeId < 0) { 87 HIVIEW_LOGE("SubscribeKeyEvent failed, finalKey: %{public}d," 88 "subscribeId: %{public}d option failed.", finalKey, subscribeId); 89 auto task = [this, preKeys, finalKey, count, holdTime] { 90 this->InitSubscribe(preKeys, finalKey, count, holdTime); 91 taskOutDeps++; 92 }; 93 std::string taskName("InitSubscribe" + std::to_string(finalKey) + "_" + std::to_string(count)); 94 ffrt::submit(task, {}, {&taskOutDeps}, ffrt::task_attr().name(taskName.c_str())); 95 } 96 std::unique_lock<ffrt::mutex> uniqueLock(mutex_); 97 subscribeIds_.emplace_back(subscribeId); 98 HIVIEW_LOGI("CombinationKeyInit finalKey: %{public}d subscribeId_: %{public}d", 99 finalKey, subscribeId); 100} 101 102void ActiveKeyEvent::Init(std::shared_ptr<LogStoreEx> logStore) 103{ 104 HIVIEW_LOGI("CombinationKeyInit"); 105 logStore_ = logStore; 106 107 std::set<int32_t> prePowerKeys; 108 prePowerKeys.insert(MMI::KeyEvent::KEYCODE_VOLUME_DOWN); 109 auto initSubscribePower = [this, prePowerKeys] { 110 this->InitSubscribe(prePowerKeys, MMI::KeyEvent::KEYCODE_POWER, 0, 500); 111 }; 112 std::set<int32_t> preOnlyPowerKeys; 113 auto initSubscribeOnlyPower = [this, preOnlyPowerKeys] { 114 this->InitSubscribe(preOnlyPowerKeys, MMI::KeyEvent::KEYCODE_POWER, 0, 3000); 115 }; 116 ffrt::submit(initSubscribePower, {}, {}, ffrt::task_attr().name("initSubscribePower").qos(ffrt::qos_default)); 117 ffrt::submit(initSubscribeOnlyPower, {}, {}, 118 ffrt::task_attr().name("initSubscribeOnlyPower").qos(ffrt::qos_default)); 119} 120 121void ActiveKeyEvent::HitraceCapture() 122{ 123 std::shared_ptr<UCollectUtil::TraceCollector> collector = UCollectUtil::TraceCollector::Create(); 124 UCollect::TraceCaller caller = UCollect::TraceCaller::BETACLUB; 125 auto result = collector->DumpTrace(caller); 126 if (result.retCode != 0) { 127 HIVIEW_LOGE("get hitrace fail! error code: %{public}d", result.retCode); 128 return; 129 } 130} 131 132void ActiveKeyEvent::SysMemCapture(int fd) 133{ 134 FileUtil::SaveStringToFd(fd, "\n\ncatcher cmd : /proc/meminfo\n"); 135 std::string content; 136 FileUtil::LoadStringFromFile("/proc/meminfo", content); 137 FileUtil::SaveStringToFd(fd, content); 138} 139 140void ActiveKeyEvent::DumpCapture(int fd) 141{ 142 SysEventCreator sysEventCreator("HIVIEWDFX", "ACTIVE_KEY", SysEventCreator::FAULT); 143 std::shared_ptr<SysEvent> sysEvent = std::make_shared<SysEvent>("ActiveKeyEvent", nullptr, sysEventCreator); 144 int noNeedJsonFd = -1; 145 std::unique_ptr<EventLogTask> logTask = std::make_unique<EventLogTask>(fd, noNeedJsonFd, sysEvent); 146 for (const std::string& cmd : CMD_LIST) { 147 logTask->AddLog(cmd); 148 } 149 150 auto ret = logTask->StartCompose(); 151 if (ret != EventLogTask::TASK_SUCCESS) { 152 HIVIEW_LOGE("capture fail %{public}d", ret); 153 } 154 SysMemCapture(fd); 155} 156 157void ActiveKeyEvent::CombinationKeyHandle(std::shared_ptr<MMI::KeyEvent> keyEvent) 158{ 159 HIVIEW_LOGI("Receive CombinationKeyHandle."); 160 if (logStore_ == nullptr) { 161 return; 162 } 163 164 std::string logFile = "ACTIVE_KEY_EVENT-0-" + 165 TimeUtil::TimestampFormatToDate(TimeUtil::GetMilliseconds() / TimeUtil::SEC_TO_MILLISEC, 166 "%Y%m%d%H%M%S") + ".log"; 167 if (FileUtil::FileExists("/data/log/eventlog/" + logFile)) { 168 HIVIEW_LOGW("filename: %{public}s is existed, direct use.", logFile.c_str()); 169 return; 170 } 171 int fd = logStore_->CreateLogFile(logFile); 172 173 auto sysStart = ActiveKeyEvent::SystemTimeMillisecond(); 174 const uint32_t placeholder = 3; 175 auto start = TimeUtil::GetMilliseconds(); 176 uint64_t startTime = start / TimeUtil::SEC_TO_MILLISEC; 177 std::ostringstream startTimeStr; 178 startTimeStr << "start time: " << TimeUtil::TimestampFormatToDate(startTime, "%Y/%m/%d-%H:%M:%S"); 179 startTimeStr << ":" << std::setw(placeholder) << std::setfill('0') << 180 std::to_string(start % TimeUtil::SEC_TO_MILLISEC) << std::endl; 181 std::vector<int32_t> keys = keyEvent->GetPressedKeys(); 182 for (auto& i : keys) { 183 startTimeStr << "CombinationKeyCallback key : "; 184 startTimeStr << MMI::KeyEvent::KeyCodeToString(i) << std::endl; 185 } 186 FileUtil::SaveStringToFd(fd, startTimeStr.str()); 187 188 auto hitraceCapture = [this] { this->HitraceCapture(); }; 189 ffrt::submit(hitraceCapture, {}, {}, ffrt::task_attr().name("HitraceCapture").qos(ffrt::qos_user_initiated)); 190 191 DumpCapture(fd); 192 auto end = ActiveKeyEvent::SystemTimeMillisecond(); 193 std::string totalTime = "\n\nCatcher log total time is " + std::to_string(end - sysStart) + "ms\n"; 194 FileUtil::SaveStringToFd(fd, totalTime); 195 close(fd); 196} 197 198void ActiveKeyEvent::CombinationKeyCallback(std::shared_ptr<MMI::KeyEvent> keyEvent) 199{ 200 HIVIEW_LOGI("Receive CombinationKeyCallback key id: %{public}d.", keyEvent->GetId()); 201 uint64_t now = (uint64_t)ActiveKeyEvent::SystemTimeMillisecond(); 202 const uint64_t interval = 10000; 203 if (now - triggeringTime_ < interval) { 204 return; 205 } 206 triggeringTime_ = now; 207 auto combinationKeyHandle = [this, keyEvent] { this->CombinationKeyHandle(keyEvent); }; 208 ffrt::submit(combinationKeyHandle, {}, {}, 209 ffrt::task_attr().name("ActiveKeyEvent").qos(ffrt::qos_user_initiated)); 210} 211} // namespace HiviewDFX 212} // namespace OHOS