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/prefs_interface.h"
     25 #include "update_engine/system_state.h"
     26 
     27 using base::Time;
     28 using base::TimeDelta;
     29 
     30 namespace chromeos_update_engine {
     31 namespace metrics_utils {
     32 
     33 metrics::AttemptResult GetAttemptResult(ErrorCode code) {
     34   ErrorCode base_code = static_cast<ErrorCode>(
     35       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
     36 
     37   switch (base_code) {
     38     case ErrorCode::kSuccess:
     39       return metrics::AttemptResult::kUpdateSucceeded;
     40 
     41     case ErrorCode::kDownloadTransferError:
     42       return metrics::AttemptResult::kPayloadDownloadError;
     43 
     44     case ErrorCode::kDownloadInvalidMetadataSize:
     45     case ErrorCode::kDownloadInvalidMetadataMagicString:
     46     case ErrorCode::kDownloadMetadataSignatureError:
     47     case ErrorCode::kDownloadMetadataSignatureVerificationError:
     48     case ErrorCode::kPayloadMismatchedType:
     49     case ErrorCode::kUnsupportedMajorPayloadVersion:
     50     case ErrorCode::kUnsupportedMinorPayloadVersion:
     51     case ErrorCode::kDownloadNewPartitionInfoError:
     52     case ErrorCode::kDownloadSignatureMissingInManifest:
     53     case ErrorCode::kDownloadManifestParseError:
     54     case ErrorCode::kDownloadOperationHashMissingError:
     55       return metrics::AttemptResult::kMetadataMalformed;
     56 
     57     case ErrorCode::kDownloadOperationHashMismatch:
     58     case ErrorCode::kDownloadOperationHashVerificationError:
     59       return metrics::AttemptResult::kOperationMalformed;
     60 
     61     case ErrorCode::kDownloadOperationExecutionError:
     62     case ErrorCode::kInstallDeviceOpenError:
     63     case ErrorCode::kKernelDeviceOpenError:
     64     case ErrorCode::kDownloadWriteError:
     65     case ErrorCode::kFilesystemCopierError:
     66     case ErrorCode::kFilesystemVerifierError:
     67       return metrics::AttemptResult::kOperationExecutionError;
     68 
     69     case ErrorCode::kDownloadMetadataSignatureMismatch:
     70       return metrics::AttemptResult::kMetadataVerificationFailed;
     71 
     72     case ErrorCode::kPayloadSizeMismatchError:
     73     case ErrorCode::kPayloadHashMismatchError:
     74     case ErrorCode::kDownloadPayloadVerificationError:
     75     case ErrorCode::kSignedDeltaPayloadExpectedError:
     76     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
     77       return metrics::AttemptResult::kPayloadVerificationFailed;
     78 
     79     case ErrorCode::kNewRootfsVerificationError:
     80     case ErrorCode::kNewKernelVerificationError:
     81       return metrics::AttemptResult::kVerificationFailed;
     82 
     83     case ErrorCode::kPostinstallRunnerError:
     84     case ErrorCode::kPostinstallBootedFromFirmwareB:
     85     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
     86       return metrics::AttemptResult::kPostInstallFailed;
     87 
     88     case ErrorCode::kUserCanceled:
     89       return metrics::AttemptResult::kUpdateCanceled;
     90 
     91     // We should never get these errors in the update-attempt stage so
     92     // return internal error if this happens.
     93     case ErrorCode::kError:
     94     case ErrorCode::kOmahaRequestXMLParseError:
     95     case ErrorCode::kOmahaRequestError:
     96     case ErrorCode::kOmahaResponseHandlerError:
     97     case ErrorCode::kDownloadStateInitializationError:
     98     case ErrorCode::kOmahaRequestEmptyResponseError:
     99     case ErrorCode::kDownloadInvalidMetadataSignature:
    100     case ErrorCode::kOmahaResponseInvalid:
    101     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
    102     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
    103     case ErrorCode::kOmahaErrorInHTTPResponse:
    104     case ErrorCode::kDownloadMetadataSignatureMissingError:
    105     case ErrorCode::kOmahaUpdateDeferredForBackoff:
    106     case ErrorCode::kPostinstallPowerwashError:
    107     case ErrorCode::kUpdateCanceledByChannelChange:
    108     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    109       return metrics::AttemptResult::kInternalError;
    110 
    111     // Special flags. These can't happen (we mask them out above) but
    112     // the compiler doesn't know that. Just break out so we can warn and
    113     // return |kInternalError|.
    114     case ErrorCode::kUmaReportedMax:
    115     case ErrorCode::kOmahaRequestHTTPResponseBase:
    116     case ErrorCode::kDevModeFlag:
    117     case ErrorCode::kResumedFlag:
    118     case ErrorCode::kTestImageFlag:
    119     case ErrorCode::kTestOmahaUrlFlag:
    120     case ErrorCode::kSpecialFlags:
    121       break;
    122   }
    123 
    124   LOG(ERROR) << "Unexpected error code " << base_code;
    125   return metrics::AttemptResult::kInternalError;
    126 }
    127 
    128 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
    129   ErrorCode base_code = static_cast<ErrorCode>(
    130       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
    131 
    132   if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
    133     int http_status =
    134         static_cast<int>(base_code) -
    135         static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
    136     if (http_status >= 200 && http_status <= 599) {
    137       return static_cast<metrics::DownloadErrorCode>(
    138           static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
    139           http_status - 200);
    140     } else if (http_status == 0) {
    141       // The code is using HTTP Status 0 for "Unable to get http
    142       // response code."
    143       return metrics::DownloadErrorCode::kDownloadError;
    144     }
    145     LOG(WARNING) << "Unexpected HTTP status code " << http_status;
    146     return metrics::DownloadErrorCode::kHttpStatusOther;
    147   }
    148 
    149   switch (base_code) {
    150     // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
    151     // variety of errors (proxy errors, host not reachable, timeouts etc.).
    152     //
    153     // For now just map that to kDownloading. See http://crbug.com/355745
    154     // for how we plan to add more detail in the future.
    155     case ErrorCode::kDownloadTransferError:
    156       return metrics::DownloadErrorCode::kDownloadError;
    157 
    158     // All of these error codes are not related to downloading so break
    159     // out so we can warn and return InputMalformed.
    160     case ErrorCode::kSuccess:
    161     case ErrorCode::kError:
    162     case ErrorCode::kOmahaRequestError:
    163     case ErrorCode::kOmahaResponseHandlerError:
    164     case ErrorCode::kFilesystemCopierError:
    165     case ErrorCode::kPostinstallRunnerError:
    166     case ErrorCode::kPayloadMismatchedType:
    167     case ErrorCode::kInstallDeviceOpenError:
    168     case ErrorCode::kKernelDeviceOpenError:
    169     case ErrorCode::kPayloadHashMismatchError:
    170     case ErrorCode::kPayloadSizeMismatchError:
    171     case ErrorCode::kDownloadPayloadVerificationError:
    172     case ErrorCode::kDownloadNewPartitionInfoError:
    173     case ErrorCode::kDownloadWriteError:
    174     case ErrorCode::kNewRootfsVerificationError:
    175     case ErrorCode::kNewKernelVerificationError:
    176     case ErrorCode::kSignedDeltaPayloadExpectedError:
    177     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
    178     case ErrorCode::kPostinstallBootedFromFirmwareB:
    179     case ErrorCode::kDownloadStateInitializationError:
    180     case ErrorCode::kDownloadInvalidMetadataMagicString:
    181     case ErrorCode::kDownloadSignatureMissingInManifest:
    182     case ErrorCode::kDownloadManifestParseError:
    183     case ErrorCode::kDownloadMetadataSignatureError:
    184     case ErrorCode::kDownloadMetadataSignatureVerificationError:
    185     case ErrorCode::kDownloadMetadataSignatureMismatch:
    186     case ErrorCode::kDownloadOperationHashVerificationError:
    187     case ErrorCode::kDownloadOperationExecutionError:
    188     case ErrorCode::kDownloadOperationHashMismatch:
    189     case ErrorCode::kOmahaRequestEmptyResponseError:
    190     case ErrorCode::kOmahaRequestXMLParseError:
    191     case ErrorCode::kDownloadInvalidMetadataSize:
    192     case ErrorCode::kDownloadInvalidMetadataSignature:
    193     case ErrorCode::kOmahaResponseInvalid:
    194     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
    195     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
    196     case ErrorCode::kOmahaErrorInHTTPResponse:
    197     case ErrorCode::kDownloadOperationHashMissingError:
    198     case ErrorCode::kDownloadMetadataSignatureMissingError:
    199     case ErrorCode::kOmahaUpdateDeferredForBackoff:
    200     case ErrorCode::kPostinstallPowerwashError:
    201     case ErrorCode::kUpdateCanceledByChannelChange:
    202     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
    203     case ErrorCode::kUnsupportedMajorPayloadVersion:
    204     case ErrorCode::kUnsupportedMinorPayloadVersion:
    205     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    206     case ErrorCode::kFilesystemVerifierError:
    207     case ErrorCode::kUserCanceled:
    208       break;
    209 
    210     // Special flags. These can't happen (we mask them out above) but
    211     // the compiler doesn't know that. Just break out so we can warn and
    212     // return |kInputMalformed|.
    213     case ErrorCode::kUmaReportedMax:
    214     case ErrorCode::kOmahaRequestHTTPResponseBase:
    215     case ErrorCode::kDevModeFlag:
    216     case ErrorCode::kResumedFlag:
    217     case ErrorCode::kTestImageFlag:
    218     case ErrorCode::kTestOmahaUrlFlag:
    219     case ErrorCode::kSpecialFlags:
    220       LOG(ERROR) << "Unexpected error code " << base_code;
    221       break;
    222   }
    223 
    224   return metrics::DownloadErrorCode::kInputMalformed;
    225 }
    226 
    227 metrics::ConnectionType GetConnectionType(NetworkConnectionType type,
    228                                           NetworkTethering tethering) {
    229   switch (type) {
    230     case NetworkConnectionType::kUnknown:
    231       return metrics::ConnectionType::kUnknown;
    232 
    233     case NetworkConnectionType::kEthernet:
    234       if (tethering == NetworkTethering::kConfirmed)
    235         return metrics::ConnectionType::kTetheredEthernet;
    236       else
    237         return metrics::ConnectionType::kEthernet;
    238 
    239     case NetworkConnectionType::kWifi:
    240       if (tethering == NetworkTethering::kConfirmed)
    241         return metrics::ConnectionType::kTetheredWifi;
    242       else
    243         return metrics::ConnectionType::kWifi;
    244 
    245     case NetworkConnectionType::kWimax:
    246       return metrics::ConnectionType::kWimax;
    247 
    248     case NetworkConnectionType::kBluetooth:
    249       return metrics::ConnectionType::kBluetooth;
    250 
    251     case NetworkConnectionType::kCellular:
    252       return metrics::ConnectionType::kCellular;
    253   }
    254 
    255   LOG(ERROR) << "Unexpected network connection type: type="
    256              << static_cast<int>(type)
    257              << ", tethering=" << static_cast<int>(tethering);
    258 
    259   return metrics::ConnectionType::kUnknown;
    260 }
    261 
    262 bool WallclockDurationHelper(SystemState* system_state,
    263                              const std::string& state_variable_key,
    264                              TimeDelta* out_duration) {
    265   bool ret = false;
    266 
    267   Time now = system_state->clock()->GetWallclockTime();
    268   int64_t stored_value;
    269   if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
    270     Time stored_time = Time::FromInternalValue(stored_value);
    271     if (stored_time > now) {
    272       LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
    273                  << " is in the future.";
    274     } else {
    275       *out_duration = now - stored_time;
    276       ret = true;
    277     }
    278   }
    279 
    280   if (!system_state->prefs()->SetInt64(state_variable_key,
    281                                        now.ToInternalValue())) {
    282     LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
    283   }
    284 
    285   return ret;
    286 }
    287 
    288 bool MonotonicDurationHelper(SystemState* system_state,
    289                              int64_t* storage,
    290                              TimeDelta* out_duration) {
    291   bool ret = false;
    292 
    293   Time now = system_state->clock()->GetMonotonicTime();
    294   if (*storage != 0) {
    295     Time stored_time = Time::FromInternalValue(*storage);
    296     *out_duration = now - stored_time;
    297     ret = true;
    298   }
    299   *storage = now.ToInternalValue();
    300 
    301   return ret;
    302 }
    303 
    304 }  // namespace metrics_utils
    305 }  // namespace chromeos_update_engine
    306