1 /**
2  * Copyright (c) 2020, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ProcPidDir.h"
18 
19 #include <android-base/file.h>
20 #include <android-base/result.h>
21 #include <errno.h>
22 
23 #include "ProcPidStat.h"
24 
25 namespace android {
26 namespace automotive {
27 namespace watchdog {
28 namespace testing {
29 
30 using android::base::Error;
31 using android::base::Result;
32 using android::base::WriteStringToFile;
33 
34 namespace {
35 
makeDir(std::string path)36 Result<void> makeDir(std::string path) {
37     if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
38         return Error() << "Could not mkdir " << path << ": " << strerror(errno);
39     }
40     return {};
41 }
42 
43 }  // namespace
44 
populateProcPidDir(const std::string & procDirPath,const std::unordered_map<uint32_t,std::vector<uint32_t>> & pidToTids,const std::unordered_map<uint32_t,std::string> & processStat,const std::unordered_map<uint32_t,std::string> & processStatus,const std::unordered_map<uint32_t,std::string> & threadStat)45 Result<void> populateProcPidDir(
46         const std::string& procDirPath,
47         const std::unordered_map<uint32_t, std::vector<uint32_t>>& pidToTids,
48         const std::unordered_map<uint32_t, std::string>& processStat,
49         const std::unordered_map<uint32_t, std::string>& processStatus,
50         const std::unordered_map<uint32_t, std::string>& threadStat) {
51     for (const auto& it : pidToTids) {
52         // 1. Create /proc/PID dir.
53         const auto& pidDirRes = makeDir(StringPrintf("%s/%" PRIu32, procDirPath.c_str(), it.first));
54         if (!pidDirRes) {
55             return Error() << "Failed to create top-level per-process directory: "
56                            << pidDirRes.error();
57         }
58 
59         // 2. Create /proc/PID/stat file.
60         uint32_t pid = it.first;
61         if (processStat.find(pid) != processStat.end()) {
62             std::string path = StringPrintf((procDirPath + kStatFileFormat).c_str(), pid);
63             if (!WriteStringToFile(processStat.at(pid), path)) {
64                 return Error() << "Failed to write pid stat file " << path;
65             }
66         }
67 
68         // 3. Create /proc/PID/status file.
69         if (processStatus.find(pid) != processStatus.end()) {
70             std::string path = StringPrintf((procDirPath + kStatusFileFormat).c_str(), pid);
71             if (!WriteStringToFile(processStatus.at(pid), path)) {
72                 return Error() << "Failed to write pid status file " << path;
73             }
74         }
75 
76         // 4. Create /proc/PID/task dir.
77         const auto& taskDirRes = makeDir(StringPrintf((procDirPath + kTaskDirFormat).c_str(), pid));
78         if (!taskDirRes) {
79             return Error() << "Failed to create task directory: " << taskDirRes.error();
80         }
81 
82         // 5. Create /proc/PID/task/TID dirs and /proc/PID/task/TID/stat files.
83         for (const auto& tid : it.second) {
84             const auto& tidDirRes = makeDir(
85                     StringPrintf((procDirPath + kTaskDirFormat + "/%" PRIu32).c_str(), pid, tid));
86             if (!tidDirRes) {
87                 return Error() << "Failed to create per-thread directory: " << tidDirRes.error();
88             }
89             if (threadStat.find(tid) != threadStat.end()) {
90                 std::string path =
91                         StringPrintf((procDirPath + kTaskDirFormat + kStatFileFormat).c_str(), pid,
92                                      tid);
93                 if (!WriteStringToFile(threadStat.at(tid), path)) {
94                     return Error() << "Failed to write thread stat file " << path;
95                 }
96             }
97         }
98     }
99 
100     return {};
101 }
102 
103 }  // namespace testing
104 }  // namespace watchdog
105 }  // namespace automotive
106 }  // namespace android
107