* Copyright (c) 2023-2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "appfreeze_manager.h"
#include <fcntl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fstream>
#include <sstream>
#include <sys/ioctl.h>
#include "faultloggerd_client.h"
#include "file_ex.h"
#include "ffrt.h"
#include "dfx_dump_catcher.h"
#include "directory_ex.h"
#include "hisysevent_report.h"
#include "hitrace_meter.h"
#include "parameter.h"
#include "parameters.h"
#include "singleton.h"
#include "res_sched_util.h"
#include "app_mgr_client.h"
#include "hilog_tag_wrapper.h"
#include "time_util.h"
#ifdef ABILITY_RUNTIME_HITRACE_ENABLE
#include "hitrace/hitracechain.h"
#endif
#include "appfreeze_cpu_freq_manager.h"
#include "appfreeze_util.h"
#include "xcollie/process_kill_reason.h"
#undef FREEZE_DOMAIN
#define FREEZE_DOMAIN 0xD001310
namespace OHOS {
namespace AppExecFwk {
namespace {
constexpr char KILL_EVENT_NAME[] = "APP_KILL";
constexpr int MAX_LAYER = 8;
constexpr int FREEZEMAP_SIZE_MAX = 20;
constexpr int FREEZE_TIME_LIMIT = 60000;
constexpr int FREEZE_EVENT_MAX_SIZE = 200;
constexpr int64_t FREEZE_KILL_LIMIT = 60000;
static constexpr uint8_t ARR_SIZE = 7;
static constexpr uint8_t DECIMAL = 10;
static constexpr uint8_t FREE_ASYNC_INDEX = 6;
static constexpr uint16_t FREE_ASYNC_MAX = 1000;
static constexpr int64_t NANOSECONDS = 1000000000;
static constexpr int64_t MICROSECONDS = 1000000;
static constexpr int DUMP_STACK_FAILED = -1;
static constexpr int DUMP_KERNEL_STACK_SUCCESS = 1;
static constexpr int MIN_APP_UID = 20000;
static constexpr int MAX_REPORT_STACK_SIZE = 256 * 1024;
static constexpr int UNKNOWN_FREEZE_REASON = -1;
const std::string LOG_FILE_PATH = "/data/log/eventlog";
static bool g_betaVersion = OHOS::system::GetParameter("const.logsystem.versiontype", "unknown") == "beta";
static bool g_overseaVersion = OHOS::system::GetParameter("const.global.region", "CN") != "CN";
static bool g_developMode = (OHOS::system::GetParameter("persist.hiview.leak_detector", "unknown") == "enable") ||
(OHOS::system::GetParameter("persist.hiview.leak_detector", "unknown") == "true");
static constexpr const char *const HITRACE_ID = "hitrace_id: ";
static constexpr const char *const SPAN_ID = "span_id: ";
static constexpr const char *const PARENT_SPAN_ID = "parent_span_id: ";
static constexpr const char *const TRACE_FLAG = "trace_flag: ";
static constexpr const char *const DEV_SYSLOAD = "/dev/sysload";
constexpr const char* PRELOAD_UIEXTENSION = "PreloadUIExtension";
constexpr int32_t INVALID_KILL_ID = -2;
constexpr const char* INVALID_KILL_REASON = "InvalidKillId";
static constexpr int SYSLOAD_GET_KILL_INFO_MAGIC = 0xE5AC02;
#define KILL_LOG_BASE 'S'
#define GET_KILL_INFO _IOWR(KILL_LOG_BASE, 0x06, int32_t)
#define SYSLOAD_GET_KILL_INFO_MAGIC 0xE5AC02
struct KillEventInfo {
int id = 0;
int adj = 0;
bool processed = false;
bool foreground = false;
pid_t pid = 0;
int uid = 0;
int64_t timestamp = 0;
int64_t eventParamFirst = 0;
int64_t eventParamSecond = 0;
int64_t eventParamThird = 0;
int64_t eventParamFourth = 0;
int64_t eventParamFifth = 0;
int64_t eventParamSixth = 0;
int64_t eventParamSeventh = 0;
};
struct KillInfo {
unsigned int magic;
pid_t pid;
struct KillEventInfo data;
unsigned int structSize;
};
}
static constexpr const char *const TWELVE_BIG_CPU_CUR_FREQ = "/sys/devices/system/cpu/cpufreq/policy2/scaling_cur_freq";
static constexpr const char *const TWELVE_BIG_CPU_MAX_FREQ = "/sys/devices/system/cpu/cpufreq/policy2/scaling_max_freq";
static constexpr const char *const TWELVE_MID_CPU_CUR_FREQ = "/sys/devices/system/cpu/cpufreq/policy1/scaling_cur_freq";
static constexpr const char *const TWELVE_MID_CPU_MAX_FREQ = "/sys/devices/system/cpu/cpufreq/policy1/scaling_max_freq";
const static std::set<std::string> HALF_EVENT_CONFIGS = {"UI_BLOCK_3S", "THREAD_BLOCK_3S", "BUSSNESS_THREAD_BLOCK_3S",
"LIFECYCLE_HALF_TIMEOUT", "LIFECYCLE_HALF_TIMEOUT_WARNING"};
static constexpr int PERF_TIME = 60000;
static constexpr int FREEZE_EVENT_ZERO = 0;
static constexpr int FREEZE_EVENT_FIRST = 1;
static constexpr int FREEZE_EVENT_SED = 2;
static constexpr int FREEZE_EVENT_THIRD = 3;
static constexpr int FREEZE_EVENT_FORTH = 4;
std::shared_ptr<AppfreezeManager> AppfreezeManager::instance_ = nullptr;
ffrt::mutex AppfreezeManager::singletonMutex_;
ffrt::mutex AppfreezeManager::freezeMutex_;
ffrt::mutex AppfreezeManager::catchStackMutex_;
std::map<int, std::string> AppfreezeManager::catchStackMap_;
ffrt::mutex AppfreezeManager::freezeFilterMutex_;
ffrt::mutex AppfreezeManager::freezeInfoMutex_;
std::string AppfreezeManager::appfreezeInfoPath_;
AppfreezeManager::AppfreezeManager()
{
name_ = "AppfreezeManager" + std::to_string(AbilityRuntime::TimeUtil::CurrentTimeMillis());
}
AppfreezeManager::~AppfreezeManager()
{
}
std::shared_ptr<AppfreezeManager> AppfreezeManager::GetInstance()
{
if (instance_ == nullptr) {
std::lock_guard<ffrt::mutex> lock(singletonMutex_);
if (instance_ == nullptr) {
instance_ = std::make_shared<AppfreezeManager>();
}
}
return instance_;
}
void AppfreezeManager::DestroyInstance()
{
std::lock_guard<ffrt::mutex> lock(singletonMutex_);
if (instance_ != nullptr) {
instance_.reset();
instance_ = nullptr;
}
}
bool AppfreezeManager::IsHandleAppfreeze(const std::string& bundleName)
{
if (bundleName.empty()) {
return true;
}
return !DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->IsAttachDebug(bundleName);
}
int AppfreezeManager::AppfreezeHandle(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo)
{
TAG_LOGD(AAFwkTag::APPDFR, "called %{public}s, bundleName %{public}s, name_ %{public}s",
faultData.errorObject.name.c_str(), appInfo.bundleName.c_str(), name_.c_str());
if (!IsHandleAppfreeze(appInfo.bundleName)) {
return -1;
}
HITRACE_METER_FMT(HITRACE_TAG_APP, "AppfreezeHandler:%{public}s bundleName:%{public}s",
faultData.errorObject.name.c_str(), appInfo.bundleName.c_str());
std::string memoryContent = "";
CollectFreezeSysMemory(memoryContent);
if (faultData.errorObject.name == AppFreezeType::APP_INPUT_BLOCK ||
faultData.errorObject.name == AppFreezeType::THREAD_BLOCK_3S ||
faultData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT ||
faultData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT_WARNING) {
AcquireStack(faultData, appInfo, memoryContent);
} else {
NotifyANR(faultData, appInfo, "", memoryContent);
}
return 0;
}
void AppfreezeManager::CollectFreezeSysMemory(std::string& memoryContent)
{
memoryContent = "\nGet freeze memory start time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() + "\n";
std::string tmp = "";
std::string pressMemInfo = "/proc/pressure/memory";
OHOS::LoadStringFromFile(pressMemInfo, tmp);
memoryContent += tmp + "\n";
std::string memInfoPath = "/proc/memview";
if (!OHOS::FileExists(memInfoPath)) {
memInfoPath = "/proc/meminfo";
}
OHOS::LoadStringFromFile(memInfoPath, tmp);
memoryContent += tmp + "\nGet freeze memory end time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr();
}
std::string AppfreezeManager::GetCatcherStack(const std::string& fileName, const std::string& catcherStack)
{
std::string stackFile = WriteToFile(fileName, catcherStack);
if (!stackFile.empty()) {
return stackFile;
}
if (catcherStack.size() > MAX_REPORT_STACK_SIZE) {
stackFile = "";
TAG_LOGW(AAFwkTag::APPDFR, "create stack failed, catcherStack over size: %{public}zu",
catcherStack.size());
} else {
stackFile = catcherStack;
TAG_LOGW(AAFwkTag::APPDFR, "create stack failed, catcherStack size: %{public}zu", catcherStack.size());
}
return stackFile;
}
int AppfreezeManager::MergeNotifyInfo(FaultData& faultNotifyData, const AppfreezeManager::AppInfo& appInfo)
{
std::string memoryContent;
CollectFreezeSysMemory(memoryContent);
std::string fileName = faultNotifyData.errorObject.name + "_" +
AbilityRuntime::TimeUtil::FormatTime("%Y%m%d%H%M%S") + "_" + std::to_string(appInfo.pid) + "_stack";
std::string catcherStack;
faultNotifyData.errorObject.message += "\nCatche stack trace start time: " +
AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() + "\n";
uint64_t dumpStartTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count());
std::string resultMsg;
if (faultNotifyData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT_WARNING ||
faultNotifyData.errorObject.name == AppFreezeType::LIFECYCLE_TIMEOUT_WARNING) {
catcherStack += CatcherStacktrace(appInfo.pid);
} else {
std::pair<std::string, std::string> catchResult =
CatchJsonStacktrace(appInfo.pid, faultNotifyData.errorObject.name);
catcherStack += catchResult.first;
resultMsg += catchResult.second;
}
uint64_t dumpFinishTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count());
std::string timeStamp = "Catche stack trace end time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr();
catcherStack = GetCatcherStack(fileName, catcherStack);
faultNotifyData.errorObject.stack = catcherStack.empty() ? faultNotifyData.errorObject.stack : catcherStack;
if (appInfo.isOccurException) {
faultNotifyData.errorObject.message += "\nnotifyAppFault exception.\n";
}
faultNotifyData.errorObject.message += timeStamp;
if (faultNotifyData.errorObject.name == AppFreezeType::APP_INPUT_BLOCK ||
faultNotifyData.errorObject.name == AppFreezeType::THREAD_BLOCK_3S ||
faultNotifyData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT ||
faultNotifyData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT_WARNING) {
AcquireStack(faultNotifyData, appInfo, memoryContent);
} else {
NotifyANR(faultNotifyData, appInfo, "", memoryContent);
}
RecordAppFreezeBehavior(faultNotifyData, dumpStartTime, dumpFinishTime, resultMsg);
return 0;
}
void AppfreezeManager::RecordAppFreezeBehavior(FaultData& faultData, uint64_t dumpStartTime,
uint64_t dumpFinishTime, const std::string& resultMsg)
{
std::lock_guard<std::mutex> mapLock(freezeMapMutex_);
std::string eventName = faultData.errorObject.name;
if (freezeEventMap_.size() > FREEZE_EVENT_MAX_SIZE) {
freezeEventMap_.clear();
}
auto it = std::find(APP_FREEZE_EVENT_NAME.begin(), APP_FREEZE_EVENT_NAME.end(), eventName);
if (it != APP_FREEZE_EVENT_NAME.end()) {
freezeEventMap_[faultData.pid][eventName].schedTime = faultData.schedTime;
freezeEventMap_[faultData.pid][eventName].detectTime = faultData.detectTime;
freezeEventMap_[faultData.pid][eventName].dumpStartTime = dumpStartTime;
freezeEventMap_[faultData.pid][eventName].dumpFinishTime = dumpFinishTime;
freezeEventMap_[faultData.pid][eventName].dumpResult = resultMsg;
freezeEventMap_[faultData.pid][eventName].appStatus = faultData.appStatus;
freezeEventMap_[faultData.pid][KILL_EVENT_NAME].dumpStartTime = faultData.samplerStartTime;
freezeEventMap_[faultData.pid][KILL_EVENT_NAME].dumpFinishTime = faultData.samplerFinishTime;
freezeEventMap_[faultData.pid][KILL_EVENT_NAME].dumpResult = std::to_string(faultData.samplerCount);
freezeEventMap_[faultData.pid][KILL_EVENT_NAME].isRepeatKilledThread = false;
}
}
int AppfreezeManager::AppfreezeHandleWithStack(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo)
{
TAG_LOGW(AAFwkTag::APPDFR, "NotifyAppFaultTask called, eventName:%{public}s, bundleName:%{public}s, "
"name_:%{public}s, currentTime:%{public}s, isInForeground:%{public}d",
faultData.errorObject.name.c_str(), appInfo.bundleName.c_str(),
name_.c_str(), AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str(), faultData.isInForeground);
if (!IsHandleAppfreeze(appInfo.bundleName)) {
return -1;
}
FaultData faultNotifyData;
faultNotifyData.errorObject.name = faultData.errorObject.name;
faultNotifyData.errorObject.message = faultData.errorObject.message;
faultNotifyData.errorObject.stack = faultData.errorObject.stack;
faultNotifyData.errorObject.mainStack = faultData.errorObject.mainStack;
faultNotifyData.faultType = FaultDataType::APP_FREEZE;
faultNotifyData.eventId = faultData.eventId;
faultNotifyData.schedTime = faultData.schedTime;
faultNotifyData.detectTime = faultData.detectTime;
faultNotifyData.appStatus = faultData.appStatus;
faultNotifyData.samplerStartTime = faultData.samplerStartTime;
faultNotifyData.samplerFinishTime = faultData.samplerFinishTime;
faultNotifyData.samplerCount = faultData.samplerCount;
faultNotifyData.pid = faultData.pid;
faultNotifyData.tid = faultData.tid;
faultNotifyData.appfreezeInfo = faultData.appfreezeInfo;
faultNotifyData.appRunningUniqueId = faultData.appRunningUniqueId;
faultNotifyData.procStatm = faultData.procStatm;
faultNotifyData.isInForeground = faultData.isInForeground;
faultNotifyData.isEnableMainThreadSample = faultData.isEnableMainThreadSample;
faultNotifyData.reportLifecycleToFreeze = faultData.reportLifecycleToFreeze;
faultNotifyData.applicationHeapInfo = faultData.applicationHeapInfo;
faultNotifyData.applicationGCInfo = faultData.applicationGCInfo;
faultNotifyData.applicationIOInfo = faultData.applicationIOInfo;
faultNotifyData.isBlockInGc = faultData.isBlockInGc;
faultNotifyData.processLifeTime = faultData.processLifeTime;
faultNotifyData.markedId = faultData.markedId;
faultNotifyData.processedId = faultData.processedId;
faultNotifyData.dispatchedEventId = faultData.dispatchedEventId;
faultNotifyData.callbackLog = faultData.callbackLog;
HITRACE_METER_FMT(HITRACE_TAG_APP, "AppfreezeHandleWithStack pid:%{public}d-name:%{public}s",
appInfo.pid, faultData.errorObject.name.c_str());
return MergeNotifyInfo(faultNotifyData, appInfo);
}
std::string AppfreezeManager::WriteToFile(const std::string& fileName, const std::string& content)
{
std::string path = LOG_FILE_PATH + "/freeze";
constexpr mode_t defaultLogDirMode = 0770;
if (!OHOS::FileExists(path)) {
OHOS::ForceCreateDirectory(path);
OHOS::ChangeModeDirectory(path, defaultLogDirMode);
}
std::string realPath = AppfreezeUtil::FreezePathToRealPath(path);
if (realPath.empty()) {
realPath = path;
}
std::string stackPath = realPath + "/" + fileName;
constexpr mode_t defaultLogFileMode = 0644;
FILE* fp = fopen(stackPath.c_str(), "w+");
chmod(stackPath.c_str(), defaultLogFileMode);
if (fp == nullptr) {
TAG_LOGI(AAFwkTag::APPDFR, "stackPath create failed, errno: %{public}d", errno);
return "";
} else {
TAG_LOGI(AAFwkTag::APPDFR, "stackPath: %{public}s", stackPath.c_str());
}
OHOS::SaveStringToFile(stackPath, content, true);
(void)fclose(fp);
return stackPath;
}
int AppfreezeManager::LifecycleTimeoutHandle(const ParamInfo& info, FreezeUtil::LifecycleFlow flow)
{
if (info.typeId != AppfreezeManager::TypeAttribute::CRITICAL_TIMEOUT || !IsHandleAppfreeze(info.bundleName)) {
return -1;
}
if (info.eventName != AppFreezeType::LIFECYCLE_TIMEOUT && info.eventName != AppFreezeType::LIFECYCLE_HALF_TIMEOUT
&& info.eventName != AppFreezeType::LIFECYCLE_TIMEOUT_WARNING
&& info.eventName != AppFreezeType::LIFECYCLE_HALF_TIMEOUT_WARNING) {
return -1;
}
std::string faultTimeStr = "\nFault time:" + AbilityRuntime::TimeUtil::FormatTime("%Y/%m/%d-%H:%M:%S") + "\n";
if (!g_betaVersion && info.eventName == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
auto hisyseventReport = std::make_shared<AAFwk::HisyseventReport>(2);
hisyseventReport->InsertParam("PID", info.pid);
hisyseventReport->InsertParam("PACKAGE_NAME", info.bundleName);
int32_t ret = hisyseventReport->Report("AAFWK", "FREEZE_HALF_HIVIEW_LOG", HISYSEVENT_FAULT);
TAG_LOGW(AAFwkTag::APPDFR, "hisysevent write FREEZE_HALF_HIVIEW_LOG, pid:%{public}d, packageName:%{public}s,"
" ret:%{public}d", info.pid, info.bundleName.c_str(), ret);
}
std::string message;
if (g_betaVersion && info.eventName == AppFreezeType::LIFECYCLE_TIMEOUT) {
auto hisyseventReport = std::make_shared<AAFwk::HisyseventReport>(3);
hisyseventReport->InsertParam("PID", info.pid);
hisyseventReport->InsertParam("PACKAGE_NAME", info.bundleName);
hisyseventReport->InsertParam("FAULT_TIME", faultTimeStr);
int32_t ret = hisyseventReport->Report("AAFWK", "FREEZE_HALF_HIVIEW_LOG", HISYSEVENT_FAULT);
message = (ret == 0) ? "FREEZE_HALF_HIVIEW_LOG write success" : "";
}
TAG_LOGD(AAFwkTag::APPDFR, "called %{public}s, name_ %{public}s", info.bundleName.c_str(), name_.c_str());
HITRACE_METER_FMT(HITRACE_TAG_APP, "LifecycleTimeoutHandle:%{public}s bundleName:%{public}s",
info.eventName.c_str(), info.bundleName.c_str());
AppFaultDataBySA faultDataSA = GenerateFaultDataBySA(info, flow);
faultDataSA.errorObject.message = faultTimeStr + faultDataSA.errorObject.message + message;
DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->NotifyAppFaultBySA(faultDataSA);
return 0;
}
AppFaultDataBySA AppfreezeManager::GenerateFaultDataBySA(const ParamInfo& info, const FreezeUtil::LifecycleFlow& flow)
{
AppFaultDataBySA faultDataSA;
if (info.eventName == AppFreezeType::LIFECYCLE_TIMEOUT) {
std::string realPath = AppfreezeUtil::FreezePathToRealPath("/proc/" + std::to_string(info.pid) + "/statm");
std::ifstream statmStream(realPath);
if (statmStream) {
std::string procStatm;
std::getline(statmStream, procStatm);
statmStream.close();
faultDataSA.procStatm = procStatm;
}
}
faultDataSA.errorObject.name = info.eventName;
faultDataSA.errorObject.message = info.msg;
faultDataSA.faultType = FaultDataType::APP_FREEZE;
faultDataSA.timeoutMarkers = "notifyFault" + std::to_string(info.pid) +
"-" + std::to_string(AbilityRuntime::TimeUtil::CurrentTimeMillis());
faultDataSA.pid = info.pid;
faultDataSA.needKillProcess = info.needKillProcess;
if (flow.state != AbilityRuntime::FreezeUtil::TimeoutState::UNKNOWN) {
faultDataSA.token = flow.token;
faultDataSA.state = static_cast<uint32_t>(flow.state);
}
faultDataSA.detectTime = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count());
return faultDataSA;
}
FaultData AppfreezeManager::GetFaultNotifyData(const FaultData& faultData, int pid)
{
FaultData faultNotifyData;
faultNotifyData.errorObject.name = faultData.errorObject.name;
faultNotifyData.errorObject.message = faultData.errorObject.message;
faultNotifyData.errorObject.stack = faultData.errorObject.stack;
faultNotifyData.errorObject.mainStack = faultData.errorObject.mainStack;
faultNotifyData.faultType = FaultDataType::APP_FREEZE;
faultNotifyData.eventId = faultData.eventId;
if (faultData.errorObject.name == AppFreezeType::APP_INPUT_BLOCK || faultData.tid <= 0) {
faultNotifyData.tid = pid;
} else {
faultNotifyData.tid = faultData.tid;
}
faultNotifyData.appfreezeInfo = faultData.appfreezeInfo;
faultNotifyData.appRunningUniqueId = faultData.appRunningUniqueId;
faultNotifyData.procStatm = faultData.procStatm;
faultNotifyData.isInForeground = faultData.isInForeground;
faultNotifyData.isEnableMainThreadSample = faultData.isEnableMainThreadSample;
faultNotifyData.reportLifecycleToFreeze = faultData.reportLifecycleToFreeze;
faultNotifyData.applicationHeapInfo = faultData.applicationHeapInfo;
faultNotifyData.applicationGCInfo = faultData.applicationGCInfo;
faultNotifyData.applicationIOInfo = faultData.applicationIOInfo;
faultNotifyData.isBlockInGc = faultData.isBlockInGc;
faultNotifyData.processLifeTime = faultData.processLifeTime;
faultNotifyData.markedId = faultData.markedId;
faultNotifyData.processedId = faultData.processedId;
faultNotifyData.dispatchedEventId = faultData.dispatchedEventId;
faultNotifyData.callbackLog = faultData.callbackLog;
return faultNotifyData;
}
int AppfreezeManager::AcquireStack(const FaultData& faultData,
const AppfreezeManager::AppInfo& appInfo, const std::string& memoryContent)
{
int pid = appInfo.pid;
FaultData faultNotifyData = GetFaultNotifyData(faultData, pid);
std::string binderInfo;
std::string binderPidsStr;
std::string terminalBinderTid;
AppfreezeManager::TerminalBinder terminalBinder = {0, 0};
AppfreezeManager::ParseBinderParam params = {pid, faultNotifyData.tid, pid, 0};
std::set<int> asyncPids;
std::set<int> syncPids = GetBinderPeerPids(binderInfo, params, asyncPids, terminalBinder);
std::string binderProcessNameStr;
std::string binderProcessStackStr;
for (auto& pidTemp : syncPids) {
TAG_LOGI(AAFwkTag::APPDFR, "PeerBinder pidTemp pids:%{public}d", pidTemp);
if (pidTemp == pid || IsAncoProc(pidTemp)) {
continue;
}
std::string content = "Binder catcher stacktrace, type is peer, pid : " + std::to_string(pidTemp) + "\n";
content += CatcherStacktrace(pidTemp);
binderPidsStr += " " + std::to_string(pidTemp);
binderProcessNameStr += std::to_string(pidTemp) + "(" +
AppfreezeUtil::GetProcessNameFromProcCmdline(pidTemp) + ");";
if (terminalBinder.pid > 0 && pidTemp == terminalBinder.pid) {
terminalBinder.tid = (terminalBinder.tid > 0) ? terminalBinder.tid : terminalBinder.pid;
content = "Binder catcher stacktrace, terminal binder tag\n" + content +
"Binder catcher stacktrace, terminal binder tag\n";
terminalBinderTid = std::to_string(terminalBinder.tid);
}
binderProcessStackStr += content;
}
if (syncPids.empty()) {
binderInfo += "PeerBinder pids is empty\n";
} else {
if (!binderProcessNameStr.empty()) {
binderProcessNameStr.pop_back();
binderProcessNameStr = "BINDER_PROC_NAME: " + binderProcessNameStr + "\n";
}
binderInfo = binderInfo + binderProcessNameStr + binderProcessStackStr;
}
binderInfo += CatchASyncByPid(asyncPids, syncPids, pid);
std::string fileName = faultData.errorObject.name + "_" +
AbilityRuntime::TimeUtil::FormatTime("%Y%m%d%H%M%S") + "_" + std::to_string(pid) + "_binder";
std::string fullStackPath = WriteToFile(fileName, binderInfo);
binderInfo = fullStackPath + "," + binderPidsStr + "," + terminalBinderTid;
int ret = NotifyANR(faultNotifyData, appInfo, binderInfo, memoryContent);
return ret;
}
bool AppfreezeManager::IsAncoProc(int pid)
{
std::string cgroupPath = "/proc/" + std::to_string(pid) + "/cgroup";
std::string firstLine = GetFirstLine(cgroupPath);
return firstLine.find("isulad") != std::string::npos;
}
std::string AppfreezeManager::CatchASyncByPid(const std::set<int> &asyncPids, const std::set<int> &syncPids, int pid)
{
std::string binderInfo;
for (auto& pidTemp : asyncPids) {
int uid = AppfreezeUtil::GetUidByPid(pidTemp);
if (uid < 0 || uid >= MIN_APP_UID) {
TAG_LOGI(AAFwkTag::APPDFR, "Async stack, skip current pid:%{public}d, uid:%{public}d", pidTemp, uid);
continue;
}
TAG_LOGI(AAFwkTag::APPDFR, "AsyncBinder pidTemp pids:%{public}d", pidTemp);
if (pidTemp != pid && !IsAncoProc(pidTemp) && syncPids.find(pidTemp) == syncPids.end()) {
std::string content = "Binder catcher stacktrace, type is async, pid : " + std::to_string(pidTemp) + "\n";
content += CatcherStacktrace(pidTemp);
binderInfo += content;
}
}
return binderInfo;
}
std::string AppfreezeManager::ParseDecToHex(uint64_t id)
{
std::stringstream ss;
ss << std::hex << id;
return ss.str();
}
std::string AppfreezeManager::GetHitraceInfo()
{
#ifdef ABILITY_RUNTIME_HITRACE_ENABLE
OHOS::HiviewDFX::HiTraceId hitraceId = OHOS::HiviewDFX::HiTraceChain::GetId();
if (hitraceId.IsValid() == 0) {
TAG_LOGW(AAFwkTag::APPDFR, "get hitrace id is invalid.");
return "";
}
std::ostringstream hitraceIdStr;
hitraceIdStr << "hitrace_id: " << ParseDecToHex(hitraceId.GetChainId()) <<
", span_id: " << ParseDecToHex(hitraceId.GetSpanId()) <<
", parent_span_id: " << ParseDecToHex(hitraceId.GetParentSpanId()) <<
", trace_flag: " << ParseDecToHex(hitraceId.GetFlags());
std::string hiTraceIdInfo = hitraceIdStr.str();
TAG_LOGW(AAFwkTag::APPDFR, "hitraceIdStr: %{public}s", hiTraceIdInfo.c_str());
return hitraceIdStr.str();
#endif
return "";
}
void AppfreezeManager::InitWarningCpuInfo(const FaultData& faultData,
const AppfreezeManager::AppInfo& appInfo)
{
std::string eventName = faultData.errorObject.name;
if (eventName != AppFreezeType::THREAD_BLOCK_3S &&
eventName != AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
return;
}
std::string type = std::to_string(appInfo.pid) + "-" + std::to_string(appInfo.uid) + "-" +
appInfo.bundleName;
bool ret = AppExecFwk::AppfreezeCpuFreqManager::GetInstance().InsertCpuDetailInfo(type, appInfo.pid);
TAG_LOGI(AAFwkTag::APPDFR, "Insert cpuInfo ret:%{public}d, pid:%{public}d, name:%{public}s, "
"appfreezeInfo:%{public}s, type:%{public}s", ret, appInfo.pid,
eventName.c_str(), faultData.appfreezeInfo.c_str(), type.c_str());
}
std::string AppfreezeManager::GetAppfreezeInfoPath(const FaultData& faultData,
const AppfreezeManager::AppInfo& appInfo)
{
std::string eventName = faultData.errorObject.name;
std::string cpuInfoFile = faultData.appfreezeInfo;
if (eventName == AppFreezeType::THREAD_BLOCK_6S || eventName == AppFreezeType::LIFECYCLE_TIMEOUT ||
eventName == AppFreezeType::APP_INPUT_BLOCK) {
std::string type = std::to_string(appInfo.pid) + "-" + std::to_string(appInfo.uid) + "-" +
appInfo.bundleName;
cpuInfoFile += "," + AppExecFwk::AppfreezeCpuFreqManager::GetInstance().GetCpuInfoPath(
type, appInfo.bundleName, appInfo.uid, appInfo.pid);
TAG_LOGI(AAFwkTag::APPDFR, "name:%{public}s, cpuInfoFile:%{public}s, type:%{public}s",
faultData.errorObject.name.c_str(), cpuInfoFile.c_str(), type.c_str());
}
return cpuInfoFile;
}
AppfreezeEventInfo AppfreezeManager::UpdateEventInfo(
const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo,
const std::string& binderInfo, const std::string& memoryContent)
{
AppfreezeEventInfo eventInfo;
int tid = faultData.tid;
eventInfo.tid = tid > 0 ? tid : 0;
eventInfo.pid = appInfo.pid;
eventInfo.uid = appInfo.uid;
eventInfo.isFrozen = appInfo.isFrozen;
eventInfo.eventId = faultData.eventId;
eventInfo.bundleName = appInfo.bundleName;
eventInfo.processName = appInfo.processName;
eventInfo.binderInfo = binderInfo;
eventInfo.freezeMemory = memoryContent + "\n" + faultData.procStatm;
eventInfo.appRunningUniqueId = faultData.appRunningUniqueId;
eventInfo.errorStack = faultData.errorObject.stack;
eventInfo.mainStack = faultData.errorObject.mainStack;
eventInfo.errorName = faultData.errorObject.name;
eventInfo.errorMessage = faultData.errorObject.message;
eventInfo.freezeInfoFile = GetAppfreezeInfoPath(faultData, appInfo);
eventInfo.hitraceInfo = GetHitraceInfo();
eventInfo.foregroundState = faultData.isInForeground;
eventInfo.enableFreeze = faultData.isEnableMainThreadSample;
eventInfo.reportLifecycleToFreeze = faultData.reportLifecycleToFreeze;
eventInfo.applicationHeapInfo = faultData.applicationHeapInfo;
eventInfo.applicationGCInfo = faultData.applicationGCInfo;
eventInfo.applicationIOInfo = faultData.applicationIOInfo;
eventInfo.isBlockInGc = faultData.isBlockInGc;
eventInfo.processLifeTime = faultData.processLifeTime;
eventInfo.markedId = faultData.markedId;
eventInfo.processedId = faultData.processedId;
eventInfo.dispatchedEventId = faultData.dispatchedEventId;
eventInfo.externalLog = faultData.callbackLog;
return eventInfo;
}
int AppfreezeManager::NotifyANR(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo,
const std::string& binderInfo, const std::string& memoryContent)
{
std::string eventName = faultData.errorObject.name;
this->PerfStart(eventName);
int64_t startTime = AbilityRuntime::TimeUtil::CurrentTimeMillis();
AppfreezeEventInfo eventInfo = UpdateEventInfo(faultData, appInfo, binderInfo, memoryContent);
int ret = AppfreezeEventReport::SendAppfreezeEvent(eventName, HISYSEVENT_FAULT, eventInfo);
TAG_LOGW(AAFwkTag::APPDFR, "reportEvent:%{public}s, pid:%{public}d, tid:%{public}d, bundleName:%{public}s, "
"appRunningUniqueId:%{public}s, endTime:%{public}s, interval:%{public}" PRId64 " ms, "
"eventId:%{public}d freezeInfoFile:%{public}s foreground:%{public}d enableFreeze:%{public}d,"
" reportFreeze:%{public}d, applicationHeapInfo:%{public}s processLifeTime:%{public}s "
"hisysevent write ret: %{public}d",
faultData.errorObject.name.c_str(), appInfo.pid, faultData.tid, appInfo.bundleName.c_str(),
faultData.appRunningUniqueId.c_str(), AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str(),
AbilityRuntime::TimeUtil::CurrentTimeMillis() - startTime, faultData.eventId,
eventInfo.freezeInfoFile.c_str(), eventInfo.foregroundState, eventInfo.enableFreeze,
eventInfo.reportLifecycleToFreeze, eventInfo.applicationHeapInfo.c_str(),
eventInfo.processLifeTime.c_str(), ret);
OHOS::HiviewDFX::HiTraceChain::ClearId();
return 0;
}
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> AppfreezeManager::BinderParser(std::ifstream& fin,
std::string& stack, std::set<int>& asyncPids) const
{
std::map<uint32_t, uint32_t> asyncBinderMap;
std::vector<std::pair<uint32_t, uint64_t>> freeAsyncSpacePairs;
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> binderInfos = BinderLineParser(fin, stack,
asyncBinderMap, freeAsyncSpacePairs);
if (!g_overseaVersion) {
std::sort(freeAsyncSpacePairs.begin(), freeAsyncSpacePairs.end(),
[] (const auto& pairOne, const auto& pairTwo) { return pairOne.second < pairTwo.second; });
std::vector<std::pair<uint32_t, uint32_t>> asyncBinderPairs(asyncBinderMap.begin(), asyncBinderMap.end());
std::sort(asyncBinderPairs.begin(), asyncBinderPairs.end(),
[] (const auto& pairOne, const auto& pairTwo) { return pairOne.second > pairTwo.second; });
size_t freeAsyncSpaceSize = freeAsyncSpacePairs.size();
size_t asyncBinderSize = asyncBinderPairs.size();
size_t individualMaxSize = 2;
for (size_t i = 0; i < individualMaxSize; i++) {
if (i < freeAsyncSpaceSize) {
asyncPids.insert(freeAsyncSpacePairs[i].first);
}
if (i < asyncBinderSize) {
asyncPids.insert(asyncBinderPairs[i].first);
}
}
}
return binderInfos;
}
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> AppfreezeManager::BinderLineParser(std::ifstream& fin,
std::string& stack, std::map<uint32_t, uint32_t>& asyncBinderMap,
std::vector<std::pair<uint32_t, uint64_t>>& freeAsyncSpacePairs) const
{
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> binderInfos;
std::string line;
bool isBinderMatchup = false;
TAG_LOGI(AAFwkTag::APPDFR, "start");
stack += "BinderCatcher --\n\n";
while (getline(fin, line)) {
stack += line + "\n";
if (g_overseaVersion) {
continue;
}
isBinderMatchup = (!isBinderMatchup && line.find("free_async_space") != line.npos) ? true : isBinderMatchup;
std::vector<std::string> strList = GetFileToList(line);
if (isBinderMatchup) {
if (line.find("free_async_space") == line.npos && strList.size() == ARR_SIZE &&
std::atoll(strList[FREE_ASYNC_INDEX].c_str()) < FREE_ASYNC_MAX) {
freeAsyncSpacePairs.emplace_back(std::atoi(strList[0].c_str()),
std::atoll(strList[FREE_ASYNC_INDEX].c_str()));
}
} else if (line.find("async\t") != std::string::npos && strList.size() > ARR_SIZE) {
std::string serverPid = StrSplit(strList[3], 0);
std::string serverTid = StrSplit(strList[3], 1);
if (serverPid != "" && serverTid != "" && std::atoi(serverTid.c_str()) == 0) {
asyncBinderMap[std::atoi(serverPid.c_str())]++;
}
} else if (strList.size() >= ARR_SIZE) {
AppfreezeManager::PeerBinderInfo info = {0};
std::string clientPid = StrSplit(strList[0], 0);
std::string clientTid = StrSplit(strList[0], 1);
std::string serverPid = StrSplit(strList[2], 0);
std::string serverTid = StrSplit(strList[2], 1);
std::string wait = StrSplit(strList[5], 1);
if (clientPid == "" || clientTid == "" || serverPid == "" || serverTid == "" || wait == "") {
continue;
}
info = {std::strtol(clientPid.c_str(), nullptr, DECIMAL), std::strtol(clientTid.c_str(), nullptr, DECIMAL),
std::strtol(serverPid.c_str(), nullptr, DECIMAL), strtol(serverTid.c_str(), nullptr, DECIMAL)};
int waitTime = std::strtol(wait.c_str(), nullptr, DECIMAL);
TAG_LOGI(AAFwkTag::APPDFR, "server:%{public}d, client:%{public}d, wait:%{public}d", info.serverPid,
info.clientPid, waitTime);
binderInfos[info.clientPid].push_back(info);
}
}
TAG_LOGI(AAFwkTag::APPDFR, "binderInfos size: %{public}zu", binderInfos.size());
return binderInfos;
}
std::vector<std::string> AppfreezeManager::GetFileToList(std::string line) const
{
std::vector<std::string> strList;
std::istringstream lineStream(line);
std::string tmpstr;
while (lineStream >> tmpstr) {
strList.push_back(tmpstr);
}
TAG_LOGD(AAFwkTag::APPDFR, "strList size: %{public}zu", strList.size());
return strList;
}
std::string AppfreezeManager::StrSplit(const std::string& str, uint16_t index) const
{
std::vector<std::string> strings;
SplitStr(str, ":", strings);
return index < strings.size() ? strings[index] : "";
}
std::set<int> AppfreezeManager::GetBinderPeerPids(std::string& stack, AppfreezeManager::ParseBinderParam params,
std::set<int>& asyncPids, AppfreezeManager::TerminalBinder& terminalBinder) const
{
std::set<int> pids;
std::ifstream fin;
std::string path = LOGGER_DEBUG_PROC_PATH;
char resolvePath[PATH_MAX] = {0};
if (realpath(path.c_str(), resolvePath) == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "invalid realpath");
return pids;
}
fin.open(resolvePath);
if (!fin.is_open()) {
TAG_LOGE(AAFwkTag::APPDFR, "open failed, %{public}s", resolvePath);
stack += "open file failed :" + path + "\r\n";
return pids;
}
stack += "\n\nPeerBinderCatcher -- pid==" + std::to_string(params.pid) + "\n\n";
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> binderInfos = BinderParser(fin, stack, asyncPids);
fin.close();
if (g_overseaVersion || binderInfos.size() == 0 || binderInfos.find(params.pid) == binderInfos.end()) {
return pids;
}
ParseBinderPids(binderInfos, pids, params, true, terminalBinder);
for (auto& each : pids) {
TAG_LOGD(AAFwkTag::APPDFR, "each pids:%{public}d", each);
}
return pids;
}
void AppfreezeManager::ParseBinderPids(const std::map<int, std::list<AppfreezeManager::PeerBinderInfo>>& binderInfos,
std::set<int>& pids, AppfreezeManager::ParseBinderParam params, bool getTerminal,
AppfreezeManager::TerminalBinder& terminalBinder) const
{
auto it = binderInfos.find(params.pid);
params.layer++;
if (params.layer >= MAX_LAYER || it == binderInfos.end()) {
return;
}
for (auto& each : it->second) {
pids.insert(each.serverPid);
params.pid = each.serverPid;
if (getTerminal && ((each.clientPid == params.eventPid && each.clientTid == params.eventTid) ||
(each.clientPid == terminalBinder.pid && each.clientTid == terminalBinder.tid))) {
terminalBinder.pid = each.serverPid;
terminalBinder.tid = each.serverTid;
ParseBinderPids(binderInfos, pids, params, true, terminalBinder);
} else {
ParseBinderPids(binderInfos, pids, params, false, terminalBinder);
}
}
}
void AppfreezeManager::DeleteStack(int pid)
{
std::lock_guard<ffrt::mutex> lock(catchStackMutex_);
auto it = catchStackMap_.find(pid);
if (it != catchStackMap_.end()) {
catchStackMap_.erase(it);
}
}
void AppfreezeManager::FindStackByPid(std::string& msg, int pid) const
{
std::lock_guard<ffrt::mutex> lock(catchStackMutex_);
auto it = catchStackMap_.find(pid);
if (it != catchStackMap_.end()) {
msg = it->second;
}
}
bool AppfreezeManager::IsHalfTimeout(const std::string& faultType) const
{
if (faultType == AppFreezeType::THREAD_BLOCK_3S ||
faultType == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
return true;
}
return false;
}
std::pair<std::string, std::string> AppfreezeManager::CatchJsonStacktrace(int pid, const std::string& faultType) const
{
HITRACE_METER_FMT(HITRACE_TAG_APP, "CatchJsonStacktrace pid:%{public}d", pid);
HiviewDFX::DfxDumpCatcher dumplog;
std::string msg;
int timeout = IsHalfTimeout(faultType) ? 5000 : 3000;
int tid = 0;
std::pair<int, std::string> dumpResult = dumplog.DumpCatchWithTimeout(pid, msg, timeout, tid, true);
if (dumpResult.first == DUMP_STACK_FAILED) {
TAG_LOGI(AAFwkTag::APPDFR, "appfreeze catch json stacktrace failed, %{public}s", dumpResult.second.c_str());
msg = "Failed to dump stacktrace for " + std::to_string(pid) + "\n" + dumpResult.second + msg;
if (faultType == AppFreezeType::APP_INPUT_BLOCK) {
FindStackByPid(msg, pid);
}
} else {
if (dumpResult.first == DUMP_KERNEL_STACK_SUCCESS) {
msg = "Failed to dump normal stacktrace for " + std::to_string(pid) + "\n" + dumpResult.second +
"Kernel stack is:\n" + msg;
}
if (faultType == AppFreezeType::THREAD_BLOCK_3S) {
std::lock_guard<ffrt::mutex> lock(catchStackMutex_);
catchStackMap_[pid] = msg;
}
}
return std::make_pair(msg, dumpResult.second);
}
std::string AppfreezeManager::CatcherStacktrace(int pid) const
{
HITRACE_METER_FMT(HITRACE_TAG_APP, "CatcherStacktrace pid:%{public}d", pid);
HiviewDFX::DfxDumpCatcher dumplog;
std::string msg;
std::pair<int, std::string> dumpResult = dumplog.DumpCatchWithTimeout(pid, msg);
if (dumpResult.first == DUMP_STACK_FAILED) {
TAG_LOGI(AAFwkTag::APPDFR, "appfreeze catch stacktrace failed, %{public}s",
dumpResult.second.c_str());
msg = "Failed to dump stacktrace for " + std::to_string(pid) + "\n" + dumpResult.second + msg;
} else if (dumpResult.first == DUMP_KERNEL_STACK_SUCCESS) {
msg = "Failed to dump normal stacktrace for " + std::to_string(pid) + "\n" + dumpResult.second +
"Kernel stack is:\n" + msg;
}
return msg;
}
bool AppfreezeManager::IsProcessDebug(int32_t pid, std::string bundleName)
{
std::lock_guard<ffrt::mutex> lock(freezeFilterMutex_);
auto it = appfreezeFilterMap_.find(bundleName);
if (it != appfreezeFilterMap_.end() && it->second.pid == pid) {
bool result = (it->second.state == AppFreezeState::APPFREEZE_STATE_CANCELING);
TAG_LOGW(AAFwkTag::APPDFR, "AppfreezeFilter: %{public}d, "
"bundleName=%{public}s, pid:%{public}d, state:%{public}d, g_betaVersion:%{public}d,"
" g_developMode:%{public}d",
result, bundleName.c_str(), pid, it->second.state, g_betaVersion, g_developMode);
return result;
}
const int buffSize = 128;
char paramBundle[buffSize] = {0};
GetParameter("hiviewdfx.appfreeze.filter_bundle_name", "", paramBundle, buffSize - 1);
std::string debugBundle(paramBundle);
if (bundleName.compare(debugBundle) == 0) {
TAG_LOGI(AAFwkTag::APPDFR, "filtration %{public}s_%{public}s not exit",
debugBundle.c_str(), bundleName.c_str());
return true;
}
return false;
}
int64_t AppfreezeManager::GetFreezeCurrentTime()
{
struct timespec t;
t.tv_sec = 0;
t.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &t);
return static_cast<int64_t>(((t.tv_sec) * NANOSECONDS + t.tv_nsec) / MICROSECONDS);
}
void AppfreezeManager::SetFreezeState(const std::string& key, int state, const std::string& eventName)
{
if (eventName == AppFreezeType::THREAD_BLOCK_3S ||
eventName == AppFreezeType::BUSSINESS_THREAD_BLOCK_3S) {
return;
}
AppFreezeInfo info;
info.state = state;
info.occurTime = GetFreezeCurrentTime();
std::lock_guard<ffrt::mutex> lock(freezeMutex_);
appfreezeInfo_[key] = info;
}
int AppfreezeManager::GetReportTimes(const std::string& key)
{
int reportTimes = DEFAULT_APPFREEZE_REPORT_TIMES;
std::lock_guard<ffrt::mutex> lock(freezeMutex_);
auto it = appfreezeInfo_.find(key);
if (it != appfreezeInfo_.end()) {
reportTimes += it->second.reportTimes;
appfreezeInfo_[key].reportTimes = reportTimes;
}
return reportTimes;
}
int64_t AppfreezeManager::GetLastOccurTime(const std::string& key)
{
std::lock_guard<ffrt::mutex> lock(freezeMutex_);
auto it = appfreezeInfo_.find(key);
if (it != appfreezeInfo_.end()) {
return it->second.occurTime;
}
return 0;
}
bool AppfreezeManager::ClearOldInfo(std::map<std::string, AppFreezeInfo>& infoMap,
size_t maxSize, int64_t maxTimelimit)
{
if (infoMap.size() < maxSize) {
return true;
}
int removeCount = 0;
int64_t curTime = GetFreezeCurrentTime();
for (auto it = infoMap.begin(); it != infoMap.end();) {
auto interval = curTime - it->second.occurTime;
if (interval > maxTimelimit || interval < 0) {
it = infoMap.erase(it);
removeCount++;
} else {
++it;
}
}
TAG_LOGI(AAFwkTag::APPDFR, "remove old count: %{public}d, "
"current info count: %{public}zu", removeCount, infoMap.size());
return removeCount != 0;
}
bool AppfreezeManager::IsNeedIgnoreFreezeEvent(const std::string& key, const std::string& eventName,
int maxReportTimes)
{
int state = 0;
{
std::lock_guard<ffrt::mutex> lock(freezeMutex_);
if (!ClearOldInfo(appfreezeInfo_, FREEZEMAP_SIZE_MAX, FREEZE_TIME_LIMIT)) {
return false;
}
auto it = appfreezeInfo_.find(key);
state = it != appfreezeInfo_.end() ? it->second.state : AppFreezeState::APPFREEZE_STATE_IDLE;
}
if (state == AppFreezeState::APPFREEZE_STATE_FREEZE) {
auto diff = GetFreezeCurrentTime() - GetLastOccurTime(key);
int reportTimes = GetReportTimes(key);
TAG_LOGW(AAFwkTag::APPDFR, "durationTime: %{public}" PRId64 " eventName: %{public}s "
"reportTimes: %{public}d key: %{public}s",
diff, eventName.c_str(), reportTimes, key.c_str());
if (diff >= 0 && diff <= FREEZE_TIME_LIMIT) {
return reportTimes > maxReportTimes;
}
}
SetFreezeState(key, AppFreezeState::APPFREEZE_STATE_FREEZE, eventName);
TAG_LOGI(AAFwkTag::APPDFR, "Set freeze info, eventName: %{public}s key: %{public}s",
eventName.c_str(), key.c_str());
return false;
}
int AppfreezeManager::ClearOldInputBlockFreezeInfo(size_t maxSize, int64_t maxTimelimit)
{
if (appInputBlockFreezeInfo_.size() <= maxSize) {
return 0;
}
int ret = 0;
int64_t curTime = GetFreezeCurrentTime();
for (auto it = appInputBlockFreezeInfo_.begin(); it != appInputBlockFreezeInfo_.end();) {
auto interval = curTime - it->second;
if (interval > maxTimelimit || interval < 0) {
it = appInputBlockFreezeInfo_.erase(it);
ret++;
} else {
++it;
}
}
return ret;
}
bool AppfreezeManager::IsNeedIgnoreInputBlockEvent(const std::string& key)
{
std::lock_guard<ffrt::mutex> lock(freezeMutex_);
ClearOldInputBlockFreezeInfo(FREEZEMAP_SIZE_MAX, FREEZE_TIME_LIMIT);
int64_t curTime = GetFreezeCurrentTime();
auto it = appInputBlockFreezeInfo_.find(key);
if (it != appInputBlockFreezeInfo_.end()) {
int64_t lastTime = it->second;
int64_t diff = curTime - lastTime;
if (diff >= 0 && diff <= FREEZE_TIME_LIMIT) {
return true;
}
}
appInputBlockFreezeInfo_[key] = curTime;
TAG_LOGI(AAFwkTag::APPDFR, "Set input block info, key: %{public}s", key.c_str());
return false;
}
bool AppfreezeManager::CancelAppFreezeDetect(int32_t pid, const std::string& bundleName)
{
if (bundleName.empty()) {
TAG_LOGE(AAFwkTag::APPDFR, "SetAppFreezeFilter: failed, bundleName is empty.");
return false;
}
std::lock_guard<ffrt::mutex> lock(freezeFilterMutex_);
AppFreezeInfo info;
info.pid = pid;
info.state = AppFreezeState::APPFREEZE_STATE_CANCELING;
appfreezeFilterMap_[bundleName] = info;
TAG_LOGI(AAFwkTag::APPDFR, "SetAppFreezeFilter: success, bundleName=%{public}s, "
"pid:%{public}d, state:%{public}d", bundleName.c_str(), info.pid, info.state);
return true;
}
void AppfreezeManager::RemoveDeathProcess(std::string bundleName)
{
std::lock_guard<ffrt::mutex> lock(freezeFilterMutex_);
auto it = appfreezeFilterMap_.find(bundleName);
if (it != appfreezeFilterMap_.end()) {
TAG_LOGI(AAFwkTag::APPDFR, "RemoveAppFreezeFilter:success, bundleName: %{public}s",
bundleName.c_str());
appfreezeFilterMap_.erase(it);
} else {
TAG_LOGD(AAFwkTag::APPDFR, "RemoveAppFreezeFilter:failed, not found bundleName: "
"%{public}s", bundleName.c_str());
}
}
void AppfreezeManager::ResetAppfreezeState(int32_t pid, const std::string& bundleName)
{
std::lock_guard<ffrt::mutex> lock(freezeFilterMutex_);
if (appfreezeFilterMap_.find(bundleName) != appfreezeFilterMap_.end()) {
appfreezeFilterMap_[bundleName].state = AppFreezeState::APPFREEZE_STATE_CANCELED;
}
TAG_LOGI(AAFwkTag::APPDFR, "SetAppFreezeFilter: reset state, "
"bundleName=%{public}s, pid:%{public}d, state:%{public}d",
bundleName.c_str(), pid, appfreezeFilterMap_[bundleName].state);
}
bool AppfreezeManager::IsValidFreezeFilter(int32_t pid, const std::string& bundleName)
{
if (g_betaVersion || g_developMode) {
TAG_LOGI(AAFwkTag::APPDFR, "SetAppFreezeFilter: "
"current device is beta or development");
return true;
}
std::lock_guard<ffrt::mutex> lock(freezeFilterMutex_);
bool ret = appfreezeFilterMap_.find(bundleName) == appfreezeFilterMap_.end();
TAG_LOGI(AAFwkTag::APPDFR, "SetAppFreezeFilter: %{public}d, bundleName=%{public}s, "
"pid:%{public}d", ret, bundleName.c_str(), pid);
return ret;
}
void AppfreezeManager::ReportAppFreezeSysEvents(int32_t pid, const std::string& bundleName)
{
std::lock_guard<std::mutex> mapLock(freezeMapMutex_);
if (freezeEventMap_.find(pid) == freezeEventMap_.end()) {
return;
}
uint64_t now = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count());
auto hisyseventReport = std::make_shared<AAFwk::HisyseventReport>(40);
hisyseventReport->InsertParam("THREAD_HALF_SCHED",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_ZERO]].schedTime);
hisyseventReport->InsertParam("THREAD_HALF_DETECT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_ZERO]].detectTime);
hisyseventReport->InsertParam("THREAD_HALF_DUMP_START",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_ZERO]].dumpStartTime);
hisyseventReport->InsertParam("THREAD_HALF_DUMP_FINISH",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_ZERO]].dumpFinishTime);
hisyseventReport->InsertParam("THREAD_HALF_DUMP_RESULT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_ZERO]].dumpResult);
hisyseventReport->InsertParam("THREAD_HALF_APP_STATUS",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_ZERO]].appStatus);
hisyseventReport->InsertParam("THREAD_TIMEOUT_SCHED",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FIRST]].schedTime);
hisyseventReport->InsertParam("THREAD_TIMEOUT_DETECT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FIRST]].detectTime);
hisyseventReport->InsertParam("THREAD_TIMEOUT_DUMP_START",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FIRST]].dumpStartTime);
hisyseventReport->InsertParam("THREAD_TIMEOUT_DUMP_FINISH",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FIRST]].dumpFinishTime);
hisyseventReport->InsertParam("THREAD_TIMEOUT_DUMP_RESULT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FIRST]].dumpResult);
hisyseventReport->InsertParam("THREAD_TIMEOUT_APP_STATUS",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FIRST]].appStatus);
hisyseventReport->InsertParam("INPUT_SCHED",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_SED]].schedTime);
hisyseventReport->InsertParam("INPUT_DETECT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_SED]].detectTime);
hisyseventReport->InsertParam("INPUT_DUMP_START",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_SED]].dumpStartTime);
hisyseventReport->InsertParam("INPUT_DUMP_FINISH",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_SED]].dumpFinishTime);
hisyseventReport->InsertParam("INPUT_DUMP_RESULT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_SED]].dumpResult);
hisyseventReport->InsertParam("INPUT_APP_STATUS",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_SED]].appStatus);
hisyseventReport->InsertParam("LIFECYCLE_HALF_SCHED",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_THIRD]].schedTime);
hisyseventReport->InsertParam("LIFECYCLE_HALF_DETECT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_THIRD]].detectTime);
hisyseventReport->InsertParam("LIFECYCLE_HALF_DUMP_START",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_THIRD]].dumpStartTime);
hisyseventReport->InsertParam("LIFECYCLE_HALF_DUMP_FINISH",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_THIRD]].dumpFinishTime);
hisyseventReport->InsertParam("LIFECYCLE_HALF_DUMP_RESULT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_THIRD]].dumpResult);
hisyseventReport->InsertParam("LIFECYCLE_HALF_APP_STATUS",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_THIRD]].appStatus);
hisyseventReport->InsertParam("LIFECYCLE_TIMEOUT_SCHED",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FORTH]].schedTime);
hisyseventReport->InsertParam("LIFECYCLE_TIMEOUT_DETECT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FORTH]].detectTime);
hisyseventReport->InsertParam("LIFECYCLE_TIMEOUT_DUMP_START",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FORTH]].dumpStartTime);
hisyseventReport->InsertParam("LIFECYCLE_TIMEOUT_DUMP_FINISH",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FORTH]].dumpFinishTime);
hisyseventReport->InsertParam("LIFECYCLE_TIMEOUT_DUMP_RESULT",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FORTH]].dumpResult);
hisyseventReport->InsertParam("LIFECYCLE_TIMEOUT_APP_STATUS",
freezeEventMap_[pid][APP_FREEZE_EVENT_NAME[FREEZE_EVENT_FORTH]].appStatus);
hisyseventReport->InsertParam("APP_KILL_TIME",
freezeEventMap_[pid][KILL_EVENT_NAME].schedTime);
hisyseventReport->InsertParam("APP_TERMINATED_TIME", now);
hisyseventReport->InsertParam("SAMPLER_START",
freezeEventMap_[pid][KILL_EVENT_NAME].dumpStartTime);
hisyseventReport->InsertParam("SAMPLER_FINISH",
freezeEventMap_[pid][KILL_EVENT_NAME].dumpFinishTime);
hisyseventReport->InsertParam("SAMPLER_COUNT",
freezeEventMap_[pid][KILL_EVENT_NAME].dumpResult);
hisyseventReport->InsertParam("BUNDLE_NAME", bundleName);
hisyseventReport->InsertParam("APP_PID", pid);
hisyseventReport->InsertParam("REPEAT_KILLED_THREAD",
freezeEventMap_[pid][KILL_EVENT_NAME].isRepeatKilledThread);
int ret = hisyseventReport->Report("RELIABILITY", "APP_FREEZE_STATISTICS", HISYSEVENT_STATISTIC);
freezeEventMap_.erase(pid);
}
void AppfreezeManager::RegisterAppKillTime(int32_t pid, uint64_t time)
{
std::lock_guard<std::mutex> mapLock(freezeMapMutex_);
if (freezeEventMap_.find(pid) == freezeEventMap_.end()) {
return;
}
freezeEventMap_[pid][KILL_EVENT_NAME].schedTime = time;
}
void AppfreezeManager::PerfStart(std::string eventName)
{
if (OHOS::system::GetParameter("const.dfx.sub_health_recovery.enable", "") != "true") {
TAG_LOGI(AAFwkTag::APPDFR, "sub_health_recovery is not enable");
return;
}
auto it = HALF_EVENT_CONFIGS.find(eventName);
if (it == HALF_EVENT_CONFIGS.end()) {
return;
}
auto curTime = AbilityRuntime::TimeUtil::SystemTimeMillisecond();
if (curTime - perfTime < PERF_TIME) {
TAG_LOGE(AAFwkTag::APPDFR, "perf time is less than 60s");
return;
}
std::string bigCpuCurFreq = this->GetFirstLine(TWELVE_BIG_CPU_CUR_FREQ);
std::string bigCpuMaxFreq = this->GetFirstLine(TWELVE_BIG_CPU_MAX_FREQ);
std::string midCpuCurFreq = this->GetFirstLine(TWELVE_MID_CPU_CUR_FREQ);
std::string midCpuMaxFreq = this->GetFirstLine(TWELVE_MID_CPU_MAX_FREQ);
if (bigCpuCurFreq == bigCpuMaxFreq || midCpuCurFreq == midCpuMaxFreq) {
perfTime = curTime;
TAG_LOGI(AAFwkTag::APPDFR, "perf start");
AAFwk::ResSchedUtil::GetInstance().ReportSubHealtyPerfInfoToRSS();
TAG_LOGI(AAFwkTag::APPDFR, "perf end");
}
}
std::string AppfreezeManager::GetFirstLine(const std::string &path)
{
std::string realPath = AppfreezeUtil::FreezePathToRealPath(path);
if (realPath.empty()) {
return "";
}
std::ifstream inFile(realPath.c_str());
if (!inFile) {
return "";
}
std::string firstLine;
getline(inFile, firstLine);
inFile.close();
return firstLine;
}
bool AppfreezeManager::CheckInBackGround(const FaultData &faultData)
{
return faultData.errorObject.name == AppFreezeType::THREAD_BLOCK_6S &&
!faultData.isInForeground;
}
bool AppfreezeManager::CheckAppfreezeHappend(const std::string& key, const std::string& eventName)
{
bool result = false;
if (eventName == AppFreezeType::LIFECYCLE_TIMEOUT ||
eventName == AppFreezeType::THREAD_BLOCK_6S || eventName == AppFreezeType::THREAD_BLOCK_3S ||
eventName == AppFreezeType::BUSSINESS_THREAD_BLOCK_3S ||
eventName == AppFreezeType::BUSSINESS_THREAD_BLOCK_6S) {
result = IsNeedIgnoreFreezeEvent(key, eventName);
} else if (eventName == AppFreezeType::LIFECYCLE_HALF_TIMEOUT_WARNING ||
eventName == AppFreezeType::LIFECYCLE_TIMEOUT_WARNING) {
std::string warningKey = eventName;
result = IsNeedIgnoreFreezeEvent(warningKey, eventName);
} else if (eventName == AppFreezeType::APP_INPUT_BLOCK) {
#ifdef APP_NO_RESPONSE_DIALOG
result = IsNeedIgnoreInputBlockEvent(key);
#else
result = IsNeedIgnoreFreezeEvent(key, eventName);
#endif
}
if (result) {
TAG_LOGE(AAFwkTag::APPDFR, "appFreeze happend, key:%{public}s, eventName:%{public}s",
key.c_str(), eventName.c_str());
}
return result;
}
bool AppfreezeManager::CheckNeedRecordAppRunningUnquieId(const std::string& eventName)
{
if (eventName == AppFreezeType::THREAD_BLOCK_3S || eventName == AppFreezeType::THREAD_BLOCK_6S ||
eventName == AppFreezeType::BUSSINESS_THREAD_BLOCK_3S ||
eventName == AppFreezeType::BUSSINESS_THREAD_BLOCK_6S ||
eventName == AppFreezeType::BUSINESS_INPUT_BLOCK) {
return true;
}
return false;
}
bool AppfreezeManager::IsBetaVersion()
{
return g_betaVersion;
}
void AppfreezeManager::InsertKillThread(int32_t state, int32_t pid, int32_t uid, const std::string& bundleName)
{
std::string key = bundleName + AppfreezeUtil::KEY_SEPARATOR + std::to_string(pid) +
AppfreezeUtil::KEY_SEPARATOR + std::to_string(uid);
std::lock_guard<std::mutex> mapLock(freezeKillThreadMutex_);
if (!ClearOldInfo(freezeKillThreadMap_, FREEZEMAP_SIZE_MAX, FREEZE_TIME_LIMIT)) {
return;
}
if (freezeKillThreadMap_.find(key) != freezeKillThreadMap_.end()) {
freezeKillThreadMap_[key].state = state;
freezeKillThreadMap_[key].occurTime = GetFreezeCurrentTime();
} else {
AppFreezeInfo info;
info.state = state;
info.occurTime = GetFreezeCurrentTime();
freezeKillThreadMap_[key] = info;
}
TAG_LOGI(AAFwkTag::APPDFR, "insert or update key: %{public}s", key.c_str());
}
bool AppfreezeManager::CheckThreadKilled(int32_t pid, int32_t uid, const std::string& bundleName)
{
std::string key = bundleName + AppfreezeUtil::KEY_SEPARATOR + std::to_string(pid) +
AppfreezeUtil::KEY_SEPARATOR + std::to_string(uid);
bool result = false;
bool isRepeatKilledThread = false;
{
std::lock_guard<std::mutex> mapLock(freezeKillThreadMutex_);
if (freezeKillThreadMap_.empty()) {
return result;
}
auto it = freezeKillThreadMap_.find(key);
if (it != freezeKillThreadMap_.end()) {
result = it->second.state >= 0;
if (result && !it->second.isRepeatKilledThread) {
it->second.isRepeatKilledThread = true;
isRepeatKilledThread = true;
}
}
}
if (isRepeatKilledThread) {
{
std::lock_guard<std::mutex> mapLock(freezeMapMutex_);
if (freezeEventMap_.find(pid) != freezeEventMap_.end()) {
freezeEventMap_[pid][KILL_EVENT_NAME].isRepeatKilledThread = true;
}
}
ReportAppFreezeSysEvents(pid, bundleName);
}
return result;
}
bool AppfreezeManager::IsSkipDetect(int32_t pid, int32_t uid, const std::string& bundleName,
const std::string& eventName)
{
if (CheckThreadKilled(pid, uid, bundleName)) {
TAG_LOGW(AAFwkTag::APPDFR, "bundleName: %{public}s has been killed, pid: %{public}d",
bundleName.c_str(), pid);
return true;
}
if (IsProcessDebug(pid, bundleName)) {
TAG_LOGW(AAFwkTag::APPDFR, "don't report event and kill:%{public}s, pid:%{public}d, bundleName:%{public}s",
eventName.c_str(), pid, bundleName.c_str());
return true;
}
return false;
}
AppfreezeManager::ProcessKillInfo AppfreezeManager::GetProcessKillReason(
int32_t killId, int32_t pid, const std::string& killMsg)
{
AppfreezeManager::ProcessKillInfo killInfo = {
.killReason = "",
.killMsg = "",
.adj = 0,
.timestamp = 0,
.killId = killId,
.eventParamFirst = 0,
.eventParamSecond = 0,
.eventParamThird = 0,
.eventParamFourth = 0,
.eventParamFifth = 0,
.eventParamSixth = 0,
.eventParamSeventh = 0,
};
if (killId == INVALID_KILL_ID) {
killInfo.killReason = INVALID_KILL_REASON;
killInfo.killMsg = killMsg + " " + std::string(INVALID_KILL_REASON) + ":" + std::to_string(killId);
} else if (killId < 0) {
GetExitKernelReason(pid, killInfo);
} else {
killInfo.killReason = HiviewDFX::ProcessKillReason::GetKillReason(killId);
killInfo.killMsg = killMsg;
}
return killInfo;
}
void AppfreezeManager::GetExitKernelReason(int32_t pid, ProcessKillInfo& killInfo)
{
int sysloadFd = open(DEV_SYSLOAD, O_RDWR);
if (sysloadFd < 0) {
TAG_LOGW(AAFwkTag::APPDFR, "open failed, errno:%{public}d", errno);
return;
}
fdsan_exchange_owner_tag(sysloadFd, 0, FREEZE_DOMAIN);
KillInfo info = {0};
info.magic = SYSLOAD_GET_KILL_INFO_MAGIC;
info.pid = pid;
info.structSize = sizeof(struct KillInfo);
int res = ioctl(sysloadFd, GET_KILL_INFO, &info);
if (fdsan_close_with_tag(sysloadFd, FREEZE_DOMAIN) != 0) {
TAG_LOGW(AAFwkTag::APPDFR, "GetExitKernelReason fdsan close failed, errno:%{public}d", errno);
}
int killId = -1;
if (res == 0) {
killId = static_cast<int>(info.data.id);
killInfo.adj = static_cast<int>(info.data.adj);
killInfo.timestamp = static_cast<int64_t>(info.data.timestamp);
killInfo.killReason = HiviewDFX::ProcessKillReason::GetKillReason(killId);
killInfo.killId = killId;
killInfo.eventParamFirst = static_cast<int64_t>(info.data.eventParamFirst);
killInfo.eventParamSecond = static_cast<int64_t>(info.data.eventParamSecond);
killInfo.eventParamThird = static_cast<int64_t>(info.data.eventParamThird);
killInfo.eventParamFourth = static_cast<int64_t>(info.data.eventParamFourth);
killInfo.eventParamFifth = static_cast<int64_t>(info.data.eventParamFifth);
killInfo.eventParamSixth = static_cast<int64_t>(info.data.eventParamSixth);
killInfo.eventParamSeventh = static_cast<int64_t>(info.data.eventParamSeventh);
int kernelPid = static_cast<int>(info.data.pid);
TAG_LOGI(AAFwkTag::APPDFR, "Get killReason success, killId:%{public}d, adj:%{public}d, "
"timestamp:%{public}" PRId64 ", killReason:%{public}s, ioctlPid:%{public}d, pid:%{public}d "
"paramFirst:%{public}" PRId64 ", paramSecond:%{public}" PRId64 ", paramThird:%{public}" PRId64 ", "
"paramFourth:%{public}" PRId64 ", paramFifth:%{public}" PRId64 ", paramSixth:%{public}" PRId64 ", "
"paramSeventh:%{public}" PRId64,
killId, killInfo.adj, killInfo.timestamp, killInfo.killReason.c_str(), kernelPid, pid,
killInfo.eventParamFirst, killInfo.eventParamSecond, killInfo.eventParamThird, killInfo.eventParamFourth,
killInfo.eventParamFifth, killInfo.eventParamSixth, killInfo.eventParamSeventh);
} else {
killInfo.killReason = INVALID_KILL_REASON;
TAG_LOGW(AAFwkTag::APPDFR, "Get killReason ioctl failed, errno:%{public}d", errno);
}
}
int AppfreezeManager::GetFreezeExitReason(const std::string& eventName)
{
if (eventName == AppFreezeType::THREAD_BLOCK_6S) {
return HiviewDFX::ProcessKillReason::KillEventId::REASON_THREAD_BLOCK_6S;
}
if (eventName == AppFreezeType::LIFECYCLE_TIMEOUT) {
return HiviewDFX::ProcessKillReason::KillEventId::REASON_LIFECYCLE_TIMEOUT;
}
if (eventName == AppFreezeType::APP_INPUT_BLOCK) {
return HiviewDFX::ProcessKillReason::KillEventId::REASON_APP_INPUT_BLOCK;
}
if (eventName == AppFreezeType::BUSSINESS_THREAD_BLOCK_6S) {
return HiviewDFX::ProcessKillReason::KillEventId::REASON_BUSINESS_THREAD_BLOCK_6S;
}
if (eventName == AppFreezeType::BUSINESS_INPUT_BLOCK) {
return HiviewDFX::ProcessKillReason::KillEventId::REASON_BUSINESS_INPUT_BLOCK;
}
return UNKNOWN_FREEZE_REASON;
}
void AppfreezeManager::UpdateFreezeExcludedPid(bool isAdd, int32_t targetPid, int32_t profilerPid)
{
std::lock_guard<ffrt::mutex> lock(freezeExcludedPidMutex_);
if (isAdd) {
FreezeExcludedPidInfo info;
info.targetPid = targetPid;
info.profilerPid = profilerPid;
info.timestamp = GetFreezeCurrentTime();
freezeExcludedPidMap_[targetPid] = info;
TAG_LOGI(AAFwkTag::APPDFR, "Add to freezeExcludedPidMap: targetPid=%{public}d, profilerPid=%{public}d",
targetPid, profilerPid);
if (freezeExcludedPidMap_.size() > FREEZE_EXCLUDED_PID_MAX_SIZE) {
CleanOldFreezeExcludedPids();
}
} else {
freezeExcludedPidMap_.erase(targetPid);
TAG_LOGI(AAFwkTag::APPDFR, "Remove from freezeExcludedPidMap: targetPid=%{public}d", targetPid);
}
}
void AppfreezeManager::CleanOldFreezeExcludedPids()
{
std::vector<std::pair<int32_t, int64_t>> pidTimePairs;
for (const auto& pair : freezeExcludedPidMap_) {
pidTimePairs.emplace_back(pair.first, pair.second.timestamp);
}
std::sort(pidTimePairs.begin(), pidTimePairs.end(),
[](const auto& a, const auto& b) { return a.second < b.second; });
size_t cleanCount = std::min(FREEZE_EXCLUDED_PID_CLEAN_COUNT, pidTimePairs.size());
for (size_t i = 0; i < cleanCount; i++) {
freezeExcludedPidMap_.erase(pidTimePairs[i].first);
TAG_LOGI(AAFwkTag::APPDFR, "Clean old freezeExcludedPid: targetPid=%{public}d", pidTimePairs[i].first);
}
}
bool AppfreezeManager::IsNativeDaemonProcess(int32_t profilerPid) const
{
std::string processName = AppfreezeUtil::GetProcessNameByPid(profilerPid);
return processName == NATIVE_DAEMON_PROCESS_NAME;
}
bool AppfreezeManager::IsFreezeExcludedPid(int32_t targetPid)
{
std::lock_guard<ffrt::mutex> lock(freezeExcludedPidMutex_);
auto it = freezeExcludedPidMap_.find(targetPid);
if (it == freezeExcludedPidMap_.end()) {
return false;
}
int32_t profilerPid = it->second.profilerPid;
if (AppfreezeUtil::GetUidByPid(profilerPid) < 0) {
TAG_LOGW(AAFwkTag::APPDFR, "profilerPid %{public}d not exist, remove targetPid %{public}d",
profilerPid, targetPid);
freezeExcludedPidMap_.erase(it);
return false;
}
if (!IsNativeDaemonProcess(profilerPid)) {
TAG_LOGW(AAFwkTag::APPDFR, "profilerPid %{public}d is not native_daemon, remove targetPid %{public}d",
profilerPid, targetPid);
freezeExcludedPidMap_.erase(it);
return false;
}
TAG_LOGW(AAFwkTag::APPDFR, "pid %{public}d is in freeze excluded list", targetPid);
return true;
}
bool AppfreezeManager::CheckPreloadUIExtension(const std::string& message, const std::string& bundleName,
int32_t pid, const std::string& eventName)
{
if (eventName != AppFreezeType::LIFECYCLE_HALF_TIMEOUT && eventName != AppFreezeType::LIFECYCLE_TIMEOUT) {
return false;
}
if (message.find(PRELOAD_UIEXTENSION) != std::string::npos) {
TAG_LOGW(AAFwkTag::APPDFR, "don't report event, msg: PreloadUIExtension, bundleName: %{public}s "
"pid: %{public}d", bundleName.c_str(), pid);
return true;
}
return false;
}
bool AppfreezeManager::CheckProcessExit(const std::string& processName, const std::string& eventName, bool foreground)
{
return foreground || eventName != AppFreezeType::THREAD_BLOCK_6S || processName == "com.ohos.sceneboard";
}
}
}