1 /*
2 * Copyright (c) 2023 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 "mem_profiler_collector_impl.h"
17
18 #include <common.h>
19 #include <memory>
20 #include <thread>
21 #include <fstream>
22 #include <sstream>
23 #include "hiview_logger.h"
24 #include "mem_profiler_decorator.h"
25 #include "native_memory_profiler_sa_client_manager.h"
26 #include "native_memory_profiler_sa_config.h"
27 #include "app_mgr_client.h"
28 #include "singleton.h"
29 #include "parameters.h"
30
31 using namespace OHOS::Developtools::NativeDaemon;
32
33 namespace OHOS {
34 namespace HiviewDFX {
35 namespace UCollectUtil {
36 DEFINE_LOG_TAG("UCollectUtil-MemProfilerCollector");
37 const std::string NATIVE_DAEMON_NAME("native_daemon");
38 int g_nativeDaemonPid = 0;
39 constexpr int WAIT_EXIT_MILLS = 100;
40 constexpr int FINAL_TIME = 3000;
41 constexpr int PREPARE_TIME = 10;
42 constexpr int PREPARE_THRESH = 2000;
43 constexpr int APP_THRESH = 20000;
44
IsNumber(const std::string & str)45 static bool IsNumber(const std::string& str)
46 {
47 return !str.empty() && std::find_if(str.begin(), str.end(), [](unsigned char c) {
48 return !std::isdigit(c);
49 }) == str.end();
50 }
51
GetUid(int pid)52 static int GetUid(int pid)
53 {
54 std::string pidStr = std::to_string(pid);
55 std::ifstream statusFile("/proc/" + pidStr + "/status");
56 if (!statusFile.is_open()) {
57 return -1;
58 }
59
60 std::string line;
61 std::string uidLabel = "Uid:";
62 std::string uid;
63 while (std::getline(statusFile, line)) {
64 if ((line.length() >= uidLabel.length()) && line.substr(0, uidLabel.length()) == uidLabel) {
65 std::stringstream is(line);
66 is >> uid;
67 is >> uid;
68 if (IsNumber(uid)) {
69 return stoi(uid);
70 } else {
71 break;
72 }
73 }
74 }
75 return -1;
76 }
77
Prepare()78 int MemProfilerCollectorImpl::Prepare()
79 {
80 OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "1");
81 sptr<IRemoteObject> service = NativeMemoryProfilerSaClientManager::GetRemoteService();
82 int time = 0;
83 while (service == nullptr && time < PREPARE_THRESH) {
84 std::this_thread::sleep_for(std::chrono::milliseconds(PREPARE_TIME));
85 time += PREPARE_TIME;
86 service = NativeMemoryProfilerSaClientManager::GetRemoteService();
87 }
88 if (service == nullptr) {
89 return RET_FAIL;
90 }
91 return RET_SUCC;
92 }
93
Start(ProfilerType type,int pid,int duration,int sampleInterval)94 int MemProfilerCollectorImpl::Start(ProfilerType type,
95 int pid, int duration, int sampleInterval)
96 {
97 OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "1");
98 int time = 0;
99 while (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid) && time < FINAL_TIME) {
100 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_EXIT_MILLS));
101 time += WAIT_EXIT_MILLS;
102 }
103 if (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
104 HIVIEW_LOGE("native daemon process not started");
105 return RET_FAIL;
106 }
107 HIVIEW_LOGI("mem_profiler_collector starting");
108 return NativeMemoryProfilerSaClientManager::Start(type, pid, duration, sampleInterval);
109 }
110
StartPrintNmd(int fd,int pid,int type)111 int MemProfilerCollectorImpl::StartPrintNmd(int fd, int pid, int type)
112 {
113 OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "1");
114 int time = 0;
115 while (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid) && time < FINAL_TIME) {
116 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_EXIT_MILLS));
117 time += WAIT_EXIT_MILLS;
118 }
119 if (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
120 HIVIEW_LOGE("native daemon process not started");
121 return RET_FAIL;
122 }
123 return NativeMemoryProfilerSaClientManager::GetMallocStats(fd, pid, type);
124 }
125
Stop(int pid)126 int MemProfilerCollectorImpl::Stop(int pid)
127 {
128 HIVIEW_LOGI("mem_profiler_collector stoping");
129 return NativeMemoryProfilerSaClientManager::Stop(pid);
130 }
131
Stop(const std::string & processName)132 int MemProfilerCollectorImpl::Stop(const std::string& processName)
133 {
134 HIVIEW_LOGI("mem_profiler_collector stoping");
135 return NativeMemoryProfilerSaClientManager::Stop(processName);
136 }
137
Start(int fd,ProfilerType type,int pid,int duration,int sampleInterval)138 int MemProfilerCollectorImpl::Start(int fd, ProfilerType type,
139 int pid, int duration, int sampleInterval)
140 {
141 OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "1");
142 int time = 0;
143 while (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid) && time < FINAL_TIME) {
144 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_EXIT_MILLS));
145 time += WAIT_EXIT_MILLS;
146 }
147 if (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
148 HIVIEW_LOGE("native daemon process not started");
149 return RET_FAIL;
150 }
151 if (GetUid(pid) >= APP_THRESH) {
152 auto client = DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance();
153 if (client == nullptr) {
154 HIVIEW_LOGE("AppMgrClient is nullptr");
155 } else {
156 client->SetAppFreezeFilter(pid);
157 }
158 }
159 std::shared_ptr<NativeMemoryProfilerSaConfig> config = std::make_shared<NativeMemoryProfilerSaConfig>();
160 if (type == ProfilerType::MEM_PROFILER_LIBRARY) {
161 config->responseLibraryMode_ = true;
162 } else if (type == ProfilerType::MEM_PROFILER_CALL_STACK) {
163 config->responseLibraryMode_ = false;
164 }
165 config->pid_ = pid;
166 config->duration_ = (uint32_t)duration;
167 config->sampleInterval_ = (uint32_t)sampleInterval;
168 uint32_t fiveMinutes = 300;
169 uint32_t jsStackDeps = 10;
170 config->statisticsInterval_ = fiveMinutes;
171 config->jsStackReport_ = true;
172 config->maxJsStackDepth_ = jsStackDeps;
173 HIVIEW_LOGI("mem_profiler_collector dumping data");
174 return NativeMemoryProfilerSaClientManager::DumpData(fd, config);
175 }
176
Start(int fd,ProfilerType type,std::string processName,int duration,int sampleInterval,bool startup)177 int MemProfilerCollectorImpl::Start(int fd, ProfilerType type,
178 std::string processName, int duration, int sampleInterval, bool startup)
179 {
180 OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "1");
181 int time = 0;
182 while (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid) && time < FINAL_TIME) {
183 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_EXIT_MILLS));
184 time += WAIT_EXIT_MILLS;
185 }
186 if (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
187 HIVIEW_LOGE("native daemon process not started");
188 return RET_FAIL;
189 }
190 std::shared_ptr<NativeMemoryProfilerSaConfig> config = std::make_shared<NativeMemoryProfilerSaConfig>();
191 if (type == ProfilerType::MEM_PROFILER_LIBRARY) {
192 config->responseLibraryMode_ = true;
193 } else if (type == ProfilerType::MEM_PROFILER_CALL_STACK) {
194 config->responseLibraryMode_ = false;
195 }
196 config->startupMode_ = startup;
197 config->processName_ = processName;
198 config->duration_ = (uint32_t)duration;
199 config->sampleInterval_ = (uint32_t)sampleInterval;
200 uint32_t fiveMinutes = 300;
201 config->statisticsInterval_ = fiveMinutes;
202 HIVIEW_LOGI("mem_profiler_collector dumping data");
203 return NativeMemoryProfilerSaClientManager::DumpData(fd, config);
204 }
205
Create()206 std::shared_ptr<MemProfilerCollector> MemProfilerCollector::Create()
207 {
208 static std::shared_ptr<MemProfilerCollector> instance_ =
209 std::make_shared<MemProfilerDecorator>(std::make_shared<MemProfilerCollectorImpl>());
210 return instance_;
211 }
212
213 } // UCollectUtil
214 } // HiViewDFX
215 } // OHOS
216