* Copyright (c) 2021-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.
*/
#include "dump_catcher.h"
#include "dfx_define.h"
#include "dfx_dump_catcher.h"
#include "dfx_log.h"
#include "dfx_json_formatter.h"
#include "dfx_kernel_stack.h"
#include "elapsed_time.h"
#include "procinfo.h"
#include "proc_util.h"
#include "dump_utils.h"
#ifndef is_ohos_lite
#include "bundle_mgr_interface.h"
#include "bundle_mgr_proxy.h"
#include "if_system_ability_manager.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"
#endif
namespace OHOS {
namespace HiviewDFX {
namespace {
constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000;
#ifndef is_ohos_lite
sptr<AppExecFwk::IBundleMgr> GetBundleManager()
{
auto systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (!systemManager) {
DFXLOGE("Get system ability manager failed");
return nullptr;
}
auto remoteObject = systemManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (!remoteObject) {
DFXLOGE("Get system ability failed");
return nullptr;
}
sptr<AppExecFwk::IBundleMgr> bundleMgrProxy = iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
return bundleMgrProxy;
}
#endif
std::string GetBundleNameByUid(int32_t uid)
{
#ifndef is_ohos_lite
constexpr long minUid = 10000;
if (uid < minUid) {
return "";
}
auto bundleInstance = GetBundleManager();
if (bundleInstance == nullptr) {
DFXLOGE("bundleInstance is nullptr");
return "";
}
std::string bundleName;
auto ret = bundleInstance->GetNameForUid(uid, bundleName);
if (ret != ERR_OK) {
DFXLOGE("GetNameForUid failed! ret = %{public}d", ret);
return "";
}
return bundleName;
#endif
return "";
}
}
DumpCatcher &DumpCatcher::GetInstance()
{
static DumpCatcher ins;
return ins;
}
void DumpCatcher::Dump(const DumpOptions& dumpOpt) const
{
ElapsedTime counter;
DfxDumpCatcher dfxDump;
std::string msg = "";
int timeout = dumpOpt.timeout > WAIT_GET_KERNEL_STACK_TIMEOUT ? dumpOpt.timeout : WAIT_GET_KERNEL_STACK_TIMEOUT;
auto dumpResult = dfxDump.DumpCatchWithTimeout(dumpOpt.pid, msg, timeout, dumpOpt.tid);
auto dumpTime = counter.Elapsed<std::chrono::milliseconds>();
std::string toFind = "Result:";
size_t startPos = msg.find(toFind);
if (startPos != std::string::npos) {
size_t endPos = msg.find("\n", startPos);
if (endPos != std::string::npos) {
msg.erase(startPos, endPos - startPos + 1);
}
}
if (dumpResult.first == -1) {
printf("Result:dump failed.\n");
} else if (dumpResult.first == 0) {
printf("Result:dump normal stack success.\n");
} else if (dumpResult.first == 1) {
printf("Result:dump kernel stack success.\n");
}
printf("%s", dumpResult.second.c_str());
printf("%s\n", msg.c_str());
printf("total cost:(%" PRId64 ")ms\n", dumpTime);
}
void DumpCatcher::DumpKernelStack(const DumpOptions& dumpOpt) const
{
ElapsedTime counter;
std::string kernelStackInfo;
std::function<bool(int)> stackTask = [&kernelStackInfo, &dumpOpt](int tid) {
if (tid <= 0) {
return false;
}
std::string tidKernelStackInfo;
auto ret = DfxGetKernelStack(tid, tidKernelStackInfo, dumpOpt.needArk);
if (ret == 0) {
kernelStackInfo.append(tidKernelStackInfo);
}
return true;
};
std::vector<int> tids;
(void)GetTidsByPidWithFunc(dumpOpt.pid, tids, stackTask);
auto getKernelStackTime = counter.Elapsed<std::chrono::milliseconds>();
counter.Reset();
std::string parsedKernelStack;
bool ret = false;
time_t parseSymbolTime = 0;
if (dumpOpt.needParse) {
std::string bundleName = GetBundleName(dumpOpt.pid);
ret = DfxJsonFormatter::FormatKernelStack(kernelStackInfo, parsedKernelStack, false, true, bundleName);
parseSymbolTime = counter.Elapsed<std::chrono::milliseconds>();
}
if (ret) {
printf("%s\n", parsedKernelStack.c_str());
} else {
printf("no need to format kernel stack or format failed.\n");
printf("%s\n", kernelStackInfo.c_str());
}
printf("threads size:(%zu)\n", tids.size());
printf("get kernel stack cost:(%" PRId64 ")ms\n", getKernelStackTime);
if (dumpOpt.needParse) {
printf("parse symbol cost:(%" PRId64 ")ms\n", parseSymbolTime);
}
}
std::string DumpCatcher::GetBundleName(int32_t pid) const
{
long uid = 0;
uint64_t sigBlk = 0;
if (!GetUidAndSigBlk(pid, uid, sigBlk)) {
printf("GetUidAndSigBlk failed for pid(%d).\n", pid);
return "";
}
return GetBundleNameByUid(uid);
}
}
}