diff options
Diffstat (limited to 'src/db/file_models.cc')
-rw-r--r-- | src/db/file_models.cc | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/db/file_models.cc b/src/db/file_models.cc new file mode 100644 index 0000000..0fe6d8f --- /dev/null +++ b/src/db/file_models.cc @@ -0,0 +1,181 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "common/cmd_utils.h" +#include "db/file_models.h" +#include "db/models.h" + +#include <android-base/file.h> +#include <android-base/properties.h> + +#include <algorithm> +#include <sstream> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +namespace iorap::db { + +static constexpr const char* kRootPathProp = "iorapd.root.dir"; +static const unsigned int kPerfettoMaxTraces = + ::android::base::GetUintProperty("iorapd.perfetto.max_traces", /*default*/10u); + +static uint64_t GetTimeNanoseconds() { + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + uint64_t now_ns = (now.tv_sec * 1000000000LL + now.tv_nsec); + return now_ns; +} + +static bool IsDir(const std::string& dirpath) { + struct stat st; + if (stat(dirpath.c_str(), &st) == 0) { + if (S_ISDIR(st.st_mode)) { + return true; + } + } + return false; +} + +// Given some path /a/b/c create all of /a, /a/b, /a/b/c/ recursively. +static bool MkdirWithParents(const std::string& path) { + size_t prev_end = 0; + while (prev_end < path.size()) { + size_t next_end = path.find('/', prev_end + 1); + + std::string dir_path = path.substr(0, next_end); + if (!IsDir(dir_path)) { +#if defined(_WIN32) + int ret = mkdir(dir_path.c_str()); +#else + mode_t old_mask = umask(0); + // The user permission is 5 to allow system server to + // read the files. No other users could do that because + // the upper directory only allows system server and iorapd + // to access. Also selinux rules prevent other users to + // read files here. + int ret = mkdir(dir_path.c_str(), 0755); + umask(old_mask); +#endif + if (ret != 0) { + PLOG(ERROR) << "failed to create dir " << dir_path; + return false; + } + } + prev_end = next_end; + + if (next_end == std::string::npos) { + break; + } + } + return true; +} + +FileModelBase::FileModelBase(VersionedComponentName vcn) + : vcn_{std::move(vcn)} { + root_path_ = common::GetEnvOrProperty(kRootPathProp, + /*default*/"/data/misc/iorapd"); +} + +std::string FileModelBase::BaseDir() const { + std::stringstream ss; + + ss << root_path_ << "/" << vcn_.GetPackage() << "/"; + ss << vcn_.GetVersion(); + ss << "/"; + ss << vcn_.GetActivity() << "/"; + ss << SubDir(); + + return ss.str(); +} + +std::string FileModelBase::FilePath() const { + std::stringstream ss; + ss << BaseDir(); + ss << "/"; + ss << BaseFile(); + + return ss.str(); +} + +bool FileModelBase::MkdirWithParents() { + LOG(VERBOSE) << "MkdirWithParents: " << BaseDir(); + return ::iorap::db::MkdirWithParents(BaseDir()); +} + +PerfettoTraceFileModel::PerfettoTraceFileModel(VersionedComponentName vcn, + uint64_t timestamp) + : FileModelBase{std::move(vcn)}, timestamp_{timestamp} { +} + +PerfettoTraceFileModel PerfettoTraceFileModel::CalculateNewestFilePath(VersionedComponentName vcn) { + uint64_t timestamp = GetTimeNanoseconds(); + return PerfettoTraceFileModel{vcn, timestamp}; +} + +std::string PerfettoTraceFileModel::BaseFile() const { + std::stringstream ss; + ss << timestamp_ << ".perfetto_trace.pb"; + return ss.str(); +} + +void PerfettoTraceFileModel::DeleteOlderFiles(DbHandle& db, VersionedComponentName vcn) { + std::vector<RawTraceModel> raw_traces = + RawTraceModel::SelectByVersionedComponentName(db, vcn); + + if (WOULD_LOG(VERBOSE)) { + size_t raw_traces_size = raw_traces.size(); + for (size_t i = 0; i < raw_traces_size; ++i) { + LOG(VERBOSE) << "DeleteOlderFiles - selected " << raw_traces[i]; + } + LOG(VERBOSE) << "DeleteOlderFiles - queried total " << raw_traces_size << " records"; + } + + size_t items_to_delete = 0; + if (raw_traces.size() > kPerfettoMaxTraces) { + items_to_delete = raw_traces.size() - kPerfettoMaxTraces; + } else { + LOG(VERBOSE) << "DeleteOlderFiles - don't delete older raw traces, too few files: " + << " wanted at least " << kPerfettoMaxTraces << ", but got " << raw_traces.size(); + } + + for (size_t i = 0; i < items_to_delete; ++i) { + RawTraceModel& raw_trace = raw_traces[i]; // sorted ascending -> items to delete are first. + std::string err_msg; + + if (!::android::base::RemoveFileIfExists(raw_trace.file_path, /*out*/&err_msg)) { + LOG(ERROR) << "Failed to remove raw trace file: " << raw_trace.file_path + << ", reason: " << err_msg; + } else { + raw_trace.Delete(); + LOG(DEBUG) << "Deleted raw trace for " << vcn << " at " << raw_trace.file_path; + } + } +} + +CompiledTraceFileModel::CompiledTraceFileModel(VersionedComponentName vcn) + : FileModelBase{std::move(vcn)} { +} + +CompiledTraceFileModel CompiledTraceFileModel::CalculateNewestFilePath(VersionedComponentName vcn) { + return CompiledTraceFileModel{vcn}; +} + +std::string CompiledTraceFileModel::BaseFile() const { + return "compiled_trace.pb"; +} + +} // namespace iorap::db |