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