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