1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dump_runtime_helper.h"
17
18 #include "app_mgr_client.h"
19 #include "faultloggerd_client.h"
20 #include "hilog_tag_wrapper.h"
21 #include "js_runtime.h"
22 #include "js_runtime_utils.h"
23 #include "singleton.h"
24 #include "dfx_jsnapi.h"
25
26 namespace OHOS {
27 namespace AppExecFwk {
28 const char *MODULE_NAME = "hiviewdfx.jsLeakWatcher";
29 const char *CHECK = "check";
30 const char *REQUIRE_NAPI = "requireNapi";
31
DumpRuntimeHelper(const std::shared_ptr<OHOSApplication> & application)32 DumpRuntimeHelper::DumpRuntimeHelper(const std::shared_ptr<OHOSApplication> &application)
33 : application_(application)
34 {}
35
SetAppFreezeFilterCallback()36 void DumpRuntimeHelper::SetAppFreezeFilterCallback()
37 {
38 if (application_ == nullptr) {
39 TAG_LOGE(AAFwkTag::APPKIT, "OHOSApplication is nullptr");
40 return;
41 }
42 auto& runtime = application_->GetRuntime();
43 if (runtime == nullptr) {
44 TAG_LOGE(AAFwkTag::APPKIT, "Runtime is nullptr");
45 return;
46 }
47 auto appfreezeFilterCallback = [] (const int32_t pid) -> bool {
48 auto client = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance();
49 if (client == nullptr) {
50 TAG_LOGE(AAFwkTag::APPKIT, "client is nullptr");
51 return false;
52 }
53 return client->SetAppFreezeFilter(pid);
54 };
55 auto vm = (static_cast<AbilityRuntime::JsRuntime&>(*runtime)).GetEcmaVm();
56 panda::DFXJSNApi::SetAppFreezeFilterCallback(vm, appfreezeFilterCallback);
57 }
58
DumpJsHeap(const OHOS::AppExecFwk::JsHeapDumpInfo & info)59 void DumpRuntimeHelper::DumpJsHeap(const OHOS::AppExecFwk::JsHeapDumpInfo &info)
60 {
61 if (application_ == nullptr) {
62 TAG_LOGE(AAFwkTag::APPKIT, "null application");
63 return;
64 }
65 auto& runtime = application_->GetRuntime();
66 if (runtime == nullptr) {
67 TAG_LOGE(AAFwkTag::APPKIT, "null runtime");
68 return;
69 }
70 if (info.needLeakobj) {
71 std::string checkList = "";
72 GetCheckList(runtime, checkList);
73 WriteCheckList(checkList);
74 }
75
76 if (info.needSnapshot == true) {
77 runtime->DumpHeapSnapshot(info.tid, info.needGc);
78 } else {
79 if (info.needGc == true) {
80 runtime->ForceFullGC(info.tid);
81 }
82 }
83 }
84
GetCheckList(const std::unique_ptr<AbilityRuntime::Runtime> & runtime,std::string & checkList)85 void DumpRuntimeHelper::GetCheckList(const std::unique_ptr<AbilityRuntime::Runtime> &runtime, std::string &checkList)
86 {
87 if (runtime->GetLanguage() != AbilityRuntime::Runtime::Language::JS) {
88 TAG_LOGE(AAFwkTag::APPKIT, "current language is not js");
89 return;
90 }
91 AbilityRuntime::JsRuntime &jsruntime = static_cast<AbilityRuntime::JsRuntime&>(*runtime);
92 AbilityRuntime::HandleScope handleScope(jsruntime);
93 auto env = jsruntime.GetNapiEnv();
94
95 napi_value global = nullptr;
96 napi_get_global(env, &global);
97 napi_value requireValue = GetJsLeakModule(env, global);
98 if (requireValue == nullptr) {
99 TAG_LOGE(AAFwkTag::APPKIT, "get jsLeak module fail");
100 return;
101 }
102 napi_value result = GetMethodCheck(env, requireValue, global);
103 if (result == nullptr) {
104 TAG_LOGE(AAFwkTag::APPKIT, "get method check fail");
105 return;
106 }
107
108 size_t checkListSize = 0;
109 napi_get_value_string_utf8(env, result, nullptr, 0, &checkListSize);
110 checkList.resize(checkListSize + 1);
111 napi_get_value_string_utf8(env, result, &checkList[0], checkListSize + 1, &checkListSize);
112 }
113
GetJsLeakModule(napi_env env,napi_value global)114 napi_value DumpRuntimeHelper::GetJsLeakModule(napi_env env, napi_value global)
115 {
116 napi_value napiFunc = nullptr;
117 napi_status status = napi_get_named_property(env, global, REQUIRE_NAPI, &napiFunc);
118 if (status != napi_ok) {
119 TAG_LOGE(AAFwkTag::APPKIT, "napi get requireNapi fail, %{public}d", status);
120 return nullptr;
121 }
122 napi_value moduleName = nullptr;
123 napi_create_string_utf8(env, MODULE_NAME, strlen(MODULE_NAME), &moduleName);
124 napi_value param[1] = {moduleName};
125 napi_value requireValue = nullptr;
126 status = napi_call_function(env, global, napiFunc, 1, ¶m[0], &requireValue);
127 if (status != napi_ok) {
128 TAG_LOGE(AAFwkTag::APPKIT, "call jsLeak fail, %{public}d", status);
129 return nullptr;
130 }
131 return requireValue;
132 }
133
GetMethodCheck(napi_env env,napi_value requireValue,napi_value global)134 napi_value DumpRuntimeHelper::GetMethodCheck(napi_env env, napi_value requireValue, napi_value global)
135 {
136 napi_value methodCheck = nullptr;
137 napi_status status = napi_get_named_property(env, requireValue, CHECK, &methodCheck);
138 if (status != napi_ok) {
139 TAG_LOGE(AAFwkTag::APPKIT, "napi get check fail, %{public}d", status);
140 return nullptr;
141 }
142 napi_valuetype valuetype = napi_undefined;
143 status = napi_typeof(env, methodCheck, &valuetype);
144 if (status != napi_ok) {
145 TAG_LOGE(AAFwkTag::APPKIT, "napi_typeof failed, %{public}d", status);
146 return nullptr;
147 }
148 napi_value result = nullptr;
149 status = napi_call_function(env, global, methodCheck, 0, nullptr, &result);
150 if (status != napi_ok) {
151 TAG_LOGE(AAFwkTag::APPKIT, "napi call check fail, %{public}d", status);
152 return nullptr;
153 }
154 return result;
155 }
156
WriteCheckList(const std::string & checkList)157 void DumpRuntimeHelper::WriteCheckList(const std::string &checkList)
158 {
159 TAG_LOGD(AAFwkTag::APPKIT, "called");
160 int32_t fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_HEAP_LEAK_LIST));
161 if (fd < 0) {
162 TAG_LOGE(AAFwkTag::APPKIT, "request fd failed, fd:%{public}d.\n", fd);
163 return;
164 }
165 if (write(fd, checkList.c_str(), strlen(checkList.c_str())) == -1) {
166 TAG_LOGE(AAFwkTag::APPKIT, "write failed, fd:%{public}d, errno:%{public}d.\n", fd, errno);
167 close(fd);
168 return;
169 }
170 close(fd);
171 }
172
173 } // namespace AppExecFwk
174 } // namespace OHOS
175