xref: /aosp_15_r20/frameworks/native/cmds/dumpstate/DumpPool.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "dumpstate"
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include "DumpPool.h"
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include <array>
22*38e8c45fSAndroid Build Coastguard Worker #include <thread>
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker #include "dumpstate.h"
27*38e8c45fSAndroid Build Coastguard Worker #include "DumpstateInternal.h"
28*38e8c45fSAndroid Build Coastguard Worker #include "DumpstateUtil.h"
29*38e8c45fSAndroid Build Coastguard Worker 
30*38e8c45fSAndroid Build Coastguard Worker namespace android {
31*38e8c45fSAndroid Build Coastguard Worker namespace os {
32*38e8c45fSAndroid Build Coastguard Worker namespace dumpstate {
33*38e8c45fSAndroid Build Coastguard Worker 
34*38e8c45fSAndroid Build Coastguard Worker const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker 
WaitForTask(std::future<std::string> future,const std::string & title,int out_fd)37*38e8c45fSAndroid Build Coastguard Worker void WaitForTask(std::future<std::string> future, const std::string& title, int out_fd) {
38*38e8c45fSAndroid Build Coastguard Worker     DurationReporter duration_reporter("Wait for " + title, true);
39*38e8c45fSAndroid Build Coastguard Worker 
40*38e8c45fSAndroid Build Coastguard Worker     std::string result = future.get();
41*38e8c45fSAndroid Build Coastguard Worker     if (result.empty()) {
42*38e8c45fSAndroid Build Coastguard Worker         return;
43*38e8c45fSAndroid Build Coastguard Worker     }
44*38e8c45fSAndroid Build Coastguard Worker     DumpFileToFd(out_fd, title, result);
45*38e8c45fSAndroid Build Coastguard Worker     if (unlink(result.c_str())) {
46*38e8c45fSAndroid Build Coastguard Worker         MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
47*38e8c45fSAndroid Build Coastguard Worker     }
48*38e8c45fSAndroid Build Coastguard Worker }
49*38e8c45fSAndroid Build Coastguard Worker 
DumpPool(const std::string & tmp_root)50*38e8c45fSAndroid Build Coastguard Worker DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false),
51*38e8c45fSAndroid Build Coastguard Worker         log_duration_(true) {
52*38e8c45fSAndroid Build Coastguard Worker     assert(!tmp_root.empty());
53*38e8c45fSAndroid Build Coastguard Worker     deleteTempFiles(tmp_root_);
54*38e8c45fSAndroid Build Coastguard Worker }
55*38e8c45fSAndroid Build Coastguard Worker 
~DumpPool()56*38e8c45fSAndroid Build Coastguard Worker DumpPool::~DumpPool() {
57*38e8c45fSAndroid Build Coastguard Worker     std::unique_lock lock(lock_);
58*38e8c45fSAndroid Build Coastguard Worker     if (shutdown_ || threads_.empty()) {
59*38e8c45fSAndroid Build Coastguard Worker         return;
60*38e8c45fSAndroid Build Coastguard Worker     }
61*38e8c45fSAndroid Build Coastguard Worker     while (!tasks_.empty()) tasks_.pop();
62*38e8c45fSAndroid Build Coastguard Worker 
63*38e8c45fSAndroid Build Coastguard Worker     shutdown_ = true;
64*38e8c45fSAndroid Build Coastguard Worker     condition_variable_.notify_all();
65*38e8c45fSAndroid Build Coastguard Worker     lock.unlock();
66*38e8c45fSAndroid Build Coastguard Worker 
67*38e8c45fSAndroid Build Coastguard Worker     for (auto& thread : threads_) {
68*38e8c45fSAndroid Build Coastguard Worker         thread.join();
69*38e8c45fSAndroid Build Coastguard Worker     }
70*38e8c45fSAndroid Build Coastguard Worker     threads_.clear();
71*38e8c45fSAndroid Build Coastguard Worker     deleteTempFiles(tmp_root_);
72*38e8c45fSAndroid Build Coastguard Worker     MYLOGI("shutdown thread pool\n");
73*38e8c45fSAndroid Build Coastguard Worker }
74*38e8c45fSAndroid Build Coastguard Worker 
start(int thread_counts)75*38e8c45fSAndroid Build Coastguard Worker void DumpPool::start(int thread_counts) {
76*38e8c45fSAndroid Build Coastguard Worker     assert(thread_counts > 0);
77*38e8c45fSAndroid Build Coastguard Worker     assert(threads_.empty());
78*38e8c45fSAndroid Build Coastguard Worker     if (thread_counts > MAX_THREAD_COUNT) {
79*38e8c45fSAndroid Build Coastguard Worker         thread_counts = MAX_THREAD_COUNT;
80*38e8c45fSAndroid Build Coastguard Worker     }
81*38e8c45fSAndroid Build Coastguard Worker     MYLOGI("Start thread pool:%d\n", thread_counts);
82*38e8c45fSAndroid Build Coastguard Worker     shutdown_ = false;
83*38e8c45fSAndroid Build Coastguard Worker     for (int i = 0; i < thread_counts; i++) {
84*38e8c45fSAndroid Build Coastguard Worker         threads_.emplace_back(std::thread([=]() {
85*38e8c45fSAndroid Build Coastguard Worker             setThreadName(pthread_self(), i + 1);
86*38e8c45fSAndroid Build Coastguard Worker             loop();
87*38e8c45fSAndroid Build Coastguard Worker         }));
88*38e8c45fSAndroid Build Coastguard Worker     }
89*38e8c45fSAndroid Build Coastguard Worker }
90*38e8c45fSAndroid Build Coastguard Worker 
deleteTempFiles()91*38e8c45fSAndroid Build Coastguard Worker void DumpPool::deleteTempFiles() {
92*38e8c45fSAndroid Build Coastguard Worker     deleteTempFiles(tmp_root_);
93*38e8c45fSAndroid Build Coastguard Worker }
94*38e8c45fSAndroid Build Coastguard Worker 
setLogDuration(bool log_duration)95*38e8c45fSAndroid Build Coastguard Worker void DumpPool::setLogDuration(bool log_duration) {
96*38e8c45fSAndroid Build Coastguard Worker     log_duration_ = log_duration;
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker 
99*38e8c45fSAndroid Build Coastguard Worker template <>
invokeTask(std::function<void ()> dump_func,const std::string & duration_title,int out_fd)100*38e8c45fSAndroid Build Coastguard Worker void DumpPool::invokeTask<std::function<void()>>(std::function<void()> dump_func,
101*38e8c45fSAndroid Build Coastguard Worker         const std::string& duration_title, int out_fd) {
102*38e8c45fSAndroid Build Coastguard Worker     DurationReporter duration_reporter(duration_title, /*logcat_only =*/!log_duration_,
103*38e8c45fSAndroid Build Coastguard Worker             /*verbose =*/false, out_fd);
104*38e8c45fSAndroid Build Coastguard Worker     std::invoke(dump_func);
105*38e8c45fSAndroid Build Coastguard Worker }
106*38e8c45fSAndroid Build Coastguard Worker 
107*38e8c45fSAndroid Build Coastguard Worker template <>
invokeTask(std::function<void (int)> dump_func,const std::string & duration_title,int out_fd)108*38e8c45fSAndroid Build Coastguard Worker void DumpPool::invokeTask<std::function<void(int)>>(std::function<void(int)> dump_func,
109*38e8c45fSAndroid Build Coastguard Worker         const std::string& duration_title, int out_fd) {
110*38e8c45fSAndroid Build Coastguard Worker     DurationReporter duration_reporter(duration_title, /*logcat_only =*/!log_duration_,
111*38e8c45fSAndroid Build Coastguard Worker             /*verbose =*/false, out_fd);
112*38e8c45fSAndroid Build Coastguard Worker     std::invoke(dump_func, out_fd);
113*38e8c45fSAndroid Build Coastguard Worker }
114*38e8c45fSAndroid Build Coastguard Worker 
createTempFile()115*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<DumpPool::TmpFile> DumpPool::createTempFile() {
116*38e8c45fSAndroid Build Coastguard Worker     auto tmp_file_ptr = std::make_unique<TmpFile>();
117*38e8c45fSAndroid Build Coastguard Worker     std::string file_name_format = "%s/" + PREFIX_TMPFILE_NAME + "XXXXXX";
118*38e8c45fSAndroid Build Coastguard Worker     snprintf(tmp_file_ptr->path, sizeof(tmp_file_ptr->path), file_name_format.c_str(),
119*38e8c45fSAndroid Build Coastguard Worker              tmp_root_.c_str());
120*38e8c45fSAndroid Build Coastguard Worker     tmp_file_ptr->fd.reset(TEMP_FAILURE_RETRY(
121*38e8c45fSAndroid Build Coastguard Worker             mkostemp(tmp_file_ptr->path, O_CLOEXEC)));
122*38e8c45fSAndroid Build Coastguard Worker     if (tmp_file_ptr->fd.get() == -1) {
123*38e8c45fSAndroid Build Coastguard Worker         MYLOGE("open(%s, %s)\n", tmp_file_ptr->path, strerror(errno));
124*38e8c45fSAndroid Build Coastguard Worker         tmp_file_ptr = nullptr;
125*38e8c45fSAndroid Build Coastguard Worker         return tmp_file_ptr;
126*38e8c45fSAndroid Build Coastguard Worker     }
127*38e8c45fSAndroid Build Coastguard Worker     return tmp_file_ptr;
128*38e8c45fSAndroid Build Coastguard Worker }
129*38e8c45fSAndroid Build Coastguard Worker 
deleteTempFiles(const std::string & folder)130*38e8c45fSAndroid Build Coastguard Worker void DumpPool::deleteTempFiles(const std::string& folder) {
131*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
132*38e8c45fSAndroid Build Coastguard Worker             &closedir);
133*38e8c45fSAndroid Build Coastguard Worker     if (!dir_ptr) {
134*38e8c45fSAndroid Build Coastguard Worker         MYLOGE("Failed to opendir (%s): %s\n", folder.c_str(), strerror(errno));
135*38e8c45fSAndroid Build Coastguard Worker         return;
136*38e8c45fSAndroid Build Coastguard Worker     }
137*38e8c45fSAndroid Build Coastguard Worker     int dir_fd = dirfd(dir_ptr.get());
138*38e8c45fSAndroid Build Coastguard Worker     if (dir_fd < 0) {
139*38e8c45fSAndroid Build Coastguard Worker         MYLOGE("Failed to get fd of dir (%s): %s\n", folder.c_str(),
140*38e8c45fSAndroid Build Coastguard Worker                strerror(errno));
141*38e8c45fSAndroid Build Coastguard Worker         return;
142*38e8c45fSAndroid Build Coastguard Worker     }
143*38e8c45fSAndroid Build Coastguard Worker 
144*38e8c45fSAndroid Build Coastguard Worker     struct dirent* de;
145*38e8c45fSAndroid Build Coastguard Worker     while ((de = readdir(dir_ptr.get()))) {
146*38e8c45fSAndroid Build Coastguard Worker         if (de->d_type != DT_REG) {
147*38e8c45fSAndroid Build Coastguard Worker             continue;
148*38e8c45fSAndroid Build Coastguard Worker         }
149*38e8c45fSAndroid Build Coastguard Worker         std::string file_name(de->d_name);
150*38e8c45fSAndroid Build Coastguard Worker         if (file_name.find(PREFIX_TMPFILE_NAME) != 0) {
151*38e8c45fSAndroid Build Coastguard Worker             continue;
152*38e8c45fSAndroid Build Coastguard Worker         }
153*38e8c45fSAndroid Build Coastguard Worker         if (unlinkat(dir_fd, file_name.c_str(), 0)) {
154*38e8c45fSAndroid Build Coastguard Worker             MYLOGE("Failed to unlink (%s): %s\n", file_name.c_str(),
155*38e8c45fSAndroid Build Coastguard Worker                    strerror(errno));
156*38e8c45fSAndroid Build Coastguard Worker         }
157*38e8c45fSAndroid Build Coastguard Worker     }
158*38e8c45fSAndroid Build Coastguard Worker }
159*38e8c45fSAndroid Build Coastguard Worker 
setThreadName(const pthread_t thread,int id)160*38e8c45fSAndroid Build Coastguard Worker void DumpPool::setThreadName(const pthread_t thread, int id) {
161*38e8c45fSAndroid Build Coastguard Worker     std::array<char, 15> name;
162*38e8c45fSAndroid Build Coastguard Worker     snprintf(name.data(), name.size(), "dumpstate_%d", id);
163*38e8c45fSAndroid Build Coastguard Worker     pthread_setname_np(thread, name.data());
164*38e8c45fSAndroid Build Coastguard Worker }
165*38e8c45fSAndroid Build Coastguard Worker 
loop()166*38e8c45fSAndroid Build Coastguard Worker void DumpPool::loop() {
167*38e8c45fSAndroid Build Coastguard Worker     std::unique_lock lock(lock_);
168*38e8c45fSAndroid Build Coastguard Worker     while (!shutdown_) {
169*38e8c45fSAndroid Build Coastguard Worker         if (tasks_.empty()) {
170*38e8c45fSAndroid Build Coastguard Worker             condition_variable_.wait(lock);
171*38e8c45fSAndroid Build Coastguard Worker             continue;
172*38e8c45fSAndroid Build Coastguard Worker         } else {
173*38e8c45fSAndroid Build Coastguard Worker             std::packaged_task<std::string()> task = std::move(tasks_.front());
174*38e8c45fSAndroid Build Coastguard Worker             tasks_.pop();
175*38e8c45fSAndroid Build Coastguard Worker             lock.unlock();
176*38e8c45fSAndroid Build Coastguard Worker             std::invoke(task);
177*38e8c45fSAndroid Build Coastguard Worker             lock.lock();
178*38e8c45fSAndroid Build Coastguard Worker         }
179*38e8c45fSAndroid Build Coastguard Worker     }
180*38e8c45fSAndroid Build Coastguard Worker }
181*38e8c45fSAndroid Build Coastguard Worker 
182*38e8c45fSAndroid Build Coastguard Worker }  // namespace dumpstate
183*38e8c45fSAndroid Build Coastguard Worker }  // namespace os
184*38e8c45fSAndroid Build Coastguard Worker }  // namespace android
185