1 // Copyright (C) 2019 The Android Open Source Project
2 //
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 #include "common/cmd_utils.h"
16 #include "db/file_models.h"
17 #include "db/models.h"
18
19 #include <android-base/file.h>
20 #include <android-base/properties.h>
21
22 #include <algorithm>
23 #include <sstream>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 namespace iorap::db {
30
31 static constexpr const char* kRootPathProp = "iorapd.root.dir";
32 static const unsigned int kPerfettoMaxTraces =
33 ::android::base::GetUintProperty("iorapd.perfetto.max_traces", /*default*/2u);
34
GetTimeNanoseconds()35 static uint64_t GetTimeNanoseconds() {
36 struct timespec now;
37 clock_gettime(CLOCK_REALTIME, &now);
38
39 uint64_t now_ns = (now.tv_sec * 1000000000LL + now.tv_nsec);
40 return now_ns;
41 }
42
IsDir(const std::string & dirpath)43 static bool IsDir(const std::string& dirpath) {
44 struct stat st;
45 if (stat(dirpath.c_str(), &st) == 0) {
46 if (S_ISDIR(st.st_mode)) {
47 return true;
48 }
49 }
50 return false;
51 }
52
53 // Given some path /a/b/c create all of /a, /a/b, /a/b/c/ recursively.
MkdirWithParents(const std::string & path)54 static bool MkdirWithParents(const std::string& path) {
55 size_t prev_end = 0;
56 while (prev_end < path.size()) {
57 size_t next_end = path.find('/', prev_end + 1);
58
59 std::string dir_path = path.substr(0, next_end);
60 if (!IsDir(dir_path)) {
61 #if defined(_WIN32)
62 int ret = mkdir(dir_path.c_str());
63 #else
64 mode_t old_mask = umask(0);
65 // The user permission is 5 to allow system server to
66 // read the files. No other users could do that because
67 // the upper directory only allows system server and iorapd
68 // to access. Also selinux rules prevent other users to
69 // read files here.
70 int ret = mkdir(dir_path.c_str(), 0755);
71 umask(old_mask);
72 #endif
73 if (ret != 0) {
74 PLOG(ERROR) << "failed to create dir " << dir_path;
75 return false;
76 }
77 }
78 prev_end = next_end;
79
80 if (next_end == std::string::npos) {
81 break;
82 }
83 }
84 return true;
85 }
86
FileModelBase(VersionedComponentName vcn)87 FileModelBase::FileModelBase(VersionedComponentName vcn)
88 : vcn_{std::move(vcn)} {
89 root_path_ = common::GetEnvOrProperty(kRootPathProp,
90 /*default*/"/data/misc/iorapd");
91 }
92
BaseDir() const93 std::string FileModelBase::BaseDir() const {
94 std::stringstream ss;
95
96 ss << root_path_ << "/" << vcn_.GetPackage() << "/";
97 ss << vcn_.GetVersion();
98 ss << "/";
99 ss << vcn_.GetActivity() << "/";
100 ss << SubDir();
101
102 return ss.str();
103 }
104
FilePath() const105 std::string FileModelBase::FilePath() const {
106 std::stringstream ss;
107 ss << BaseDir();
108 ss << "/";
109 ss << BaseFile();
110
111 return ss.str();
112 }
113
MkdirWithParents()114 bool FileModelBase::MkdirWithParents() {
115 LOG(VERBOSE) << "MkdirWithParents: " << BaseDir();
116 return ::iorap::db::MkdirWithParents(BaseDir());
117 }
118
PerfettoTraceFileModel(VersionedComponentName vcn,uint64_t timestamp)119 PerfettoTraceFileModel::PerfettoTraceFileModel(VersionedComponentName vcn,
120 uint64_t timestamp)
121 : FileModelBase{std::move(vcn)}, timestamp_{timestamp} {
122 }
123
CalculateNewestFilePath(VersionedComponentName vcn)124 PerfettoTraceFileModel PerfettoTraceFileModel::CalculateNewestFilePath(VersionedComponentName vcn) {
125 uint64_t timestamp = GetTimeNanoseconds();
126 return PerfettoTraceFileModel{vcn, timestamp};
127 }
128
BaseFile() const129 std::string PerfettoTraceFileModel::BaseFile() const {
130 std::stringstream ss;
131 ss << timestamp_ << ".perfetto_trace.pb";
132 return ss.str();
133 }
134
NeedMorePerfettoTraces(DbHandle & db,VersionedComponentName vcn)135 bool PerfettoTraceFileModel::NeedMorePerfettoTraces(DbHandle& db,
136 VersionedComponentName vcn) {
137 std::vector<RawTraceModel> raw_traces =
138 RawTraceModel::SelectByVersionedComponentName(db, vcn);
139
140 size_t raw_traces_size = raw_traces.size();
141 LOG(VERBOSE) << "The number of perfetto traces is "
142 << raw_traces_size
143 << " The cap is "
144 << kPerfettoMaxTraces ;
145 return raw_traces_size < kPerfettoMaxTraces;
146 }
147
DeleteOlderFiles(DbHandle & db,VersionedComponentName vcn)148 void PerfettoTraceFileModel::DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn) {
149 std::vector<RawTraceModel> raw_traces =
150 RawTraceModel::SelectByVersionedComponentName(db, vcn);
151
152 if (WOULD_LOG(VERBOSE)) {
153 size_t raw_traces_size = raw_traces.size();
154 for (size_t i = 0; i < raw_traces_size; ++i) {
155 LOG(VERBOSE) << "DeleteOlderFiles - selected " << raw_traces[i];
156 }
157 LOG(VERBOSE) << "DeleteOlderFiles - queried total " << raw_traces_size << " records";
158 }
159
160 size_t items_to_delete = 0;
161 if (raw_traces.size() > kPerfettoMaxTraces) {
162 items_to_delete = raw_traces.size() - kPerfettoMaxTraces;
163 } else {
164 LOG(VERBOSE) << "DeleteOlderFiles - don't delete older raw traces, too few files: "
165 << " wanted at least " << kPerfettoMaxTraces << ", but got " << raw_traces.size();
166 }
167
168 for (size_t i = 0; i < items_to_delete; ++i) {
169 RawTraceModel& raw_trace = raw_traces[i]; // sorted ascending -> items to delete are first.
170 std::string err_msg;
171
172 if (!::android::base::RemoveFileIfExists(raw_trace.file_path, /*out*/&err_msg)) {
173 LOG(ERROR) << "Failed to remove raw trace file: " << raw_trace.file_path
174 << ", reason: " << err_msg;
175 } else {
176 raw_trace.Delete();
177 LOG(DEBUG) << "Deleted raw trace for " << vcn << " at " << raw_trace.file_path;
178 }
179 }
180 }
181
CompiledTraceFileModel(VersionedComponentName vcn)182 CompiledTraceFileModel::CompiledTraceFileModel(VersionedComponentName vcn)
183 : FileModelBase{std::move(vcn)} {
184 }
185
CalculateNewestFilePath(VersionedComponentName vcn)186 CompiledTraceFileModel CompiledTraceFileModel::CalculateNewestFilePath(VersionedComponentName vcn) {
187 return CompiledTraceFileModel{vcn};
188 }
189
BaseFile() const190 std::string CompiledTraceFileModel::BaseFile() const {
191 return "compiled_trace.pb";
192 }
193
194 } // namespace iorap::db
195