* Copyright (c) 2023-2024 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_inner.h"
#include <sys/time.h>
#include <sstream>
#include "ability_manager_client.h"
#include "ability_state.h"
#include "appfreeze_manager.h"
#include "app_recovery.h"
#include "backtrace_local.h"
#include "file_ex.h"
#include "freeze_util.h"
#include "hilog_tag_wrapper.h"
#include "hitrace_meter.h"
#include "hisysevent_report.h"
#include "js_runtime.h"
#include "ohos_application.h"
#include "parameter.h"
#include "xcollie/watchdog.h"
#include "time_util.h"
#include "parameters.h"
#include "unique_fd.h"
#include "input_manager.h"
#include "exit_reason.h"
#include "dfx_jsnapi.h"
namespace OHOS {
using AbilityRuntime::FreezeUtil;
namespace AppExecFwk {
namespace {
constexpr int32_t HALF_DURATION = 3000;
constexpr int32_t HALF_INTERVAL = 300;
const bool BETA_VERSION = OHOS::system::GetParameter("const.logsystem.versiontype", "unknown") == "beta";
constexpr int32_t APPFREEZE_INNER_TASKWORKER_NUM = 1;
static constexpr const char *const HEAP_TOTAL_SIZE = "HEAP_TOTAL_SIZE";
static constexpr const char *const HEAP_OBJECT_SIZE = "HEAP_OBJECT_SIZE";
static constexpr const char *const HEAP_SHARED_SIZE = "HEAP_SHARED_SIZE";
static constexpr const char *const PROCESS_LIFETIME = "PROCESS_LIFETIME";
static constexpr const char *const COLON_SEPARATOR = ":";
static constexpr const char *const COMMA_SEPARATOR = ",";
static constexpr const char *const SECOND = "s";
static constexpr const char *const GC_COUNT = "count";
static constexpr const char *const GC_MAX_PAUSE = "maxPause";
static constexpr const char *const GC_MIN_PAUSE = "minPause";
static constexpr const char *const GC_AVERAGE_PAUSE = "averagePause";
static constexpr const char *const GC_LAST_START_TIME = "lastStartTime";
static constexpr const char *const GC_LAST_END_TIME = "lastEndTime";
static constexpr const char *const GC_LAST_TYPE = "lastType";
static constexpr const char *const GC_SHARED_GC_TYPE = "Shared GC";
static constexpr const char *const PROC_SELF_IO = "/proc/self/io";
constexpr int THREAD_BLOCK_3S_TYPE = 0;
constexpr int THREAD_BLOCK_6S_TYPE = 1;
constexpr int LIFECYCLE_HALF_TIMEOUT_TYPE = 2;
constexpr int LIFECYCLE_TIMEOUT_TYPE = 3;
constexpr int APP_INPUT_BLOCK_TYPE = 4;
constexpr int BUSSINESS_THREAD_BLOCK_3S_TYPE = 5;
constexpr int BUSSINESS_THREAD_BLOCK_6S_TYPE = 6;
constexpr int BUSINESS_INPUT_BLOCK_TYPE = 7;
constexpr int DUMP_MAIN_STACK_TIMEOUT = 1;
constexpr int LAST_SAVE_MAIN_STACK_TIME = 3000;
constexpr uint64_t APP_INPUT_BLOCK_TIME = 8000;
}
std::weak_ptr<EventHandler> AppfreezeInner::appMainHandler_;
std::shared_ptr<AppfreezeInner> AppfreezeInner::instance_ = nullptr;
std::mutex AppfreezeInner::singletonMutex_;
AppfreezeInner::AppfreezeInner()
{
appfreezeInnerTaskHandler_ = AAFwk::TaskHandlerWrap::CreateConcurrentQueueHandler(
"app_freeze_inner_task_queue", APPFREEZE_INNER_TASKWORKER_NUM, AAFwk::TaskQoS::USER_INITIATED);
appfreezeInnerTaskHandler_->SetPrintTaskLog(true);
}
AppfreezeInner::~AppfreezeInner()
{}
void AppfreezeInner::SetMainHandler(const std::shared_ptr<EventHandler>& eventHandler)
{
appMainHandler_ = eventHandler;
}
void AppfreezeInner::SetApplicationInfo(const std::shared_ptr<ApplicationInfo>& applicationInfo)
{
applicationInfo_ = applicationInfo;
}
std::shared_ptr<AppfreezeInner> AppfreezeInner::GetInstance()
{
if (instance_ == nullptr) {
std::lock_guard<std::mutex> lock(singletonMutex_);
if (instance_ == nullptr) {
instance_ = std::make_shared<AppfreezeInner>();
}
}
return instance_;
}
void AppfreezeInner::DestroyInstance()
{
std::lock_guard<std::mutex> lock(singletonMutex_);
if (instance_ != nullptr) {
instance_.reset();
instance_ = nullptr;
}
}
bool AppfreezeInner::IsHandleAppfreeze()
{
return !isAppDebug_;
}
bool AppfreezeInner::IsProcessDebug(int32_t pid, std::string bundleName)
{
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;
}
std::string AppfreezeInner::GetBundleNameByApplication()
{
auto applicationInfo = applicationInfo_.lock();
if (applicationInfo == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "null applicationInfo_");
return "";
}
return applicationInfo->bundleName;
}
std::string AppfreezeInner::GetProcStatm(int32_t pid)
{
std::string procStatm;
std::ifstream statmStream("/proc/" + std::to_string(pid) + "/statm");
if (statmStream) {
std::getline(statmStream, procStatm);
statmStream.close();
}
return procStatm;
}
void AppfreezeInner::GetMainHandlerDump(std::string& msgContent)
{
msgContent = "\nMain handler dump start time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() + "\n";
auto mainHandler = appMainHandler_.lock();
if (mainHandler == nullptr) {
msgContent += "mainHandler is destructed!\n";
} else {
MainHandlerDumper handlerDumper;
msgContent += "mainHandler dump is:\n";
mainHandler->Dump(handlerDumper);
msgContent += handlerDumper.GetDumpInfo();
}
msgContent += "Main handler dump end time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() + "\n";
}
bool AppfreezeInner::ReadFdToString(int fd, std::string& content)
{
content.clear();
struct stat sb;
if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
content.reserve(sb.st_size);
}
char buf[BUFSIZ] = {0};
ssize_t n;
while ((n = OHOS_TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) {
content.append(buf, n);
}
return (n == 0);
}
bool AppfreezeInner::GetProcessStartTime(pid_t tid, unsigned long long &startTime)
{
std::string path = "/proc/" +std::to_string(tid);
UniqueFd dirFd(open(path.c_str(), O_DIRECTORY | O_RDONLY));
if (dirFd == -1) {
TAG_LOGE(AAFwkTag::APPDFR, "GetProcessInfo open %{public}s fail. errno %{public}d", path.c_str(), errno);
return false;
}
UniqueFd statFd(openat(dirFd.Get(), "stat", O_RDONLY | O_CLOEXEC));
if (statFd == -1) {
TAG_LOGE(AAFwkTag::APPDFR, "GetProcessInfo open %{public}s/stat fail. errno %{public}d", path.c_str(), errno);
return false;
}
std::string statStr;
if (!ReadFdToString(statFd.Get(), statStr)) {
TAG_LOGE(AAFwkTag::APPDFR, "GetProcessInfo read string fail.");
return false;
}
auto lastParenPos = statStr.find_last_of(")");
if (lastParenPos == std::string::npos) {
return false;
}
std::string eoc = statStr.substr(lastParenPos);
std::istringstream is(eoc);
constexpr int startTimePos = 21;
constexpr int base = 10;
int pos = 0;
std::string tmp;
while (is >> tmp && pos <= startTimePos) {
pos++;
if (pos == startTimePos) {
startTime = strtoull(tmp.c_str(), nullptr, base);
return true;
}
}
TAG_LOGE(AAFwkTag::APPDFR, "GetProcessInfo Get process info fail.");
return false;
}
std::string AppfreezeInner::GetProcessLifeCycle()
{
struct timespec ts;
(void)clock_gettime(CLOCK_BOOTTIME, &ts);
uint64_t sysUpTime = static_cast<uint64_t>(ts.tv_sec + static_cast<time_t>(ts.tv_nsec != 0 ? 1L : 0L));
unsigned long long startTime = 0;
if (GetProcessStartTime(getpid(), startTime)) {
auto clkTck = sysconf(_SC_CLK_TCK);
if (clkTck == -1) {
TAG_LOGE(AAFwkTag::APPDFR, "Get _SC_CLK_TCK fail. errno %{public}d", errno);
return "";
}
uint64_t procUpTime = sysUpTime - startTime / static_cast<uint32_t>(clkTck);
constexpr uint64_t invalidTimeLimit = 10 * 365 * 24 * 3600;
if (procUpTime > invalidTimeLimit) {
TAG_LOGE(AAFwkTag::APPDFR, "invalid system upTime %{public}" PRIu64" proc upTime: %{public}" PRIu64 ", "
"startTime: %{public}llu.", sysUpTime, procUpTime, startTime);
return "";
}
std::ostringstream oss;
oss << PROCESS_LIFETIME << COLON_SEPARATOR << std::to_string(procUpTime) << SECOND;
return oss.str();
}
return "";
}
std::string AppfreezeInner::LogFormatHeapSize(size_t totalSize, size_t objectSize, size_t sharedSize)
{
std::ostringstream oss;
oss << HEAP_TOTAL_SIZE << COLON_SEPARATOR << totalSize << COMMA_SEPARATOR <<
HEAP_OBJECT_SIZE << COLON_SEPARATOR << objectSize << COMMA_SEPARATOR <<
HEAP_SHARED_SIZE << COLON_SEPARATOR << sharedSize;
return oss.str();
}
std::string AppfreezeInner::LogFormatGC(const panda::GCStatistic& gCStatistic)
{
std::ostringstream oss;
oss << GC_COUNT << COLON_SEPARATOR << gCStatistic.count << COMMA_SEPARATOR <<
GC_MAX_PAUSE << COLON_SEPARATOR << gCStatistic.maxPause << COMMA_SEPARATOR <<
GC_MIN_PAUSE << COLON_SEPARATOR << gCStatistic.minPause << COMMA_SEPARATOR <<
GC_AVERAGE_PAUSE << COLON_SEPARATOR << gCStatistic.averagePause << COMMA_SEPARATOR <<
GC_LAST_START_TIME << COLON_SEPARATOR << gCStatistic.lastStartTime << COMMA_SEPARATOR <<
GC_LAST_END_TIME << COLON_SEPARATOR << gCStatistic.lastEndTime << COMMA_SEPARATOR <<
GC_LAST_TYPE << COLON_SEPARATOR << gCStatistic.lastType;
return oss.str();
}
std::string AppfreezeInner::ParseIOValue(std::string ioStr)
{
if (ioStr.empty()) {
return "";
}
std::istringstream iss(ioStr);
std::string line;
bool first = true;
std::string key;
std::string value;
std::ostringstream oss;
while (std::getline(iss, line)) {
if (line.empty()) {
continue;
}
size_t colonPos = line.find(":");
if (colonPos == std::string::npos) {
continue;
}
key = line.substr(0, colonPos);
value = line.substr(colonPos + 1);
value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
if (key.empty() || value.empty()) {
continue;
}
if (!first) {
oss << COMMA_SEPARATOR;
} else {
first = false;
}
oss << key << COLON_SEPARATOR << value;
}
TAG_LOGD(AAFwkTag::APPDFR, "read io: %{public}s", oss.str().c_str());
return oss.str();
}
std::string AppfreezeInner::GetProcessIOStr()
{
char realPath[PATH_MAX] = {0};
if (realpath(PROC_SELF_IO, realPath) == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "realpath error, errno: %{public}d, path: %{public}s", errno, PROC_SELF_IO);
return "";
}
UniqueFd ioFd(open(realPath, O_RDONLY | O_CLOEXEC));
if (ioFd < 0) {
TAG_LOGE(AAFwkTag::APPDFR, "open %{public}s fail. errno %{public}d", realPath, errno);
return "";
}
std::string ioStr;
if (!ReadFdToString(ioFd.Get(), ioStr)) {
TAG_LOGE(AAFwkTag::APPDFR, "read string fail, path: %{public}s", realPath);
return "";
}
return ParseIOValue(ioStr);
}
void AppfreezeInner::GetApplicationInfo(FaultData& faultData)
{
TAG_LOGD(AAFwkTag::APPDFR, "called");
if (!IsAppFreeze(faultData.errorObject.name) && !IsAppFreezeWarning(faultData.errorObject.name)) {
TAG_LOGI(AAFwkTag::APPDFR, "not to get application info");
return;
}
std::shared_ptr<OHOSApplication> application;
{
std::lock_guard<std::mutex> lock(applicationMutex_);
application = application_;
}
if (application == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "null application_");
return;
}
auto &runtime = application->GetRuntime();
if (runtime == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "null runtime");
return;
}
if (runtime->GetLanguage() != AbilityRuntime::Runtime::Language::JS) {
TAG_LOGE(AAFwkTag::APPDFR, "only support js");
return;
}
AbilityRuntime::JsRuntime* jsRuntime = static_cast<AbilityRuntime::JsRuntime*>(runtime.get());
if (jsRuntime == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "null runtime");
return;
}
size_t heapTotalSize = jsRuntime->GetHeapTotalSize();
size_t heapObjectSize = jsRuntime->GetHeapObjectSize();
size_t sharedSize = jsRuntime->GetSharedHeapSize();
faultData.applicationHeapInfo = LogFormatHeapSize(heapTotalSize, heapObjectSize, sharedSize);
faultData.processLifeTime = GetProcessLifeCycle();
faultData.applicationIOInfo = GetProcessIOStr();
panda::GCStatistic gCStatistic = jsRuntime->GetGCStatistic();
faultData.applicationGCInfo = LogFormatGC(gCStatistic);
faultData.isBlockInGc = CheckGCType(gCStatistic.lastType) &&
CheckBlockInGC(faultData.errorObject.name, gCStatistic.lastStartTime, gCStatistic.lastEndTime);
TAG_LOGI(AAFwkTag::APPDFR, "heap info: %{public}s, process lifeTime: %{public}s",
faultData.applicationHeapInfo.c_str(), faultData.processLifeTime.c_str());
}
bool AppfreezeInner::CheckGCType(std::string lastType)
{
return lastType != GC_SHARED_GC_TYPE;
}
int64_t AppfreezeInner::GetFreezeCurrentTime()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
system_clock::now().time_since_epoch()).count();
}
bool AppfreezeInner::IsFreezeTimeInGCPeriod(uint64_t halfTime, uint64_t blockTime,
uint64_t lastStartTime, uint64_t lastEndTime)
{
if (halfTime == 0 || blockTime == 0 || lastStartTime == 0 || lastEndTime == 0) {
return false;
}
if (halfTime > blockTime) {
return false;
}
TAG_LOGD(AAFwkTag::APPDFR, "GC Period halfTime: %{public}" PRIu64 ", blockTime: %{public}" PRIu64 " "
"lastStartTime: %{public}" PRIu64 ", lastEndTime: %{public}" PRIu64".",
halfTime, blockTime, lastStartTime, lastEndTime);
return (halfTime >= lastStartTime && lastEndTime < lastStartTime);
}
bool AppfreezeInner::CheckBlockInGC(const std::string& faultName,
uint64_t lastStartTime, uint64_t lastEndTime)
{
uint64_t now = static_cast<uint64_t>(GetFreezeCurrentTime());
if (faultName == AppFreezeType::THREAD_BLOCK_3S) {
threadBlock3STime_ = now;
} else if (faultName == AppFreezeType::THREAD_BLOCK_6S) {
return IsFreezeTimeInGCPeriod(threadBlock3STime_, now, lastStartTime, lastEndTime);
} else if (faultName == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
lifeCycleHalfTime_ = now;
} else if (faultName == AppFreezeType::LIFECYCLE_TIMEOUT) {
return IsFreezeTimeInGCPeriod(lifeCycleHalfTime_, now, lastStartTime, lastEndTime);
} else if (faultName == AppFreezeType::APP_INPUT_BLOCK) {
uint64_t inputBegin = now - APP_INPUT_BLOCK_TIME;
return IsFreezeTimeInGCPeriod(inputBegin, now, lastStartTime, lastEndTime);
}
return false;
}
int AppfreezeInner::TransformHicollieFaultNumber(const std::string& faultName)
{
if (faultName == AppFreezeType::THREAD_BLOCK_3S) {
return THREAD_BLOCK_3S_TYPE;
} else if (faultName == AppFreezeType::THREAD_BLOCK_6S) {
return THREAD_BLOCK_6S_TYPE;
} else if (faultName == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
return LIFECYCLE_HALF_TIMEOUT_TYPE;
} else if (faultName == AppFreezeType::LIFECYCLE_TIMEOUT) {
return LIFECYCLE_TIMEOUT_TYPE;
} else if (faultName == AppFreezeType::APP_INPUT_BLOCK) {
return APP_INPUT_BLOCK_TYPE;
} else if (faultName == AppFreezeType::BUSSINESS_THREAD_BLOCK_3S) {
return BUSSINESS_THREAD_BLOCK_3S_TYPE;
} else if (faultName == AppFreezeType::BUSSINESS_THREAD_BLOCK_6S) {
return BUSSINESS_THREAD_BLOCK_6S_TYPE;
} else if (faultName == AppFreezeType::BUSINESS_INPUT_BLOCK) {
return BUSINESS_INPUT_BLOCK_TYPE;
}
return -1;
}
std::string AppfreezeInner::GetMainStackDump(int32_t pid)
{
int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
system_clock::now().time_since_epoch()).count();
if (!lastMainStack_.empty() && now - lastMainStackTime_ < LAST_SAVE_MAIN_STACK_TIME) {
{
std::unique_lock<ffrt::mutex> lock(mainStackMutex_);
return lastMainStack_;
}
}
auto task = [pid, this]() {
std::string startTime = "\nDump main thread stack start time: " +
AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() + "\n";
std::string mainStack;
if (HiviewDFX::GetBacktraceStringByTidWithMix(mainStack, pid, 0, true)) {
mainStack = startTime + mainStack + "\nDump main thread stack end time: " +
AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() + "\n";
} else {
TAG_LOGE(AAFwkTag::APPDFR, "get main stack failed, mainStack=%{public}s", mainStack.c_str());
}
lastMainStackTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
system_clock::now().time_since_epoch()).count();
std::unique_lock<ffrt::mutex> lock(mainStackMutex_);
lastMainStack_ = mainStack;
mainStackCv_.notify_one();
};
ffrt::submit_h(task);
{
std::unique_lock<ffrt::mutex> lock(mainStackMutex_);
if (mainStackCv_.wait_for(lock, std::chrono::seconds(DUMP_MAIN_STACK_TIMEOUT)) == ffrt::cv_status::timeout) {
TAG_LOGW(AAFwkTag::APPDFR, "get main stack has been extecting more than 1s");
} else {
TAG_LOGI(AAFwkTag::APPDFR, "get main stack has finished less than 1s");
return lastMainStack_;
}
}
return "";
}
void AppfreezeInner::ChangeFaultDateInfo(FaultData& faultData, const std::string& msgContent)
{
faultData.errorObject.message += msgContent;
faultData.isInForeground = GetAppInForeground();
faultData.faultType = FaultDataType::APP_FREEZE;
faultData.notifyApp = false;
faultData.waitSaveState = false;
faultData.forceExit = false;
int faultNum = TransformHicollieFaultNumber(faultData.errorObject.name);
faultData.callbackLog = OHOS::HiviewDFX::Watchdog::GetInstance().ReadDataFromBuffer(faultNum);
GetApplicationInfo(faultData);
if (faultData.errorObject.name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
bool reportLifecycle = GetReportLifeCycleAsAppfreeze();
faultData.reportLifecycleToFreeze = reportLifecycle;
}
if (faultData.errorObject.name == AppFreezeType::LIFECYCLE_TIMEOUT) {
faultData.reportLifecycleToFreeze = GetReportLifeCycleAsAppfreeze();
}
if (faultData.errorObject.name == AppFreezeType::APP_INPUT_BLOCK) {
MMI::InputManager::GetInstance()->GetLastEventIds(faultData.markedId,
faultData.processedId, faultData.dispatchedEventId);
}
int32_t pid = IPCSkeleton::GetCallingPid();
int32_t uid = IPCSkeleton::GetCallingUid();
faultData.errorObject.mainStack = GetMainStackDump(pid);
bool isExit = IsExitApp(faultData.errorObject.name) && faultData.needKillProcess;
if (isExit) {
faultData.forceExit = true;
faultData.waitSaveState = AppRecovery::GetInstance().IsEnabled();
std::string reason = faultData.errorObject.name;
AAFwk::ExitReasonCompability exitReason = { REASON_APP_FREEZE, "Reason:" + reason };
exitReason.killId =
AppExecFwk::AppfreezeManager::GetInstance()->GetFreezeExitReason(faultData.errorObject.name);
exitReason.killMsg = reason;
exitReason.innerMsg = reason;
auto result = AbilityManagerClient::GetInstance()->RecordAppWithReason(pid, uid, exitReason);
TAG_LOGI(AAFwkTag::APPDFR, "Record result=%{public}d, pid=%{public}d, uid=%{public}d, "
"killId=%{public}d", result, pid, uid, exitReason.killId);
}
NotifyANR(faultData);
if (isExit) {
AppFreezeRecovery();
}
}
void AppfreezeInner::AppfreezeHandleOverReportCount(bool isSixSecondEvent)
{
FaultData faultData;
std::string faultTimeStr = "\nFault time:" + AbilityRuntime::TimeUtil::FormatTime("%Y/%m/%d-%H:%M:%S") + "\n";
faultData.errorObject.message = faultTimeStr;
faultData.errorObject.message += "App main thread is not response!";
int32_t pid = static_cast<int32_t>(getpid());
if (isSixSecondEvent) {
faultData.errorObject.name = AppFreezeType::THREAD_BLOCK_6S;
faultData.procStatm = GetProcStatm(pid);
if (BETA_VERSION) {
std::string packageName = "";
auto hisyseventReport = std::make_shared<HisyseventReport>(3);
hisyseventReport->InsertParam("PID", pid);
hisyseventReport->InsertParam("PACKAGE_NAME", packageName);
hisyseventReport->InsertParam("FAULT_TIME", faultTimeStr);
int32_t ret = hisyseventReport->Report("AAFWK", "FREEZE_HALF_HIVIEW_LOG", HISYSEVENT_FAULT);
faultData.errorObject.message += (ret == 0) ? "FREEZE_HALF_HIVIEW_LOG write success" : "";
}
} else {
if (!BETA_VERSION) {
std::string packageName = "";
auto hisyseventReport = std::make_shared<HisyseventReport>(2);
hisyseventReport->InsertParam("PID", pid);
hisyseventReport->InsertParam("PACKAGE_NAME", packageName);
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:,"
" ret:%{public}d", pid, ret);
}
faultData.errorObject.name = AppFreezeType::THREAD_BLOCK_3S;
}
std::string bundleName = GetBundleNameByApplication();
if (!IsHandleAppfreeze() || IsProcessDebug(pid, bundleName)) {
TAG_LOGW(AAFwkTag::APPDFR, "don't report event and kill, pid:%{public}d, bundleName:%{public}s",
pid, bundleName.c_str());
return;
}
std::string msgContent;
EnableFreezeSample(faultData);
GetMainHandlerDump(msgContent);
ChangeFaultDateInfo(faultData, msgContent);
return;
}
void AppfreezeInner::EnableFreezeSample(FaultData& newFaultData)
{
std::string eventName = newFaultData.errorObject.name;
newFaultData.isInForeground = GetAppInForeground();
if (eventName == AppFreezeType::THREAD_BLOCK_3S || eventName == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
newFaultData.appfreezeInfo = OHOS::HiviewDFX::Watchdog::GetInstance().StartSample(HALF_DURATION, HALF_INTERVAL);
TAG_LOGI(AAFwkTag::APPDFR, "start to sample freeze stack, eventName:%{public}s", eventName.c_str());
return;
}
if (IsAppFreeze(eventName)) {
newFaultData.appfreezeInfo = OHOS::HiviewDFX::Watchdog::GetInstance().StopSample(HALF_DURATION / HALF_INTERVAL);
newFaultData.isEnableMainThreadSample = GetMainThreadSample();
OHOS::HiviewDFX::Watchdog::GetInstance().GetSamplerResult(newFaultData.samplerStartTime,
newFaultData.samplerFinishTime, newFaultData.samplerCount);
TAG_LOGI(AAFwkTag::APPDFR, "stop to sample freeze stack, eventName:%{public}s freezeFile:%{public}s "
"enbleMainThreadSample:%{public}d.", eventName.c_str(), newFaultData.appfreezeInfo.c_str(),
newFaultData.isEnableMainThreadSample);
}
}
void AppfreezeInner::ReportAppfreezeTask(const FaultData& faultData, bool onlyMainThread)
{
FaultData newFaultData = faultData;
EnableFreezeSample(newFaultData);
auto reportFreeze = [newFaultData, onlyMainThread]() {
if (newFaultData.errorObject.name == "") {
TAG_LOGE(AAFwkTag::APPDFR, "null name");
return;
}
AppExecFwk::AppfreezeInner::GetInstance()->AcquireStack(newFaultData, onlyMainThread);
};
{
std::lock_guard<std::mutex> lock(handlingMutex_);
handlinglist_.emplace_back(newFaultData);
constexpr int HANDLING_MIN_SIZE = 1;
if (handlinglist_.size() <= HANDLING_MIN_SIZE) {
TAG_LOGW(AAFwkTag::APPDFR, "submit reportAppFreeze, name:%{public}s, startTime:%{public}s\n",
newFaultData.errorObject.name.c_str(), AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
appfreezeInnerTaskHandler_->SubmitTask(reportFreeze, "reportFreeze");
}
}
}
int AppfreezeInner::AppfreezeHandle(const FaultData& faultData, bool onlyMainThread)
{
int32_t pid = static_cast<int32_t>(getpid());
std::string bundleName = GetBundleNameByApplication();
if (!IsHandleAppfreeze() || IsProcessDebug(pid, bundleName)) {
TAG_LOGW(AAFwkTag::APPDFR, "don't report event and kill, pid:%{public}d, bundleName:%{public}s",
pid, bundleName.c_str());
return -1;
}
auto watchdogTask = [faultData, onlyMainThread, this] { this->ReportAppfreezeTask(faultData, onlyMainThread); };
OHOS::HiviewDFX::Watchdog::GetInstance().RunOneShotTask("ReportAppfreezeInnerTask", watchdogTask);
return 0;
}
bool AppfreezeInner::IsExitApp(const std::string& name)
{
if (name == AppFreezeType::THREAD_BLOCK_6S || name == AppFreezeType::APP_INPUT_BLOCK ||
name == AppFreezeType::LIFECYCLE_TIMEOUT || name == AppFreezeType::BUSSINESS_THREAD_BLOCK_6S ||
name == AppFreezeType::LIFECYCLE_TIMEOUT_WARNING) {
return true;
}
return false;
}
bool AppfreezeInner::IsAppFreeze(const std::string& name)
{
if (name == AppFreezeType::THREAD_BLOCK_6S || name == AppFreezeType::APP_INPUT_BLOCK ||
name == AppFreezeType::LIFECYCLE_TIMEOUT) {
return true;
}
return false;
}
bool AppfreezeInner::IsAppFreezeWarning(const std::string& name)
{
if (name == AppFreezeType::THREAD_BLOCK_3S || name == AppFreezeType::LIFECYCLE_HALF_TIMEOUT) {
return true;
}
return false;
}
int AppfreezeInner::AcquireStack(const FaultData& info, bool onlyMainThread)
{
HITRACE_METER_FMT(HITRACE_TAG_APP, "AppfreezeInner::AcquireStack name:%s", info.errorObject.name.c_str());
std::string msgContent;
int64_t startTime = AbilityRuntime::TimeUtil::CurrentTimeMillis();
GetMainHandlerDump(msgContent);
TAG_LOGW(AAFwkTag::APPDFR, "get mainhandler dump, eventName:%{public}s, endTime:%{public}s, "
"interval:[%{public}" PRId64 "] ms", info.errorObject.name.c_str(),
AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str(),
AbilityRuntime::TimeUtil::CurrentTimeMillis() - startTime);
std::lock_guard<std::mutex> lock(handlingMutex_);
for (auto it = handlinglist_.begin(); it != handlinglist_.end(); it = handlinglist_.erase(it)) {
HITRACE_METER_FMT(HITRACE_TAG_APP, "send appfreeze name:%s", it->errorObject.name.c_str());
FaultData faultData;
faultData.errorObject.message = it->errorObject.message + "\n";
if (it->state != 0) {
faultData.errorObject.message += "client actions for ability:\n" +
FreezeUtil::GetInstance().GetLifecycleEvent(it->token) + "\nclient actions for app:\n" +
FreezeUtil::GetInstance().GetAppLifecycleEvent(0) + "\n";
if (it->errorObject.name == AppFreezeType::LIFECYCLE_TIMEOUT ||
it->errorObject.name == AppFreezeType::LIFECYCLE_TIMEOUT_WARNING) {
FreezeUtil::GetInstance().DeleteLifecycleEvent(it->token);
FreezeUtil::GetInstance().DeleteAppLifecycleEvent(0);
}
}
faultData.errorObject.name = it->errorObject.name;
faultData.timeoutMarkers = it->timeoutMarkers;
faultData.eventId = it->eventId;
faultData.needKillProcess = it->needKillProcess;
faultData.appfreezeInfo = it->appfreezeInfo;
faultData.appRunningUniqueId = it->appRunningUniqueId;
faultData.procStatm = it->procStatm;
faultData.isEnableMainThreadSample = it->isEnableMainThreadSample;
faultData.schedTime = it->schedTime;
faultData.detectTime = it->detectTime;
faultData.appStatus = it->appStatus;
faultData.samplerStartTime = it->samplerStartTime;
faultData.samplerFinishTime = it->samplerFinishTime;
faultData.samplerCount = it->samplerCount;
faultData.pid = it->pid;
faultData.applicationHeapInfo = it->applicationHeapInfo;
faultData.processLifeTime = it->processLifeTime;
ChangeFaultDateInfo(faultData, msgContent);
}
return 0;
}
void AppfreezeInner::ThreadBlock(std::atomic_bool& isSixSecondEvent, uint64_t schedTime,
uint64_t now, bool isInBackground)
{
FaultData faultData;
std::string faultTimeStr = "\nFault time:" + AbilityRuntime::TimeUtil::FormatTime("%Y/%m/%d-%H:%M:%S") + "\n";
faultData.errorObject.message = faultTimeStr;
faultData.errorObject.message += "App main thread is not response!";
bool onlyMainThread = false;
int32_t pid = static_cast<int32_t>(getpid());
faultData.pid = pid;
faultData.schedTime = schedTime;
faultData.detectTime = now;
faultData.appStatus = isInBackground ? AppStatus::APP_STATUS_BACKGROUND : AppStatus::APP_STATUS_FOREGROUND;
if (isSixSecondEvent) {
faultData.errorObject.name = AppFreezeType::THREAD_BLOCK_6S;
onlyMainThread = true;
#ifdef APP_NO_RESPONSE_DIALOG
isSixSecondEvent.store(false);
#endif
faultData.procStatm = GetProcStatm(pid);
if (BETA_VERSION) {
std::string packageName = "";
auto hisyseventReport = std::make_shared<HisyseventReport>(3);
hisyseventReport->InsertParam("PID", pid);
hisyseventReport->InsertParam("PACKAGE_NAME", packageName);
hisyseventReport->InsertParam("FAULT_TIME", faultTimeStr);
int32_t ret = hisyseventReport->Report("AAFWK", "FREEZE_HALF_HIVIEW_LOG", HISYSEVENT_FAULT);
faultData.errorObject.message += (ret == 0) ? "FREEZE_HALF_HIVIEW_LOG write success" : "";
}
} else {
if (!BETA_VERSION) {
std::string packageName = "";
auto hisyseventReport = std::make_shared<HisyseventReport>(2);
hisyseventReport->InsertParam("PID", pid);
hisyseventReport->InsertParam("PACKAGE_NAME", packageName);
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:,"
" ret:%{public}d", pid, ret);
}
faultData.errorObject.name = AppFreezeType::THREAD_BLOCK_3S;
isSixSecondEvent.store(true);
}
if (!IsHandleAppfreeze()) {
return;
}
AppfreezeHandle(faultData, onlyMainThread);
}
int AppfreezeInner::NotifyANR(const FaultData& faultData)
{
HITRACE_METER_FMT(HITRACE_TAG_APP, "AppfreezeInner::NotifyANR name:%s",
faultData.errorObject.name.c_str());
auto applicationInfo = applicationInfo_.lock();
if (applicationInfo == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "null applicationInfo_");
return -1;
}
int32_t pid = static_cast<int32_t>(getpid());
TAG_LOGW(AAFwkTag::APPDFR, "NotifyAppFault:%{public}s, pid:%{public}d, bundleName:%{public}s "
"currentTime:%{public}s, processExit:%{public}d appfreezeInfo:%{public}s enbleMainThreadSample:%{public}d.",
faultData.errorObject.name.c_str(), pid,
applicationInfo->bundleName.c_str(), AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str(),
faultData.needKillProcess, faultData.appfreezeInfo.c_str(), faultData.isEnableMainThreadSample);
int ret = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->NotifyAppFault(faultData);
if (ret != 0) {
TAG_LOGW(AAFwkTag::APPDFR, "NotifyAppFault ret:%{public}d", ret);
}
return ret;
}
void AppfreezeInner::AppFreezeRecovery()
{
AppRecovery::GetInstance().ScheduleSaveAppState(StateReason::APP_FREEZE);
AppRecovery::GetInstance().ScheduleRecoverApp(StateReason::APP_FREEZE);
}
void AppfreezeInner::SetAppDebug(bool isAppDebug)
{
isAppDebug_ = isAppDebug;
}
void AppfreezeInner::SetAppInForeground(bool isInForeground)
{
isInForeground_ = isInForeground;
}
bool AppfreezeInner::GetAppInForeground()
{
return isInForeground_;
}
void AppfreezeInner::SetMainThreadSample(bool isEnableMainThreadSample)
{
isEnableMainThreadSample_ = isEnableMainThreadSample;
}
bool AppfreezeInner::GetMainThreadSample()
{
return isEnableMainThreadSample_;
}
void AppfreezeInner::SetReportLifeCycleAsAppfreeze(bool reportLifecycleToFreeze)
{
reportLifecycleToFreeze_ = reportLifecycleToFreeze;
}
bool AppfreezeInner::GetReportLifeCycleAsAppfreeze()
{
return reportLifecycleToFreeze_;
}
void AppfreezeInner::SetAppfreezeApplication(const std::shared_ptr<OHOSApplication> &application)
{
if (application == nullptr) {
TAG_LOGE(AAFwkTag::APPDFR, "null application");
return;
}
std::lock_guard<std::mutex> lock(applicationMutex_);
application_ = application;
}
void MainHandlerDumper::Dump(const std::string &message)
{
dumpInfo += message;
}
std::string MainHandlerDumper::GetTag()
{
return "";
}
std::string MainHandlerDumper::GetDumpInfo()
{
return dumpInfo;
}
}
}