| // Copyright (C) 2020 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 <libsnapshot/snapshot_stats.h> |
| |
| #include <sstream> |
| |
| #include <android-base/file.h> |
| #include <android-base/logging.h> |
| #include "utility.h" |
| |
| namespace android { |
| namespace snapshot { |
| |
| SnapshotMergeStats* SnapshotMergeStats::GetInstance(SnapshotManager& parent) { |
| static SnapshotMergeStats g_instance(parent.GetMergeStateFilePath()); |
| CHECK(g_instance.path_ == parent.GetMergeStateFilePath()); |
| return &g_instance; |
| } |
| |
| SnapshotMergeStats::SnapshotMergeStats(const std::string& path) : path_(path), running_(false) {} |
| |
| bool SnapshotMergeStats::ReadState() { |
| std::string contents; |
| if (!android::base::ReadFileToString(path_, &contents)) { |
| PLOG(INFO) << "Read merge statistics file failed"; |
| return false; |
| } |
| if (!report_.ParseFromString(contents)) { |
| LOG(ERROR) << "Unable to parse merge statistics file as SnapshotMergeReport"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SnapshotMergeStats::WriteState() { |
| std::string contents; |
| if (!report_.SerializeToString(&contents)) { |
| LOG(ERROR) << "Unable to serialize SnapshotMergeStats."; |
| return false; |
| } |
| if (!WriteStringToFileAtomic(contents, path_)) { |
| PLOG(ERROR) << "Could not write to merge statistics file"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SnapshotMergeStats::DeleteState() { |
| std::string error; |
| if (!android::base::RemoveFileIfExists(path_, &error)) { |
| LOG(ERROR) << "Failed to remove merge statistics file " << path_ << ": " << error; |
| return false; |
| } |
| return true; |
| } |
| |
| bool SnapshotMergeStats::Start() { |
| if (running_) { |
| LOG(ERROR) << "SnapshotMergeStats running_ == " << running_; |
| return false; |
| } |
| running_ = true; |
| |
| start_time_ = std::chrono::steady_clock::now(); |
| if (ReadState()) { |
| report_.set_resume_count(report_.resume_count() + 1); |
| } else { |
| report_.set_resume_count(0); |
| report_.set_state(UpdateState::None); |
| } |
| |
| return WriteState(); |
| } |
| |
| void SnapshotMergeStats::set_state(android::snapshot::UpdateState state, bool using_compression) { |
| report_.set_state(state); |
| report_.set_compression_enabled(using_compression); |
| } |
| |
| void SnapshotMergeStats::set_cow_file_size(uint64_t cow_file_size) { |
| report_.set_cow_file_size(cow_file_size); |
| } |
| |
| uint64_t SnapshotMergeStats::cow_file_size() { |
| return report_.cow_file_size(); |
| } |
| |
| void SnapshotMergeStats::set_total_cow_size_bytes(uint64_t bytes) { |
| report_.set_total_cow_size_bytes(bytes); |
| } |
| |
| void SnapshotMergeStats::set_estimated_cow_size_bytes(uint64_t bytes) { |
| report_.set_estimated_cow_size_bytes(bytes); |
| } |
| |
| uint64_t SnapshotMergeStats::total_cow_size_bytes() { |
| return report_.total_cow_size_bytes(); |
| } |
| |
| uint64_t SnapshotMergeStats::estimated_cow_size_bytes() { |
| return report_.estimated_cow_size_bytes(); |
| } |
| |
| void SnapshotMergeStats::set_boot_complete_time_ms(uint32_t ms) { |
| report_.set_boot_complete_time_ms(ms); |
| } |
| |
| uint32_t SnapshotMergeStats::boot_complete_time_ms() { |
| return report_.boot_complete_time_ms(); |
| } |
| |
| void SnapshotMergeStats::set_boot_complete_to_merge_start_time_ms(uint32_t ms) { |
| report_.set_boot_complete_to_merge_start_time_ms(ms); |
| } |
| |
| uint32_t SnapshotMergeStats::boot_complete_to_merge_start_time_ms() { |
| return report_.boot_complete_to_merge_start_time_ms(); |
| } |
| |
| void SnapshotMergeStats::set_merge_failure_code(MergeFailureCode code) { |
| report_.set_merge_failure_code(code); |
| } |
| |
| MergeFailureCode SnapshotMergeStats::merge_failure_code() { |
| return report_.merge_failure_code(); |
| } |
| |
| void SnapshotMergeStats::set_source_build_fingerprint(const std::string& fingerprint) { |
| report_.set_source_build_fingerprint(fingerprint); |
| } |
| |
| std::string SnapshotMergeStats::source_build_fingerprint() { |
| return report_.source_build_fingerprint(); |
| } |
| |
| class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result { |
| public: |
| SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report, |
| std::chrono::steady_clock::duration merge_time) |
| : report_(report), merge_time_(merge_time) {} |
| const SnapshotMergeReport& report() const override { return report_; } |
| std::chrono::steady_clock::duration merge_time() const override { return merge_time_; } |
| |
| private: |
| SnapshotMergeReport report_; |
| std::chrono::steady_clock::duration merge_time_; |
| }; |
| |
| std::unique_ptr<SnapshotMergeStats::Result> SnapshotMergeStats::Finish() { |
| if (!running_) { |
| LOG(ERROR) << "SnapshotMergeStats running_ == " << running_; |
| return nullptr; |
| } |
| running_ = false; |
| |
| auto result = std::make_unique<SnapshotMergeStatsResultImpl>( |
| report_, std::chrono::steady_clock::now() - start_time_); |
| |
| // We still want to report result if state is not deleted. Just leave |
| // it there and move on. A side effect is that it may be reported over and |
| // over again in the future, but there is nothing we can do. |
| (void)DeleteState(); |
| |
| return result; |
| } |
| |
| } // namespace snapshot |
| } // namespace android |