1 // 2 // Copyright (C) 2017 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 "update_engine/metrics_reporter_android.h" 18 19 #include <stdint.h> 20 21 #include <memory> 22 #include <string> 23 24 #include <android-base/properties.h> 25 #include <base/strings/string_util.h> 26 #include <fs_mgr.h> 27 #include <libdm/dm.h> 28 #include <liblp/builder.h> 29 #include <liblp/liblp.h> 30 #include <statslog.h> 31 32 #include "update_engine/common/constants.h" 33 34 using android::fs_mgr::GetPartitionGroupName; 35 using android::fs_mgr::LpMetadata; 36 using android::fs_mgr::MetadataBuilder; 37 using android::fs_mgr::ReadMetadata; 38 using android::fs_mgr::SlotNumberForSlotSuffix; 39 using base::EndsWith; 40 41 namespace { 42 // A number offset adds on top of the enum value. e.g. ErrorCode::SUCCESS will 43 // be reported as 10000, and AttemptResult::UPDATE_CANCELED will be reported as 44 // 10011. This keeps the ordering of update engine's enum definition when statsd 45 // atoms reserve the value 0 for unknown state. 46 constexpr auto kMetricsReporterEnumOffset = 10000; 47 48 int32_t GetStatsdEnumValue(int32_t value) { 49 return kMetricsReporterEnumOffset + value; 50 } 51 } // namespace 52 53 namespace chromeos_update_engine { 54 55 namespace metrics { 56 57 std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter() { 58 return std::make_unique<MetricsReporterAndroid>(); 59 } 60 61 } // namespace metrics 62 63 void MetricsReporterAndroid::ReportUpdateAttemptMetrics( 64 SystemState* /* system_state */, 65 int attempt_number, 66 PayloadType payload_type, 67 base::TimeDelta duration, 68 base::TimeDelta duration_uptime, 69 int64_t payload_size, 70 metrics::AttemptResult attempt_result, 71 ErrorCode error_code) { 72 int64_t payload_size_mib = payload_size / kNumBytesInOneMiB; 73 74 int64_t super_partition_size_bytes = 0; 75 int64_t super_free_space = 0; 76 int64_t slot_size_bytes = 0; 77 78 if (android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) { 79 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); 80 auto super_device = fs_mgr_get_super_partition_name(); 81 std::unique_ptr<LpMetadata> metadata = ReadMetadata(super_device, slot); 82 if (metadata) { 83 super_partition_size_bytes = GetTotalSuperPartitionSize(*metadata); 84 85 for (const auto& group : metadata->groups) { 86 if (EndsWith(GetPartitionGroupName(group), 87 fs_mgr_get_slot_suffix(), 88 base::CompareCase::SENSITIVE)) { 89 slot_size_bytes += group.maximum_size; 90 } 91 } 92 93 auto metadata_builder = MetadataBuilder::New(*metadata); 94 if (metadata_builder) { 95 auto free_regions = metadata_builder->GetFreeRegions(); 96 for (const auto& interval : free_regions) { 97 super_free_space += interval.length(); 98 } 99 super_free_space *= android::dm::kSectorSize; 100 } else { 101 LOG(ERROR) << "Cannot create metadata builder."; 102 } 103 } else { 104 LOG(ERROR) << "Could not read dynamic partition metadata for device: " 105 << super_device; 106 } 107 } 108 109 android::util::stats_write( 110 android::util::UPDATE_ENGINE_UPDATE_ATTEMPT_REPORTED, 111 attempt_number, 112 GetStatsdEnumValue(static_cast<int32_t>(payload_type)), 113 duration.InMinutes(), 114 duration_uptime.InMinutes(), 115 payload_size_mib, 116 GetStatsdEnumValue(static_cast<int32_t>(attempt_result)), 117 GetStatsdEnumValue(static_cast<int32_t>(error_code)), 118 android::base::GetProperty("ro.build.fingerprint", "").c_str(), 119 super_partition_size_bytes, 120 slot_size_bytes, 121 super_free_space); 122 } 123 124 void MetricsReporterAndroid::ReportUpdateAttemptDownloadMetrics( 125 int64_t payload_bytes_downloaded, 126 int64_t /* payload_download_speed_bps */, 127 DownloadSource /* download_source */, 128 metrics::DownloadErrorCode /* payload_download_error_code */, 129 metrics::ConnectionType /* connection_type */) { 130 // TODO(xunchang) add statsd reporting 131 LOG(INFO) << "Current update attempt downloads " 132 << payload_bytes_downloaded / kNumBytesInOneMiB << " bytes data"; 133 } 134 135 void MetricsReporterAndroid::ReportSuccessfulUpdateMetrics( 136 int attempt_count, 137 int /* updates_abandoned_count */, 138 PayloadType payload_type, 139 int64_t payload_size, 140 int64_t num_bytes_downloaded[kNumDownloadSources], 141 int download_overhead_percentage, 142 base::TimeDelta total_duration, 143 base::TimeDelta /* total_duration_uptime */, 144 int reboot_count, 145 int /* url_switch_count */) { 146 int64_t payload_size_mib = payload_size / kNumBytesInOneMiB; 147 int64_t total_bytes_downloaded = 0; 148 for (size_t i = 0; i < kNumDownloadSources; i++) { 149 total_bytes_downloaded += num_bytes_downloaded[i] / kNumBytesInOneMiB; 150 } 151 152 android::util::stats_write( 153 android::util::UPDATE_ENGINE_SUCCESSFUL_UPDATE_REPORTED, 154 static_cast<int32_t>(attempt_count), 155 GetStatsdEnumValue(static_cast<int32_t>(payload_type)), 156 static_cast<int32_t>(payload_size_mib), 157 static_cast<int32_t>(total_bytes_downloaded), 158 static_cast<int32_t>(download_overhead_percentage), 159 static_cast<int32_t>(total_duration.InMinutes()), 160 static_cast<int32_t>(reboot_count)); 161 } 162 163 void MetricsReporterAndroid::ReportAbnormallyTerminatedUpdateAttemptMetrics() { 164 int attempt_result = 165 static_cast<int>(metrics::AttemptResult::kAbnormalTermination); 166 // TODO(xunchang) add statsd reporting 167 LOG(INFO) << "Abnormally terminated update attempt result " << attempt_result; 168 } 169 170 }; // namespace chromeos_update_engine 171