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     // TODO(deymo): The next two items belong in their own category; they
    103     // should not be counted as internal errors. b/27112092
    104     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
    105     case ErrorCode::kNonCriticalUpdateInOOBE:
    106     case ErrorCode::kOmahaErrorInHTTPResponse:
    107     case ErrorCode::kDownloadMetadataSignatureMissingError:
    108     case ErrorCode::kOmahaUpdateDeferredForBackoff:
    109     case ErrorCode::kPostinstallPowerwashError:
    110     case ErrorCode::kUpdateCanceledByChannelChange:
    111     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    112       return metrics::AttemptResult::kInternalError;
    113 
    114     // Special flags. These can't happen (we mask them out above) but
    115     // the compiler doesn't know that. Just break out so we can warn and
    116     // return |kInternalError|.
    117     case ErrorCode::kUmaReportedMax:
    118     case ErrorCode::kOmahaRequestHTTPResponseBase:
    119     case ErrorCode::kDevModeFlag:
    120     case ErrorCode::kResumedFlag:
    121     case ErrorCode::kTestImageFlag:
    122     case ErrorCode::kTestOmahaUrlFlag:
    123     case ErrorCode::kSpecialFlags:
    124       break;
    125   }
    126 
    127   LOG(ERROR) << "Unexpected error code " << base_code;
    128   return metrics::AttemptResult::kInternalError;
    129 }
    130 
    131 metrics::DownloadErrorCode GetDownloadErrorCode(ErrorCode code) {
    132   ErrorCode base_code = static_cast<ErrorCode>(
    133       static_cast<int>(code) & ~static_cast<int>(ErrorCode::kSpecialFlags));
    134 
    135   if (base_code >= ErrorCode::kOmahaRequestHTTPResponseBase) {
    136     int http_status =
    137         static_cast<int>(base_code) -
    138         static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase);
    139     if (http_status >= 200 && http_status <= 599) {
    140       return static_cast<metrics::DownloadErrorCode>(
    141           static_cast<int>(metrics::DownloadErrorCode::kHttpStatus200) +
    142           http_status - 200);
    143     } else if (http_status == 0) {
    144       // The code is using HTTP Status 0 for "Unable to get http
    145       // response code."
    146       return metrics::DownloadErrorCode::kDownloadError;
    147     }
    148     LOG(WARNING) << "Unexpected HTTP status code " << http_status;
    149     return metrics::DownloadErrorCode::kHttpStatusOther;
    150   }
    151 
    152   switch (base_code) {
    153     // Unfortunately, ErrorCode::kDownloadTransferError is returned for a wide
    154     // variety of errors (proxy errors, host not reachable, timeouts etc.).
    155     //
    156     // For now just map that to kDownloading. See http://crbug.com/355745
    157     // for how we plan to add more detail in the future.
    158     case ErrorCode::kDownloadTransferError:
    159       return metrics::DownloadErrorCode::kDownloadError;
    160 
    161     // All of these error codes are not related to downloading so break
    162     // out so we can warn and return InputMalformed.
    163     case ErrorCode::kSuccess:
    164     case ErrorCode::kError:
    165     case ErrorCode::kOmahaRequestError:
    166     case ErrorCode::kOmahaResponseHandlerError:
    167     case ErrorCode::kFilesystemCopierError:
    168     case ErrorCode::kPostinstallRunnerError:
    169     case ErrorCode::kPayloadMismatchedType:
    170     case ErrorCode::kInstallDeviceOpenError:
    171     case ErrorCode::kKernelDeviceOpenError:
    172     case ErrorCode::kPayloadHashMismatchError:
    173     case ErrorCode::kPayloadSizeMismatchError:
    174     case ErrorCode::kDownloadPayloadVerificationError:
    175     case ErrorCode::kDownloadNewPartitionInfoError:
    176     case ErrorCode::kDownloadWriteError:
    177     case ErrorCode::kNewRootfsVerificationError:
    178     case ErrorCode::kNewKernelVerificationError:
    179     case ErrorCode::kSignedDeltaPayloadExpectedError:
    180     case ErrorCode::kDownloadPayloadPubKeyVerificationError:
    181     case ErrorCode::kPostinstallBootedFromFirmwareB:
    182     case ErrorCode::kDownloadStateInitializationError:
    183     case ErrorCode::kDownloadInvalidMetadataMagicString:
    184     case ErrorCode::kDownloadSignatureMissingInManifest:
    185     case ErrorCode::kDownloadManifestParseError:
    186     case ErrorCode::kDownloadMetadataSignatureError:
    187     case ErrorCode::kDownloadMetadataSignatureVerificationError:
    188     case ErrorCode::kDownloadMetadataSignatureMismatch:
    189     case ErrorCode::kDownloadOperationHashVerificationError:
    190     case ErrorCode::kDownloadOperationExecutionError:
    191     case ErrorCode::kDownloadOperationHashMismatch:
    192     case ErrorCode::kOmahaRequestEmptyResponseError:
    193     case ErrorCode::kOmahaRequestXMLParseError:
    194     case ErrorCode::kDownloadInvalidMetadataSize:
    195     case ErrorCode::kDownloadInvalidMetadataSignature:
    196     case ErrorCode::kOmahaResponseInvalid:
    197     case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
    198     case ErrorCode::kOmahaUpdateDeferredPerPolicy:
    199     case ErrorCode::kNonCriticalUpdateInOOBE:
    200     case ErrorCode::kOmahaErrorInHTTPResponse:
    201     case ErrorCode::kDownloadOperationHashMissingError:
    202     case ErrorCode::kDownloadMetadataSignatureMissingError:
    203     case ErrorCode::kOmahaUpdateDeferredForBackoff:
    204     case ErrorCode::kPostinstallPowerwashError:
    205     case ErrorCode::kUpdateCanceledByChannelChange:
    206     case ErrorCode::kPostinstallFirmwareRONotUpdatable:
    207     case ErrorCode::kUnsupportedMajorPayloadVersion:
    208     case ErrorCode::kUnsupportedMinorPayloadVersion:
    209     case ErrorCode::kOmahaRequestXMLHasEntityDecl:
    210     case ErrorCode::kFilesystemVerifierError:
    211     case ErrorCode::kUserCanceled:
    212       break;
    213 
    214     // Special flags. These can't happen (we mask them out above) but
    215     // the compiler doesn't know that. Just break out so we can warn and
    216     // return |kInputMalformed|.
    217     case ErrorCode::kUmaReportedMax:
    218     case ErrorCode::kOmahaRequestHTTPResponseBase:
    219     case ErrorCode::kDevModeFlag:
    220     case ErrorCode::kResumedFlag:
    221     case ErrorCode::kTestImageFlag:
    222     case ErrorCode::kTestOmahaUrlFlag:
    223     case ErrorCode::kSpecialFlags:
    224       LOG(ERROR) << "Unexpected error code " << base_code;
    225       break;
    226   }
    227 
    228   return metrics::DownloadErrorCode::kInputMalformed;
    229 }
    230 
    231 metrics::ConnectionType GetConnectionType(ConnectionType type,
    232                                           ConnectionTethering tethering) {
    233   switch (type) {
    234     case ConnectionType::kUnknown:
    235       return metrics::ConnectionType::kUnknown;
    236 
    237     case ConnectionType::kEthernet:
    238       if (tethering == ConnectionTethering::kConfirmed)
    239         return metrics::ConnectionType::kTetheredEthernet;
    240       else
    241         return metrics::ConnectionType::kEthernet;
    242 
    243     case ConnectionType::kWifi:
    244       if (tethering == ConnectionTethering::kConfirmed)
    245         return metrics::ConnectionType::kTetheredWifi;
    246       else
    247         return metrics::ConnectionType::kWifi;
    248 
    249     case ConnectionType::kWimax:
    250       return metrics::ConnectionType::kWimax;
    251 
    252     case ConnectionType::kBluetooth:
    253       return metrics::ConnectionType::kBluetooth;
    254 
    255     case ConnectionType::kCellular:
    256       return metrics::ConnectionType::kCellular;
    257   }
    258 
    259   LOG(ERROR) << "Unexpected network connection type: type="
    260              << static_cast<int>(type)
    261              << ", tethering=" << static_cast<int>(tethering);
    262 
    263   return metrics::ConnectionType::kUnknown;
    264 }
    265 
    266 bool WallclockDurationHelper(SystemState* system_state,
    267                              const std::string& state_variable_key,
    268                              TimeDelta* out_duration) {
    269   bool ret = false;
    270 
    271   Time now = system_state->clock()->GetWallclockTime();
    272   int64_t stored_value;
    273   if (system_state->prefs()->GetInt64(state_variable_key, &stored_value)) {
    274     Time stored_time = Time::FromInternalValue(stored_value);
    275     if (stored_time > now) {
    276       LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
    277                  << " is in the future.";
    278     } else {
    279       *out_duration = now - stored_time;
    280       ret = true;
    281     }
    282   }
    283 
    284   if (!system_state->prefs()->SetInt64(state_variable_key,
    285                                        now.ToInternalValue())) {
    286     LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
    287   }
    288 
    289   return ret;
    290 }
    291 
    292 bool MonotonicDurationHelper(SystemState* system_state,
    293                              int64_t* storage,
    294                              TimeDelta* out_duration) {
    295   bool ret = false;
    296 
    297   Time now = system_state->clock()->GetMonotonicTime();
    298   if (*storage != 0) {
    299     Time stored_time = Time::FromInternalValue(*storage);
    300     *out_duration = now - stored_time;
    301     ret = true;
    302   }
    303   *storage = now.ToInternalValue();
    304 
    305   return ret;
    306 }
    307 
    308 }  // namespace metrics_utils
    309 }  // namespace chromeos_update_engine
    310