* Copyright (c) 2023 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.
*/
#ifndef OHOS_ABILITY_RUNTIME_APPFREEZE_MAMAGER_H
#define OHOS_ABILITY_RUNTIME_APPFREEZE_MAMAGER_H
#include <sys/types.h>
#include <fstream>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
#include "cpp/mutex.h"
#include "cpp/condition_variable.h"
#include "fault_data.h"
#include "freeze_util.h"
#include "appfreeze_event_report.h"
namespace OHOS {
using AbilityRuntime::FreezeUtil;
namespace AppExecFwk {
static const std::vector<std::string> APP_FREEZE_EVENT_NAME = {
"THREAD_BLOCK_3S",
"THREAD_BLOCK_6S",
"APP_INPUT_BLOCK",
"LIFECYCLE_HALF_TIMEOUT",
"LIFECYCLE_TIMEOUT",
};
static constexpr int DEFAULT_APPFREEZE_REPORT_TIMES = 1;
class AppfreezeManager : public std::enable_shared_from_this<AppfreezeManager> {
public:
struct AppInfo {
bool isOccurException = false;
bool isFrozen = false;
int pid;
int uid;
std::string bundleName;
std::string processName;
};
enum TypeAttribute {
NORMAL_TIMEOUT = 0,
CRITICAL_TIMEOUT = 1,
};
enum AppFreezeState {
APPFREEZE_STATE_IDLE = 0,
APPFREEZE_STATE_FREEZE = 1,
APPFREEZE_STATE_CANCELING = 2,
APPFREEZE_STATE_CANCELED = 3,
};
struct ParamInfo {
bool needKillProcess = true;
int typeId = TypeAttribute::NORMAL_TIMEOUT;
int32_t pid = 0;
std::string eventName;
std::string bundleName;
std::string msg;
};
struct AppfreezeEventRecord {
std::string dumpResult;
uint64_t schedTime = 0;
uint64_t detectTime = 0;
uint64_t dumpStartTime = 0;
uint64_t dumpFinishTime = 0;
int32_t appStatus = -1;
bool isRepeatKilledThread = false;
};
struct ProcessKillInfo {
std::string killReason;
std::string killMsg;
int adj = 0;
int64_t timestamp = 0;
int killId = -1;
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;
};
AppfreezeManager();
~AppfreezeManager();
static std::shared_ptr<AppfreezeManager> GetInstance();
static void DestroyInstance();
int AppfreezeHandle(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo);
int AppfreezeHandleWithStack(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo);
int LifecycleTimeoutHandle(const ParamInfo& info, FreezeUtil::LifecycleFlow flow = FreezeUtil::LifecycleFlow());
std::string WriteToFile(const std::string& fileName, const std::string& content);
bool IsHandleAppfreeze(const std::string& bundleName);
bool IsProcessDebug(int32_t pid, std::string bundleName);
void DeleteStack(int pid);
bool CancelAppFreezeDetect(int32_t pid, const std::string& bundleName);
void RemoveDeathProcess(std::string bundleName);
void ResetAppfreezeState(int32_t pid, const std::string& bundleName);
bool IsValidFreezeFilter(int32_t pid, const std::string& bundleName);
void ReportAppFreezeSysEvents(int32_t pid, const std::string& bundleName);
void RegisterAppKillTime(int32_t pid, uint64_t killTime);
void InitWarningCpuInfo(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo);
bool CheckInBackGround(const FaultData &faultData);
bool CheckAppfreezeHappend(const std::string& key, const std::string& eventName);
bool CheckNeedRecordAppRunningUnquieId(const std::string& eventName);
bool IsBetaVersion();
void InsertKillThread(int32_t state, int32_t pid, int32_t uid, const std::string& bundleName);
bool IsSkipDetect(int32_t pid, int32_t uid, const std::string& bundleName,
const std::string& eventName);
AppfreezeManager::ProcessKillInfo GetProcessKillReason(int32_t killId, int32_t pid, const std::string& killMsg);
void GetExitKernelReason(int32_t pid, ProcessKillInfo& killInfo);
int GetFreezeExitReason(const std::string& eventName);
void UpdateFreezeExcludedPid(bool isAdd, int32_t targetPid, int32_t profilerPid);
bool IsFreezeExcludedPid(int32_t targetPid);
bool CheckPreloadUIExtension(const std::string& message, const std::string& bundleName, int32_t pid,
const std::string& eventName);
bool CheckProcessExit(const std::string& processName, const std::string& eventName, bool foreground);
private:
struct PeerBinderInfo {
int32_t clientPid;
int32_t clientTid;
int32_t serverPid;
int32_t serverTid;
};
struct TerminalBinder {
int32_t pid;
int32_t tid;
};
struct ParseBinderParam {
int32_t eventPid;
int32_t eventTid;
int32_t pid;
int layer;
};
struct AppFreezeInfo {
int64_t occurTime = 0;
int pid = 0;
int reportTimes = DEFAULT_APPFREEZE_REPORT_TIMES;
int state = 0;
bool isRepeatKilledThread = false;
};
struct FreezeExcludedPidInfo {
int32_t targetPid = 0;
int32_t profilerPid = 0;
int64_t timestamp = 0;
};
AppfreezeManager& operator=(const AppfreezeManager&) = delete;
AppfreezeManager(const AppfreezeManager&) = delete;
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> BinderParser(std::ifstream& fin, std::string& stack,
std::set<int>& asyncPids) const;
std::map<int, std::list<AppfreezeManager::PeerBinderInfo>> 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::vector<std::string> GetFileToList(std::string line) const;
std::string StrSplit(const std::string& str, uint16_t index) const;
void ParseBinderPids(const std::map<int, std::list<AppfreezeManager::PeerBinderInfo>>& binderInfos,
std::set<int>& pids, AppfreezeManager::ParseBinderParam params, bool getTerminal,
AppfreezeManager::TerminalBinder& terminalBinder) const;
std::set<int> GetBinderPeerPids(std::string& stack, AppfreezeManager::ParseBinderParam params,
std::set<int>& asyncPids, AppfreezeManager::TerminalBinder& terminalBinder) const;
void FindStackByPid(std::string& msg, int pid) const;
std::pair<std::string, std::string> CatchJsonStacktrace(int pid, const std::string& faultType) const;
std::string CatcherStacktrace(int pid) const;
FaultData GetFaultNotifyData(const FaultData& faultData, int pid);
int AcquireStack(const FaultData& faultData, const AppInfo& appInfo, const std::string& memoryContent);
bool IsAncoProc(int pid);
std::string GetAppfreezeInfoPath(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo);
int NotifyANR(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo,
const std::string& binderInfo, const std::string& memoryContent);
void CollectFreezeSysMemory(std::string& memoryContent);
int MergeNotifyInfo(FaultData& faultNotifyData, const AppfreezeManager::AppInfo& appInfo);
void RecordAppFreezeBehavior(FaultData& faultData, uint64_t dumpStartTime,
uint64_t dumpFinishTime, const std::string& dumpResult);
std::string ParseDecToHex(uint64_t id);
std::string GetHitraceInfo();
AppFaultDataBySA GenerateFaultDataBySA(const ParamInfo& info, const FreezeUtil::LifecycleFlow& flow);
void PerfStart(std::string eventName);
std::string GetFirstLine(const std::string &path);
bool GetHitraceId(std::string& hiTraceIdInfo);
std::string CatchASyncByPid(const std::set<int> &asyncPids, const std::set<int> &syncPids, int pid);
bool CheckThreadKilled(int32_t pid, int32_t uid, const std::string& bundleName);
std::string GetCatcherStack(const std::string& fileName, const std::string& catcherStack);
bool IsNeedIgnoreFreezeEvent(const std::string& key, const std::string& eventName,
int maxReportTimes = DEFAULT_APPFREEZE_REPORT_TIMES);
bool IsNeedIgnoreInputBlockEvent(const std::string& key);
int ClearOldInputBlockFreezeInfo(size_t maxSize, int64_t maxTimelimit);
int64_t GetFreezeCurrentTime();
void SetFreezeState(const std::string& key, int state, const std::string& eventName);
int GetReportTimes(const std::string& key);
int64_t GetLastOccurTime(const std::string& key);
bool ClearOldInfo(std::map<std::string, AppFreezeInfo>& infoMap, size_t maxSize, int64_t maxTimelimit);
bool IsHalfTimeout(const std::string& faultType) const;
void CleanOldFreezeExcludedPids();
bool IsNativeDaemonProcess(int32_t profilerPid) const;
AppfreezeEventInfo UpdateEventInfo(const FaultData& faultData, const AppfreezeManager::AppInfo& appInfo,
const std::string& binderInfo, const std::string& memoryContent);
static constexpr size_t FREEZE_EXCLUDED_PID_MAX_SIZE = 100;
static constexpr size_t FREEZE_EXCLUDED_PID_CLEAN_COUNT = 30;
static constexpr const char* const NATIVE_DAEMON_PROCESS_NAME = "native_daemon";
static const inline std::string LOGGER_DEBUG_PROC_PATH = "/proc/transaction_proc";
std::string name_;
static ffrt::mutex singletonMutex_;
static std::shared_ptr<AppfreezeManager> instance_;
static ffrt::mutex freezeMutex_;
std::map<std::string, AppFreezeInfo> appfreezeInfo_;
std::map<std::string, int64_t> appInputBlockFreezeInfo_;
static ffrt::mutex catchStackMutex_;
static std::map<int, std::string> catchStackMap_;
static ffrt::mutex freezeFilterMutex_;
std::map<std::string, AppFreezeInfo> appfreezeFilterMap_;
int64_t perfTime = 0;
static ffrt::mutex freezeInfoMutex_;
static std::string appfreezeInfoPath_;
std::mutex freezeMapMutex_;
std::map<int32_t, std::map<std::string, AppfreezeEventRecord>> freezeEventMap_;
std::mutex freezeKillThreadMutex_;
std::map<std::string, AppFreezeInfo> freezeKillThreadMap_;
mutable ffrt::mutex freezeExcludedPidMutex_;
std::unordered_map<int32_t, FreezeExcludedPidInfo> freezeExcludedPidMap_;
};
}
}
#endif