Home | History | Annotate | Download | only in update_engine
      1 //
      2 // Copyright (C) 2015 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_utils.h"
     18 
     19 #include <string>
     20 
     21 #include <base/time/time.h>
     22 
     23 #include "update_engine/common/clock_interface.h"
     24 #include "update_engine/common/constants.h"
     25 #include "update_engine/common/utils.h"
     26 #include "update_engine/system_state.h"
     27 
     28 using base::Time;
     29 using base::TimeDelta;
     30 
     31 namespace chromeos_update_engine {
     32 namespace metrics_utils {
     33 
     34 metrics::AttemptResult GetAttemptResult(ErrorCode code) {
     35   ErrorCode base_code = static_cast<ErrorCode>(
     36       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
     37 
     38   switch (base_code) {
     39     case ErrorCode::kSuccess:
     40       return metrics::AttemptResult::kUpdateSucceeded;
     41 
     42     case ErrorCode::kUpdatedButNotActive:
     43       return metrics::AttemptResult::kUpdateSucceededNotActive;
     44 
     45     case ErrorCode::kDownloadTransferError:
     46       return metrics::AttemptResult::kPayloadDownloadError;
     47 
     48     case ErrorCode::kDownloadInvalidMetadataSize:
     49     case ErrorCode::kDownloadInvalidMetadataMagicString:
     50     case ErrorCode::kDownloadMetadataSignatureError:
     51     case ErrorCode::kDownloadMetadataSignatureVerificationError:
     52     case ErrorCode::kPayloadMismatchedType:
     53     case ErrorCode::kUnsupportedMajorPayloadVersion:
     54     case ErrorCode::kUnsupportedMinorPayloadVersion:
     55     case ErrorCode::kDownloadNewPartitionInfoError:
     56     case ErrorCode::kDownloadSignatureMissingInManifest:
     57     case ErrorCode::kDownloadManifestParseError:
     58     case ErrorCode::kDownloadOperationHashMissingError:
     59       return metrics::AttemptResult::kMetadataMalformed;
     60 
     61     case ErrorCode::kDownloadOperationHashMismatch:
     62     case ErrorCode::kDownloadOperationHashVerificationError:
     63       return metrics::AttemptResult::kOperationMalformed;
     64 
     65     case ErrorCode::kDownloadOperationExecutionError:
     66     case ErrorCode::kInstallDeviceOpenError:
     67     case ErrorCode::kKernelDeviceOpenError:
     68     case ErrorCode::kDownloadWriteError:
     69     case ErrorCode::kFilesystemCopierError:
     70     case ErrorCode::kFilesystemVerifierError:
     71       return metrics::AttemptResult::kOperationExecutionError;
     72 
     73     case ErrorCode::kDownloadMetadataSignatureMismatch:
     74       return metrics::AttemptResult::kMetadataVerificationFailed;
     75 
     76     case ErrorCode::kPayloadSizeMismatchError:
     77     case ErrorCode::kPayloadHashMismatchError:
     78     case ErrorCode::kDownloadPayloadVerificationError:
     79     case ErrorCode::kSignedDeltaPayloadExpectedError:
     80     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
     81     case ErrorCode::kPayloadTimestampError:
     82       return metrics::AttemptResult::kPayloadVerificationFailed;
     83 
     84     case ErrorCode::kNewRootfsVerificationError:
     85     case ErrorCode::kNewKernelVerificationError:
     86       return metrics::AttemptResult::kVerificationFailed;
     87 
     88     case ErrorCode::kPostinstallRunnerError:
     89     case ErrorCode::kPostinstallBootedFromFirmwareB:
     90     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
     91       return metrics::AttemptResult::kPostInstallFailed;
     92 
     93     case ErrorCode::kUserCanceled:
     94       return metrics::AttemptResult::kUpdateCanceled;
     95 
     96     // We should never get these errors in the update-attempt stage so
     97     // return internal error if this happens.
     98     case ErrorCode::kError:
     99     case ErrorCode::kOmahaRequestXMLParseError:
    100     case ErrorCode::kOmahaRequestError:
    101     case ErrorCode::kOmahaResponseHandlerError:
    102     case ErrorCode::kDownloadStateInitializationError:
    103     case ErrorCode::kOmahaRequestEmptyResponseError:
    104     case ErrorCode::kDownloadInvalidMetadataSignature:
    105     case ErrorCode::kOmahaResponseInvalid:
    106     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
    107     // TODO(deymo): The next two items belong in their own category; they
    108     // should not be counted as internal errors. b/27112092
    109     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
    110     case ErrorCode::kNonCriticalUpdateInOOBE:
    111     case ErrorCode::kOmahaErrorInHTTPResponse:
    112     case ErrorCode::kDownloadMetadataSignatureMissingError:
    113     case ErrorCode::kOmahaUpdateDeferredForBackoff:
    114     case ErrorCode::kPostinstallPowerwashError:
    115     case ErrorCode::kUpdateCanceledByChannelChange:
    116     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    117       return metrics::AttemptResult::kInternalError;
    118 
    119     // Special flags. These can't happen (we mask them out above) but
    120     // the compiler doesn't know that. Just break out so we can warn and
    121     // return |kInternalError|.
    122     case ErrorCode::kUmaReportedMax:
    123     case ErrorCode::kOmahaRequestHTTPResponseBase:
    124     case ErrorCode::kDevModeFlag:
    125     case ErrorCode::kResumedFlag:
    126     case ErrorCode::kTestImageFlag:
    127     case ErrorCode::kTestOmahaUrlFlag:
    128     case ErrorCode::kSpecialFlags:
    129       break;
    130   }
    131 
    132   LOG(ERROR) << "Unexpected error code " << base_code;
    133   return metrics::AttemptResult::kInternalError;
    134 }
    135 
    136 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
    137   ErrorCode base_code = static_cast<ErrorCode>(
    138       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
    139 
    140   if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
    141     int http_status =
    142         static_cast<int>(base_code) -
    143         static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
    144     if (http_status >= 200 && http_status <= 599) {
    145       return static_cast<metrics::DownloadErrorCode>(
    146           static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
    147           http_status - 200);
    148     } else if (http_status == 0) {
    149       // The code is using HTTP Status 0 for "Unable to get http
    150       // response code."
    151       return metrics::DownloadErrorCode::kDownloadError;
    152     }
    153     LOG(WARNING) << "Unexpected HTTP status code " << http_status;
    154     return metrics::DownloadErrorCode::kHttpStatusOther;
    155   }
    156 
    157   switch (base_code) {
    158     // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
    159     // variety of errors (proxy errors, host not reachable, timeouts etc.).
    160     //
    161     // For now just map that to kDownloading. See http://crbug.com/355745
    162     // for how we plan to add more detail in the future.
    163     case ErrorCode::kDownloadTransferError:
    164       return metrics::DownloadErrorCode::kDownloadError;
    165 
    166     // All of these error codes are not related to downloading so break
    167     // out so we can warn and return InputMalformed.
    168     case ErrorCode::kSuccess:
    169     case ErrorCode::kError:
    170     case ErrorCode::kOmahaRequestError:
    171     case ErrorCode::kOmahaResponseHandlerError:
    172     case ErrorCode::kFilesystemCopierError:
    173     case ErrorCode::kPostinstallRunnerError:
    174     case ErrorCode::kPayloadMismatchedType:
    175     case ErrorCode::kInstallDeviceOpenError:
    176     case ErrorCode::kKernelDeviceOpenError:
    177     case ErrorCode::kPayloadHashMismatchError:
    178     case ErrorCode::kPayloadSizeMismatchError:
    179     case ErrorCode::kDownloadPayloadVerificationError:
    180     case ErrorCode::kDownloadNewPartitionInfoError:
    181     case ErrorCode::kDownloadWriteError:
    182     case ErrorCode::kNewRootfsVerificationError:
    183     case ErrorCode::kNewKernelVerificationError:
    184     case ErrorCode::kSignedDeltaPayloadExpectedError:
    185     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
    186     case ErrorCode::kPostinstallBootedFromFirmwareB:
    187     case ErrorCode::kDownloadStateInitializationError:
    188     case ErrorCode::kDownloadInvalidMetadataMagicString:
    189     case ErrorCode::kDownloadSignatureMissingInManifest:
    190     case ErrorCode::kDownloadManifestParseError:
    191     case ErrorCode::kDownloadMetadataSignatureError:
    192     case ErrorCode::kDownloadMetadataSignatureVerificationError:
    193     case ErrorCode::kDownloadMetadataSignatureMismatch:
    194     case ErrorCode::kDownloadOperationHashVerificationError:
    195     case ErrorCode::kDownloadOperationExecutionError:
    196     case ErrorCode::kDownloadOperationHashMismatch:
    197     case ErrorCode::kOmahaRequestEmptyResponseError:
    198     case ErrorCode::kOmahaRequestXMLParseError:
    199     case ErrorCode::kDownloadInvalidMetadataSize:
    200     case ErrorCode::kDownloadInvalidMetadataSignature:
    201     case ErrorCode::kOmahaResponseInvalid:
    202     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
    203     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
    204     case ErrorCode::kNonCriticalUpdateInOOBE:
    205     case ErrorCode::kOmahaErrorInHTTPResponse:
    206     case ErrorCode::kDownloadOperationHashMissingError:
    207     case ErrorCode::kDownloadMetadataSignatureMissingError:
    208     case ErrorCode::kOmahaUpdateDeferredForBackoff:
    209     case ErrorCode::kPostinstallPowerwashError:
    210     case ErrorCode::kUpdateCanceledByChannelChange:
    211     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
    212     case ErrorCode::kUnsupportedMajorPayloadVersion:
    213     case ErrorCode::kUnsupportedMinorPayloadVersion:
    214     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    215     case ErrorCode::kFilesystemVerifierError:
    216     case ErrorCode::kUserCanceled:
    217     case ErrorCode::kPayloadTimestampError:
    218     case ErrorCode::kUpdatedButNotActive:
    219       break;
    220 
    221     // Special flags. These can't happen (we mask them out above) but
    222     // the compiler doesn't know that. Just break out so we can warn and
    223     // return |kInputMalformed|.
    224     case ErrorCode::kUmaReportedMax:
    225     case ErrorCode::kOmahaRequestHTTPResponseBase:
    226     case ErrorCode::kDevModeFlag:
    227     case ErrorCode::kResumedFlag:
    228     case ErrorCode::kTestImageFlag:
    229     case ErrorCode::kTestOmahaUrlFlag:
    230     case ErrorCode::kSpecialFlags:
    231       LOG(ERROR) << "Unexpected error code " << base_code;
    232       break;
    233   }
    234 
    235   return metrics::DownloadErrorCode::kInputMalformed;
    236 }
    237 
    238 metrics::ConnectionType GetConnectionType(ConnectionType type,
    239                                           ConnectionTethering tethering) {
    240   switch (type) {
    241     case ConnectionType::kUnknown:
    242       return metrics::ConnectionType::kUnknown;
    243 
    244     case ConnectionType::kEthernet:
    245       if (tethering == ConnectionTethering::kConfirmed)
    246         return metrics::ConnectionType::kTetheredEthernet;
    247       else
    248         return metrics::ConnectionType::kEthernet;
    249 
    250     case ConnectionType::kWifi:
    251       if (tethering == ConnectionTethering::kConfirmed)
    252         return metrics::ConnectionType::kTetheredWifi;
    253       else
    254         return metrics::ConnectionType::kWifi;
    255 
    256     case ConnectionType::kWimax:
    257       return metrics::ConnectionType::kWimax;
    258 
    259     case ConnectionType::kBluetooth:
    260       return metrics::ConnectionType::kBluetooth;
    261 
    262     case ConnectionType::kCellular:
    263       return metrics::ConnectionType::kCellular;
    264   }
    265 
    266   LOG(ERROR) << "Unexpected network connection type: type="
    267              << static_cast<int>(type)
    268              << ", tethering=" << static_cast<int>(tethering);
    269 
    270   return metrics::ConnectionType::kUnknown;
    271 }
    272 
    273 bool WallclockDurationHelper(SystemState* system_state,
    274                              const std::string& state_variable_key,
    275                              TimeDelta* out_duration) {
    276   bool ret = false;
    277 
    278   Time now = system_state->clock()->GetWallclockTime();
    279   int64_t stored_value;
    280   if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
    281     Time stored_time = Time::FromInternalValue(stored_value);
    282     if (stored_time > now) {
    283       LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
    284                  << " is in the future.";
    285     } else {
    286       *out_duration = now - stored_time;
    287       ret = true;
    288     }
    289   }
    290 
    291   if (!system_state->prefs()->SetInt64(state_variable_key,
    292                                        now.ToInternalValue())) {
    293     LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
    294   }
    295 
    296   return ret;
    297 }
    298 
    299 bool MonotonicDurationHelper(SystemState* system_state,
    300                              int64_t* storage,
    301                              TimeDelta* out_duration) {
    302   bool ret = false;
    303 
    304   Time now = system_state->clock()->GetMonotonicTime();
    305   if (*storage != 0) {
    306     Time stored_time = Time::FromInternalValue(*storage);
    307     *out_duration = now - stored_time;
    308     ret = true;
    309   }
    310   *storage = now.ToInternalValue();
    311 
    312   return ret;
    313 }
    314 
    315 int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) {
    316   CHECK(prefs);
    317   if (!prefs->Exists(key))
    318     return 0;
    319 
    320   int64_t stored_value;
    321   if (!prefs->GetInt64(key, &stored_value))
    322     return 0;
    323 
    324   if (stored_value < 0) {
    325     LOG(ERROR) << key << ": Invalid value (" << stored_value
    326                << ") in persisted state. Defaulting to 0";
    327     return 0;
    328   }
    329 
    330   return stored_value;
    331 }
    332 
    333 void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs) {
    334   CHECK(prefs);
    335   prefs->SetInt64(kPrefsNumReboots, num_reboots);
    336   LOG(INFO) << "Number of Reboots during current update attempt = "
    337             << num_reboots;
    338 }
    339 
    340 void SetPayloadAttemptNumber(int64_t payload_attempt_number,
    341                              PrefsInterface* prefs) {
    342   CHECK(prefs);
    343   prefs->SetInt64(kPrefsPayloadAttemptNumber, payload_attempt_number);
    344   LOG(INFO) << "Payload Attempt Number = " << payload_attempt_number;
    345 }
    346 
    347 void SetSystemUpdatedMarker(ClockInterface* clock, PrefsInterface* prefs) {
    348   CHECK(prefs);
    349   CHECK(clock);
    350   Time update_finish_time = clock->GetMonotonicTime();
    351   prefs->SetInt64(kPrefsSystemUpdatedMarker,
    352                   update_finish_time.ToInternalValue());
    353   LOG(INFO) << "Updated Marker = " << utils::ToString(update_finish_time);
    354 }
    355 
    356 void SetUpdateTimestampStart(const Time& update_start_time,
    357                              PrefsInterface* prefs) {
    358   CHECK(prefs);
    359   prefs->SetInt64(kPrefsUpdateTimestampStart,
    360                   update_start_time.ToInternalValue());
    361   LOG(INFO) << "Update Timestamp Start = "
    362             << utils::ToString(update_start_time);
    363 }
    364 
    365 bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
    366                                PrefsInterface* prefs,
    367                                ClockInterface* clock) {
    368   CHECK(prefs);
    369   CHECK(clock);
    370   int64_t stored_value = GetPersistedValue(kPrefsSystemUpdatedMarker, prefs);
    371   if (stored_value == 0)
    372     return false;
    373 
    374   Time system_updated_at = Time::FromInternalValue(stored_value);
    375   base::TimeDelta time_to_reboot =
    376       clock->GetMonotonicTime() - system_updated_at;
    377   if (time_to_reboot.ToInternalValue() < 0) {
    378     LOG(ERROR) << "time_to_reboot is negative - system_updated_at: "
    379                << utils::ToString(system_updated_at);
    380     return false;
    381   }
    382   metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes());
    383   return true;
    384 }
    385 
    386 }  // namespace metrics_utils
    387 }  // namespace chromeos_update_engine
    388