diff options
Diffstat (limited to 'cmds/statsd/src/StatsLogProcessor.cpp')
-rw-r--r-- | cmds/statsd/src/StatsLogProcessor.cpp | 175 |
1 files changed, 131 insertions, 44 deletions
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index bde15a5cdaae..6e7f08135f1e 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -196,17 +196,27 @@ void StatsLogProcessor::onBinaryPushStateChangedEventLocked(LogEvent* event) { !checkPermissionForIds(kPermissionUsage, pid, uid)) { return; } - status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR, err4 = NO_ERROR; - string trainName = string(event->GetString(1 /*train name field id*/, &err)); - int64_t trainVersionCode = event->GetLong(2 /*train version field id*/, &err2); - int32_t state = int32_t(event->GetLong(6 /*state field id*/, &err3)); + // The Get* functions don't modify the status on success, they only write in + // failure statuses, so we can use one status variable for all calls then + // check if it is no longer NO_ERROR. + status_t err = NO_ERROR; + InstallTrainInfo trainInfo; + trainInfo.trainName = string(event->GetString(1 /*train name field id*/, &err)); + trainInfo.trainVersionCode = event->GetLong(2 /*train version field id*/, &err); + trainInfo.requiresStaging = event->GetBool(3 /*requires staging field id*/, &err); + trainInfo.rollbackEnabled = event->GetBool(4 /*rollback enabled field id*/, &err); + trainInfo.requiresLowLatencyMonitor = + event->GetBool(5 /*requires low latency monitor field id*/, &err); + trainInfo.status = int32_t(event->GetLong(6 /*state field id*/, &err)); #ifdef NEW_ENCODING_SCHEME std::vector<uint8_t> trainExperimentIdBytes = - event->GetStorage(7 /*experiment ids field id*/, &err4); + event->GetStorage(7 /*experiment ids field id*/, &err); #else - string trainExperimentIdString = event->GetString(7 /*experiment ids field id*/, &err4); + string trainExperimentIdString = event->GetString(7 /*experiment ids field id*/, &err); #endif - if (err != NO_ERROR || err2 != NO_ERROR || err3 != NO_ERROR || err4 != NO_ERROR) { + bool is_rollback = event->GetBool(10 /*is rollback field id*/, &err); + + if (err != NO_ERROR) { ALOGE("Failed to parse fields in binary push state changed log event"); return; } @@ -220,83 +230,154 @@ void StatsLogProcessor::onBinaryPushStateChangedEventLocked(LogEvent* event) { ALOGE("Failed to parse experimentids in binary push state changed."); return; } - vector<int64_t> experimentIdVector = {trainExperimentIds.experiment_id().begin(), - trainExperimentIds.experiment_id().end()}; + trainInfo.experimentIds = {trainExperimentIds.experiment_id().begin(), + trainExperimentIds.experiment_id().end()}; + // Update the train info on disk and get any data the logevent is missing. - getAndUpdateTrainInfoOnDisk( - state, &trainVersionCode, &trainName, &experimentIdVector); + getAndUpdateTrainInfoOnDisk(is_rollback, &trainInfo); std::vector<uint8_t> trainExperimentIdProto; - writeExperimentIdsToProto(experimentIdVector, &trainExperimentIdProto); + writeExperimentIdsToProto(trainInfo.experimentIds, &trainExperimentIdProto); int32_t userId = multiuser_get_user_id(uid); - event->updateValue(1 /*train name field id*/, trainName, STRING); - event->updateValue(2 /*train version field id*/, trainVersionCode, LONG); + event->updateValue(2 /*train version field id*/, trainInfo.trainVersionCode, LONG); #ifdef NEW_ENCODING_SCHEME event->updateValue(7 /*experiment ids field id*/, trainExperimentIdProto, STORAGE); #else event->updateValue(7 /*experiment ids field id*/, trainExperimentIdProto, STRING); #endif event->updateValue(8 /*user id field id*/, userId, INT); + + if (is_rollback) { + int bit = trainInfo.requiresStaging ? 1 : 0; + event->updateValue(3 /*requires staging field id*/, bit, INT); + bit = trainInfo.rollbackEnabled ? 1 : 0; + event->updateValue(4 /*rollback enabled field id*/, bit, INT); + bit = trainInfo.requiresLowLatencyMonitor ? 1 : 0; + event->updateValue(5 /*requires low latency monitor field id*/, bit, INT); + } } -void StatsLogProcessor::getAndUpdateTrainInfoOnDisk(int32_t state, - int64_t* trainVersionCode, - string* trainName, - std::vector<int64_t>* experimentIds) { +void StatsLogProcessor::getAndUpdateTrainInfoOnDisk(bool is_rollback, + InstallTrainInfo* trainInfo) { + // If the train name is empty, we don't know which train to attribute the + // event to, so return early. + if (trainInfo->trainName.empty()) { + return; + } bool readTrainInfoSuccess = false; InstallTrainInfo trainInfoOnDisk; - readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfoOnDisk); + readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo->trainName, trainInfoOnDisk); bool resetExperimentIds = false; if (readTrainInfoSuccess) { // Keep the old train version if we received an empty version. - if (*trainVersionCode == -1) { - *trainVersionCode = trainInfoOnDisk.trainVersionCode; - } else if (*trainVersionCode != trainInfoOnDisk.trainVersionCode) { - // Reset experiment ids if we receive a new non-empty train version. - resetExperimentIds = true; - } - - // Keep the old train name if we received an empty train name. - if (trainName->size() == 0) { - *trainName = trainInfoOnDisk.trainName; - } else if (*trainName != trainInfoOnDisk.trainName) { - // Reset experiment ids if we received a new valid train name. + if (trainInfo->trainVersionCode == -1) { + trainInfo->trainVersionCode = trainInfoOnDisk.trainVersionCode; + } else if (trainInfo->trainVersionCode != trainInfoOnDisk.trainVersionCode) { + // Reset experiment ids if we receive a new non-empty train version. resetExperimentIds = true; } // Reset if we received a different experiment id. - if (!experimentIds->empty() && - (trainInfoOnDisk.experimentIds.empty() || - experimentIds->at(0) != trainInfoOnDisk.experimentIds[0])) { + if (!trainInfo->experimentIds.empty() && + (trainInfoOnDisk.experimentIds.empty() || + trainInfo->experimentIds.at(0) != trainInfoOnDisk.experimentIds[0])) { resetExperimentIds = true; } } // Find the right experiment IDs - if (!resetExperimentIds && readTrainInfoSuccess) { - *experimentIds = trainInfoOnDisk.experimentIds; + if ((!resetExperimentIds || is_rollback) && readTrainInfoSuccess) { + trainInfo->experimentIds = trainInfoOnDisk.experimentIds; } - if (!experimentIds->empty()) { - int64_t firstId = experimentIds->at(0); - switch (state) { + if (!trainInfo->experimentIds.empty()) { + int64_t firstId = trainInfo->experimentIds.at(0); + switch (trainInfo->status) { case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS: - experimentIds->push_back(firstId + 1); + trainInfo->experimentIds.push_back(firstId + 1); break; case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED: - experimentIds->push_back(firstId + 2); + trainInfo->experimentIds.push_back(firstId + 2); break; case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS: - experimentIds->push_back(firstId + 3); + trainInfo->experimentIds.push_back(firstId + 3); break; } } - StorageManager::writeTrainInfo(*trainVersionCode, *trainName, state, *experimentIds); + if (is_rollback) { + trainInfo->requiresStaging = trainInfoOnDisk.requiresStaging; + trainInfo->rollbackEnabled = trainInfoOnDisk.rollbackEnabled; + trainInfo->requiresLowLatencyMonitor = trainInfoOnDisk.requiresLowLatencyMonitor; + } + + StorageManager::writeTrainInfo(*trainInfo); } +void StatsLogProcessor::onWatchdogRollbackOccurredLocked(LogEvent* event) { + pid_t pid = event->GetPid(); + uid_t uid = event->GetUid(); + if (!checkPermissionForIds(kPermissionDump, pid, uid) || + !checkPermissionForIds(kPermissionUsage, pid, uid)) { + return; + } + // The Get* functions don't modify the status on success, they only write in + // failure statuses, so we can use one status variable for all calls then + // check if it is no longer NO_ERROR. + status_t err = NO_ERROR; + int32_t rollbackType = int32_t(event->GetInt(1 /*rollback type field id*/, &err)); + string packageName = string(event->GetString(2 /*package name field id*/, &err)); + + if (err != NO_ERROR) { + ALOGE("Failed to parse fields in watchdog rollback occurred log event"); + return; + } + + vector<int64_t> experimentIds = + processWatchdogRollbackOccurred(rollbackType, packageName); + vector<uint8_t> experimentIdProto; + writeExperimentIdsToProto(experimentIds, &experimentIdProto); + +#ifdef NEW_ENCODING_SCHEME + event->updateValue(6 /*experiment ids field id*/, experimentIdProto, STORAGE); +#else + event->updateValue(6 /*experiment ids field id*/, experimentIdProto, STRING); +#endif +} + +vector<int64_t> StatsLogProcessor::processWatchdogRollbackOccurred(const int32_t rollbackTypeIn, + const string& packageNameIn) { + // If the package name is empty, we can't attribute it to any train, so + // return early. + if (packageNameIn.empty()) { + return vector<int64_t>(); + } + bool readTrainInfoSuccess = false; + InstallTrainInfo trainInfoOnDisk; + readTrainInfoSuccess = StorageManager::readTrainInfo(packageNameIn, trainInfoOnDisk); + + if (!readTrainInfoSuccess) { + return vector<int64_t>(); + } + + if (trainInfoOnDisk.experimentIds.empty()) { + return vector<int64_t>(); + } + switch (rollbackTypeIn) { + case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE: + trainInfoOnDisk.experimentIds.push_back(trainInfoOnDisk.experimentIds[0] + 4); + StorageManager::writeTrainInfo(trainInfoOnDisk); + break; + case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS: + trainInfoOnDisk.experimentIds.push_back(trainInfoOnDisk.experimentIds[0] + 5); + StorageManager::writeTrainInfo(trainInfoOnDisk); + break; + } + + return trainInfoOnDisk.experimentIds; +} void StatsLogProcessor::resetConfigs() { std::lock_guard<std::mutex> lock(mMetricsMutex); @@ -321,7 +402,13 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) { // Hard-coded logic to update train info on disk and fill in any information // this log event may be missing. if (event->GetTagId() == android::util::BINARY_PUSH_STATE_CHANGED) { - onBinaryPushStateChangedEventLocked(event); + onBinaryPushStateChangedEventLocked(event); + } + + // Hard-coded logic to update experiment ids on disk for certain rollback + // types and fill the rollback atom with experiment ids + if (event->GetTagId() == android::util::WATCHDOG_ROLLBACK_OCCURRED) { + onWatchdogRollbackOccurredLocked(event); } #ifdef VERY_VERBOSE_PRINTING |