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