Update StatsLogProcessor to handle BinaryPushStateChanged
Also changed StatsLog to call write() instead of the hard coded function
in StatsService.
Test: gts-tradefed run gts-dev --module GtsStatsdHostTestCases
Change-Id: I26171fa4cfc877e1e179b74ec8076d964aff8548
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 879b3c3..bde15a5 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -20,13 +20,17 @@
#include "StatsLogProcessor.h"
#include <android-base/file.h>
+#include <cutils/multiuser.h>
#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
+#include <frameworks/base/cmds/statsd/src/experiment_ids.pb.h>
#include "android-base/stringprintf.h"
#include "atoms_info.h"
#include "external/StatsPullerManager.h"
#include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
#include "metrics/CountMetricProducer.h"
+#include "StatsService.h"
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
@@ -68,6 +72,10 @@
// for ActiveConfigList
const int FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG = 1;
+// for permissions checks
+constexpr const char* kPermissionDump = "android.permission.DUMP";
+constexpr const char* kPermissionUsage = "android.permission.PACKAGE_USAGE_STATS";
+
#define NS_PER_HOUR 3600 * NS_PER_SEC
#define STATS_ACTIVE_METRIC_DIR "/data/misc/stats-active-metric"
@@ -181,6 +189,115 @@
}
}
+void StatsLogProcessor::onBinaryPushStateChangedEventLocked(LogEvent* event) {
+ pid_t pid = event->GetPid();
+ uid_t uid = event->GetUid();
+ if (!checkPermissionForIds(kPermissionDump, pid, uid) ||
+ !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));
+#ifdef NEW_ENCODING_SCHEME
+ std::vector<uint8_t> trainExperimentIdBytes =
+ event->GetStorage(7 /*experiment ids field id*/, &err4);
+#else
+ string trainExperimentIdString = event->GetString(7 /*experiment ids field id*/, &err4);
+#endif
+ if (err != NO_ERROR || err2 != NO_ERROR || err3 != NO_ERROR || err4 != NO_ERROR) {
+ ALOGE("Failed to parse fields in binary push state changed log event");
+ return;
+ }
+ ExperimentIds trainExperimentIds;
+#ifdef NEW_ENCODING_SCHEME
+ if (!trainExperimentIds.ParseFromArray(trainExperimentIdBytes.data(),
+ trainExperimentIdBytes.size())) {
+#else
+ if (!trainExperimentIds.ParseFromString(trainExperimentIdString)) {
+#endif
+ ALOGE("Failed to parse experimentids in binary push state changed.");
+ return;
+ }
+ vector<int64_t> experimentIdVector = {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);
+
+ std::vector<uint8_t> trainExperimentIdProto;
+ writeExperimentIdsToProto(experimentIdVector, &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);
+#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);
+}
+
+void StatsLogProcessor::getAndUpdateTrainInfoOnDisk(int32_t state,
+ int64_t* trainVersionCode,
+ string* trainName,
+ std::vector<int64_t>* experimentIds) {
+ bool readTrainInfoSuccess = false;
+ InstallTrainInfo trainInfoOnDisk;
+ readTrainInfoSuccess = StorageManager::readTrainInfo(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.
+ resetExperimentIds = true;
+ }
+
+ // Reset if we received a different experiment id.
+ if (!experimentIds->empty() &&
+ (trainInfoOnDisk.experimentIds.empty() ||
+ experimentIds->at(0) != trainInfoOnDisk.experimentIds[0])) {
+ resetExperimentIds = true;
+ }
+ }
+
+ // Find the right experiment IDs
+ if (!resetExperimentIds && readTrainInfoSuccess) {
+ *experimentIds = trainInfoOnDisk.experimentIds;
+ }
+
+ if (!experimentIds->empty()) {
+ int64_t firstId = experimentIds->at(0);
+ switch (state) {
+ case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
+ experimentIds->push_back(firstId + 1);
+ break;
+ case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
+ experimentIds->push_back(firstId + 2);
+ break;
+ case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
+ experimentIds->push_back(firstId + 3);
+ break;
+ }
+ }
+
+ StorageManager::writeTrainInfo(*trainVersionCode, *trainName, state, *experimentIds);
+}
+
+
void StatsLogProcessor::resetConfigs() {
std::lock_guard<std::mutex> lock(mMetricsMutex);
resetConfigsLocked(getElapsedRealtimeNs());
@@ -201,6 +318,12 @@
void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
+ // 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);
+ }
+
#ifdef VERY_VERBOSE_PRINTING
if (mPrintAllLogs) {
ALOGI("%s", event->ToString().c_str());