Loading cmds/statsd/src/StatsService.cpp +40 −23 Original line number Diff line number Diff line Loading @@ -65,8 +65,6 @@ constexpr const char* kOpUsage = "android:get_usage_stats"; // for StatsDataDumpProto const int FIELD_ID_REPORTS_LIST = 1; // for TrainInfo experiment id serialization const int FIELD_ID_EXPERIMENT_ID = 1; static binder::Status ok() { return binder::Status::ok(); Loading Loading @@ -1181,7 +1179,7 @@ Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& p Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName, int64_t trainVersionCode, int options, int32_t state, const std::vector<int64_t>& experimentIds) { const std::vector<int64_t>& experimentIdsIn) { uid_t uid = IPCThreadState::self()->getCallingUid(); // For testing if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) { Loading @@ -1201,7 +1199,7 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra bool readTrainInfoSuccess = false; InstallTrainInfo trainInfo; if (trainVersionCode == -1 || experimentIds.empty() || trainName.size() == 0) { if (trainVersionCode == -1 || experimentIdsIn.empty() || trainName.size() == 0) { readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo); } Loading @@ -1209,27 +1207,19 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra trainVersionCode = trainInfo.trainVersionCode; } vector<uint8_t> experimentIdsProtoBuffer; if (readTrainInfoSuccess && experimentIds.empty()) { experimentIdsProtoBuffer = trainInfo.experimentIds; // Find the right experiment IDs std::vector<int64_t> experimentIds; if (readTrainInfoSuccess && experimentIdsIn.empty()) { experimentIds = trainInfo.experimentIds; } else { ProtoOutputStream proto; for (const auto& expId : experimentIds) { proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID, (long long)expId); experimentIds = experimentIdsIn; } experimentIdsProtoBuffer.resize(proto.size()); size_t pos = 0; sp<ProtoReader> reader = proto.data(); while (reader->readBuffer() != NULL) { size_t toRead = reader->currentToRead(); std::memcpy(&(experimentIdsProtoBuffer[pos]), reader->readBuffer(), toRead); pos += toRead; reader->move(toRead); } } // Flatten the experiment IDs to proto vector<uint8_t> experimentIdsProtoBuffer; writeExperimentIdsToProto(experimentIds, &experimentIdsProtoBuffer); // Find the right train name std::string trainNameUtf8; if (readTrainInfoSuccess && trainName.size() == 0) { trainNameUtf8 = trainInfo.trainName; Loading @@ -1244,7 +1234,34 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled, requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId); mProcessor->OnLogEvent(&event); StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIdsProtoBuffer); StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds); return Status::ok(); } Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) { uid_t uid = IPCThreadState::self()->getCallingUid(); // Caller must be granted these permissions if (!checkCallingPermission(String16(kPermissionDump))) { return exception(binder::Status::EX_SECURITY, StringPrintf("UID %d lacks permission %s", uid, kPermissionDump)); } if (!checkCallingPermission(String16(kPermissionUsage))) { return exception(binder::Status::EX_SECURITY, StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage)); } // TODO: add verifier permission // Read the latest train info InstallTrainInfo trainInfo; if (!StorageManager::readTrainInfo(trainInfo)) { // No train info means no experiment IDs, return an empty list experimentIdsOut->clear(); return Status::ok(); } // Copy the experiment IDs to the out vector experimentIdsOut->assign(trainInfo.experimentIds.begin(), trainInfo.experimentIds.end()); return Status::ok(); } Loading cmds/statsd/src/StatsService.h +5 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,11 @@ public: const android::String16& trainName, int64_t trainVersionCode, int options, int32_t state, const std::vector<int64_t>& experimentIds) override; /** * Binder call to get registered experiment IDs. */ virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut); /** * Binder call to get SpeakerImpedance atom. */ Loading cmds/statsd/src/logd/LogEvent.cpp +24 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ namespace android { namespace os { namespace statsd { // for TrainInfo experiment id serialization const int FIELD_ID_EXPERIMENT_ID = 1; using namespace android::util; using android::util::ProtoOutputStream; using std::string; Loading Loading @@ -241,7 +244,9 @@ LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, mValues.push_back( FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode))); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainInfo.experimentIds))); std::vector<uint8_t> experimentIdsProto; writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto))); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName))); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status))); } Loading Loading @@ -671,6 +676,24 @@ void LogEvent::ToProto(ProtoOutputStream& protoOutput) const { writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput); } void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut) { ProtoOutputStream proto; for (const auto& expId : experimentIds) { proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID, (long long)expId); } protoOut->resize(proto.size()); size_t pos = 0; sp<ProtoReader> reader = proto.data(); while (reader->readBuffer() != NULL) { size_t toRead = reader->currentToRead(); std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead); pos += toRead; reader->move(toRead); } } } // namespace statsd } // namespace os } // namespace android cmds/statsd/src/logd/LogEvent.h +4 −1 Original line number Diff line number Diff line Loading @@ -60,8 +60,9 @@ struct InstallTrainInfo { int64_t trainVersionCode; std::string trainName; int32_t status; std::vector<uint8_t> experimentIds; std::vector<int64_t> experimentIds; }; /** * Wrapper for the log_msg structure. */ Loading Loading @@ -239,6 +240,8 @@ private: uint32_t mLogUid; }; void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut); } // namespace statsd } // namespace os } // namespace android Loading cmds/statsd/src/storage/StorageManager.cpp +123 −88 Original line number Diff line number Diff line Loading @@ -36,9 +36,17 @@ using android::util::FIELD_COUNT_REPEATED; using android::util::FIELD_TYPE_MESSAGE; using std::map; /** * NOTE: these directories are protected by SELinux, any changes here must also update * the SELinux policies. */ #define STATS_DATA_DIR "/data/misc/stats-data" #define STATS_SERVICE_DIR "/data/misc/stats-service" #define TRAIN_INFO_DIR "/data/misc/train-info" #define TRAIN_INFO_PATH "/data/misc/train-info/train-info.bin" // Magic word at the start of the train info file, change this if changing the file format const uint32_t TRAIN_INFO_FILE_MAGIC = 0xff7447ff; // for ConfigMetricsReportList const int FIELD_ID_REPORTS = 2; Loading Loading @@ -96,27 +104,42 @@ void StorageManager::writeFile(const char* file, const void* buffer, int numByte } bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& trainName, int32_t status, const std::vector<uint8_t>& experimentIds) { int32_t status, const std::vector<int64_t>& experimentIds) { std::lock_guard<std::mutex> lock(sTrainInfoMutex); deleteAllFiles(TRAIN_INFO_DIR); string file_name = StringPrintf("%s/%lld", TRAIN_INFO_DIR, (long long)trainVersionCode); int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); int fd = open(TRAIN_INFO_PATH, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); if (fd == -1) { VLOG("Attempt to access %s but failed", file_name.c_str()); VLOG("Attempt to access %s but failed", TRAIN_INFO_PATH); return false; } size_t result; // Write the magic word result = write(fd, &TRAIN_INFO_FILE_MAGIC, sizeof(TRAIN_INFO_FILE_MAGIC)); if (result != sizeof(TRAIN_INFO_FILE_MAGIC)) { VLOG("Failed to wrtie train info magic"); close(fd); return false; } // Write the train version const size_t trainVersionCodeByteCount = sizeof(trainVersionCode); result = write(fd, &trainVersionCode, trainVersionCodeByteCount); if (result != trainVersionCodeByteCount) { VLOG("Failed to wrtie train version code"); close(fd); return false; } // Write # of bytes in trainName to file const size_t trainNameSize = trainName.size(); const size_t trainNameSizeByteCount = sizeof(trainNameSize); result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount); if (result != trainNameSizeByteCount) { VLOG("Failed to write train name size for %s", file_name.c_str()); VLOG("Failed to write train name size"); close(fd); return false; } Loading @@ -124,7 +147,7 @@ bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& // Write trainName to file result = write(fd, trainName.c_str(), trainNameSize); if (result != trainNameSize) { VLOG("Failed to write train name for%s", file_name.c_str()); VLOG("Failed to write train name"); close(fd); return false; } Loading @@ -133,34 +156,38 @@ bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& const size_t statusByteCount = sizeof(status); result = write(fd, (uint8_t*)&status, statusByteCount); if (result != statusByteCount) { VLOG("Failed to write status for %s", file_name.c_str()); VLOG("Failed to write status"); close(fd); return false; } // Write experiment id size to file. const size_t experimentIdSize = experimentIds.size(); const size_t experimentIdsSizeByteCount = sizeof(experimentIdSize); result = write(fd, (uint8_t*) &experimentIdSize, experimentIdsSizeByteCount); if (result != experimentIdsSizeByteCount) { VLOG("Failed to write experiment id size for %s", file_name.c_str()); // Write experiment id count to file. const size_t experimentIdsCount = experimentIds.size(); const size_t experimentIdsCountByteCount = sizeof(experimentIdsCount); result = write(fd, (uint8_t*) &experimentIdsCount, experimentIdsCountByteCount); if (result != experimentIdsCountByteCount) { VLOG("Failed to write experiment id count"); close(fd); return false; } // Write experimentIds to file result = write(fd, experimentIds.data(), experimentIds.size()); if (result == experimentIds.size()) { VLOG("Successfully wrote %s", file_name.c_str()); for (size_t i = 0; i < experimentIdsCount; i++) { const int64_t experimentId = experimentIds[i]; const size_t experimentIdByteCount = sizeof(experimentId); result = write(fd, &experimentId, experimentIdByteCount); if (result == experimentIdByteCount) { VLOG("Successfully wrote experiment IDs"); } else { VLOG("Failed to write experiment ids for %s", file_name.c_str()); VLOG("Failed to write experiment ids"); close(fd); return false; } } result = fchown(fd, AID_STATSD, AID_STATSD); if (result) { VLOG("Failed to chown %s to statsd", file_name.c_str()); VLOG("Failed to chown train info file to statsd"); close(fd); return false; } Loading @@ -172,26 +199,33 @@ bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { std::lock_guard<std::mutex> lock(sTrainInfoMutex); unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir); if (dir == NULL) { VLOG("Directory does not exist: %s", TRAIN_INFO_DIR); int fd = open(TRAIN_INFO_PATH, O_RDONLY | O_CLOEXEC); if (fd == -1) { VLOG("Failed to open train-info.bin"); return false; } dirent* de; while ((de = readdir(dir.get()))) { char* name = de->d_name; if (name[0] == '.') { continue; // Read the magic word uint32_t magic; size_t result = read(fd, &magic, sizeof(magic)); if (result != sizeof(magic)) { VLOG("Failed to read train info magic"); close(fd); return false; } size_t result; if (magic != TRAIN_INFO_FILE_MAGIC) { VLOG("Train info magic was 0x%08x, expected 0x%08x", magic, TRAIN_INFO_FILE_MAGIC); close(fd); return false; } trainInfo.trainVersionCode = StrToInt64(name); string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name); int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC); if (fd == -1) { // Read the train version code const size_t trainVersionCodeByteCount(sizeof(trainInfo.trainVersionCode)); result = read(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount); if (result != trainVersionCodeByteCount) { VLOG("Failed to read train version code from train info file"); close(fd); return false; } Loading @@ -199,7 +233,7 @@ bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { size_t trainNameSize; result = read(fd, &trainNameSize, sizeof(size_t)); if (result != sizeof(size_t)) { VLOG("Failed to read train name size from file %s", fullPath.c_str()); VLOG("Failed to read train name size from train info file"); close(fd); return false; } Loading @@ -208,7 +242,7 @@ bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { trainInfo.trainName.resize(trainNameSize); result = read(fd, trainInfo.trainName.data(), trainNameSize); if (result != trainNameSize) { VLOG("Failed to read train name from file %s", fullPath.c_str()); VLOG("Failed to read train name from train info file"); close(fd); return false; } Loading @@ -217,44 +251,45 @@ bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { const size_t statusByteCount = sizeof(trainInfo.status); result = read(fd, &trainInfo.status, statusByteCount); if (result != statusByteCount) { VLOG("Failed to read train status from file %s", fullPath.c_str()); VLOG("Failed to read train status from train info file"); close(fd); return false; } // Read experiment ids size. size_t experimentIdSize; result = read(fd, &experimentIdSize, sizeof(size_t)); // Read experiment ids count. size_t experimentIdsCount; result = read(fd, &experimentIdsCount, sizeof(size_t)); if (result != sizeof(size_t)) { VLOG("Failed to read train experiment id size from file %s", fullPath.c_str()); VLOG("Failed to read train experiment id count from train info file"); close(fd); return false; } // Read experimentIds trainInfo.experimentIds.resize(experimentIdSize); result = read(fd, trainInfo.experimentIds.data(), experimentIdSize); if (result != experimentIdSize) { VLOG("Failed to read train experiment ids from file %s", fullPath.c_str()); for (size_t i = 0; i < experimentIdsCount; i++) { int64_t experimentId; result = read(fd, &experimentId, sizeof(experimentId)); if (result != sizeof(experimentId)) { VLOG("Failed to read train experiment id from train info file"); close(fd); return false; } trainInfo.experimentIds.push_back(experimentId); } // Expect to be at EOF. char c; result = read(fd, &c, 1); if (result != 0) { VLOG("Failed to read train info from file %s. Did not get expected EOF.", fullPath.c_str()); VLOG("Failed to read train info from file. Did not get expected EOF."); close(fd); return false; } VLOG("Read train info file successful: %s", fullPath.c_str()); VLOG("Read train info file successful"); close(fd); return true; } return false; } void StorageManager::deleteFile(const char* file) { if (remove(file) != 0) { Loading Loading
cmds/statsd/src/StatsService.cpp +40 −23 Original line number Diff line number Diff line Loading @@ -65,8 +65,6 @@ constexpr const char* kOpUsage = "android:get_usage_stats"; // for StatsDataDumpProto const int FIELD_ID_REPORTS_LIST = 1; // for TrainInfo experiment id serialization const int FIELD_ID_EXPERIMENT_ID = 1; static binder::Status ok() { return binder::Status::ok(); Loading Loading @@ -1181,7 +1179,7 @@ Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& p Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName, int64_t trainVersionCode, int options, int32_t state, const std::vector<int64_t>& experimentIds) { const std::vector<int64_t>& experimentIdsIn) { uid_t uid = IPCThreadState::self()->getCallingUid(); // For testing if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) { Loading @@ -1201,7 +1199,7 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra bool readTrainInfoSuccess = false; InstallTrainInfo trainInfo; if (trainVersionCode == -1 || experimentIds.empty() || trainName.size() == 0) { if (trainVersionCode == -1 || experimentIdsIn.empty() || trainName.size() == 0) { readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo); } Loading @@ -1209,27 +1207,19 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra trainVersionCode = trainInfo.trainVersionCode; } vector<uint8_t> experimentIdsProtoBuffer; if (readTrainInfoSuccess && experimentIds.empty()) { experimentIdsProtoBuffer = trainInfo.experimentIds; // Find the right experiment IDs std::vector<int64_t> experimentIds; if (readTrainInfoSuccess && experimentIdsIn.empty()) { experimentIds = trainInfo.experimentIds; } else { ProtoOutputStream proto; for (const auto& expId : experimentIds) { proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID, (long long)expId); experimentIds = experimentIdsIn; } experimentIdsProtoBuffer.resize(proto.size()); size_t pos = 0; sp<ProtoReader> reader = proto.data(); while (reader->readBuffer() != NULL) { size_t toRead = reader->currentToRead(); std::memcpy(&(experimentIdsProtoBuffer[pos]), reader->readBuffer(), toRead); pos += toRead; reader->move(toRead); } } // Flatten the experiment IDs to proto vector<uint8_t> experimentIdsProtoBuffer; writeExperimentIdsToProto(experimentIds, &experimentIdsProtoBuffer); // Find the right train name std::string trainNameUtf8; if (readTrainInfoSuccess && trainName.size() == 0) { trainNameUtf8 = trainInfo.trainName; Loading @@ -1244,7 +1234,34 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled, requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId); mProcessor->OnLogEvent(&event); StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIdsProtoBuffer); StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds); return Status::ok(); } Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) { uid_t uid = IPCThreadState::self()->getCallingUid(); // Caller must be granted these permissions if (!checkCallingPermission(String16(kPermissionDump))) { return exception(binder::Status::EX_SECURITY, StringPrintf("UID %d lacks permission %s", uid, kPermissionDump)); } if (!checkCallingPermission(String16(kPermissionUsage))) { return exception(binder::Status::EX_SECURITY, StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage)); } // TODO: add verifier permission // Read the latest train info InstallTrainInfo trainInfo; if (!StorageManager::readTrainInfo(trainInfo)) { // No train info means no experiment IDs, return an empty list experimentIdsOut->clear(); return Status::ok(); } // Copy the experiment IDs to the out vector experimentIdsOut->assign(trainInfo.experimentIds.begin(), trainInfo.experimentIds.end()); return Status::ok(); } Loading
cmds/statsd/src/StatsService.h +5 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,11 @@ public: const android::String16& trainName, int64_t trainVersionCode, int options, int32_t state, const std::vector<int64_t>& experimentIds) override; /** * Binder call to get registered experiment IDs. */ virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut); /** * Binder call to get SpeakerImpedance atom. */ Loading
cmds/statsd/src/logd/LogEvent.cpp +24 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,9 @@ namespace android { namespace os { namespace statsd { // for TrainInfo experiment id serialization const int FIELD_ID_EXPERIMENT_ID = 1; using namespace android::util; using android::util::ProtoOutputStream; using std::string; Loading Loading @@ -241,7 +244,9 @@ LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs, mValues.push_back( FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode))); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainInfo.experimentIds))); std::vector<uint8_t> experimentIdsProto; writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto))); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName))); mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status))); } Loading Loading @@ -671,6 +676,24 @@ void LogEvent::ToProto(ProtoOutputStream& protoOutput) const { writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput); } void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut) { ProtoOutputStream proto; for (const auto& expId : experimentIds) { proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID, (long long)expId); } protoOut->resize(proto.size()); size_t pos = 0; sp<ProtoReader> reader = proto.data(); while (reader->readBuffer() != NULL) { size_t toRead = reader->currentToRead(); std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead); pos += toRead; reader->move(toRead); } } } // namespace statsd } // namespace os } // namespace android
cmds/statsd/src/logd/LogEvent.h +4 −1 Original line number Diff line number Diff line Loading @@ -60,8 +60,9 @@ struct InstallTrainInfo { int64_t trainVersionCode; std::string trainName; int32_t status; std::vector<uint8_t> experimentIds; std::vector<int64_t> experimentIds; }; /** * Wrapper for the log_msg structure. */ Loading Loading @@ -239,6 +240,8 @@ private: uint32_t mLogUid; }; void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut); } // namespace statsd } // namespace os } // namespace android Loading
cmds/statsd/src/storage/StorageManager.cpp +123 −88 Original line number Diff line number Diff line Loading @@ -36,9 +36,17 @@ using android::util::FIELD_COUNT_REPEATED; using android::util::FIELD_TYPE_MESSAGE; using std::map; /** * NOTE: these directories are protected by SELinux, any changes here must also update * the SELinux policies. */ #define STATS_DATA_DIR "/data/misc/stats-data" #define STATS_SERVICE_DIR "/data/misc/stats-service" #define TRAIN_INFO_DIR "/data/misc/train-info" #define TRAIN_INFO_PATH "/data/misc/train-info/train-info.bin" // Magic word at the start of the train info file, change this if changing the file format const uint32_t TRAIN_INFO_FILE_MAGIC = 0xff7447ff; // for ConfigMetricsReportList const int FIELD_ID_REPORTS = 2; Loading Loading @@ -96,27 +104,42 @@ void StorageManager::writeFile(const char* file, const void* buffer, int numByte } bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& trainName, int32_t status, const std::vector<uint8_t>& experimentIds) { int32_t status, const std::vector<int64_t>& experimentIds) { std::lock_guard<std::mutex> lock(sTrainInfoMutex); deleteAllFiles(TRAIN_INFO_DIR); string file_name = StringPrintf("%s/%lld", TRAIN_INFO_DIR, (long long)trainVersionCode); int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); int fd = open(TRAIN_INFO_PATH, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); if (fd == -1) { VLOG("Attempt to access %s but failed", file_name.c_str()); VLOG("Attempt to access %s but failed", TRAIN_INFO_PATH); return false; } size_t result; // Write the magic word result = write(fd, &TRAIN_INFO_FILE_MAGIC, sizeof(TRAIN_INFO_FILE_MAGIC)); if (result != sizeof(TRAIN_INFO_FILE_MAGIC)) { VLOG("Failed to wrtie train info magic"); close(fd); return false; } // Write the train version const size_t trainVersionCodeByteCount = sizeof(trainVersionCode); result = write(fd, &trainVersionCode, trainVersionCodeByteCount); if (result != trainVersionCodeByteCount) { VLOG("Failed to wrtie train version code"); close(fd); return false; } // Write # of bytes in trainName to file const size_t trainNameSize = trainName.size(); const size_t trainNameSizeByteCount = sizeof(trainNameSize); result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount); if (result != trainNameSizeByteCount) { VLOG("Failed to write train name size for %s", file_name.c_str()); VLOG("Failed to write train name size"); close(fd); return false; } Loading @@ -124,7 +147,7 @@ bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& // Write trainName to file result = write(fd, trainName.c_str(), trainNameSize); if (result != trainNameSize) { VLOG("Failed to write train name for%s", file_name.c_str()); VLOG("Failed to write train name"); close(fd); return false; } Loading @@ -133,34 +156,38 @@ bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& const size_t statusByteCount = sizeof(status); result = write(fd, (uint8_t*)&status, statusByteCount); if (result != statusByteCount) { VLOG("Failed to write status for %s", file_name.c_str()); VLOG("Failed to write status"); close(fd); return false; } // Write experiment id size to file. const size_t experimentIdSize = experimentIds.size(); const size_t experimentIdsSizeByteCount = sizeof(experimentIdSize); result = write(fd, (uint8_t*) &experimentIdSize, experimentIdsSizeByteCount); if (result != experimentIdsSizeByteCount) { VLOG("Failed to write experiment id size for %s", file_name.c_str()); // Write experiment id count to file. const size_t experimentIdsCount = experimentIds.size(); const size_t experimentIdsCountByteCount = sizeof(experimentIdsCount); result = write(fd, (uint8_t*) &experimentIdsCount, experimentIdsCountByteCount); if (result != experimentIdsCountByteCount) { VLOG("Failed to write experiment id count"); close(fd); return false; } // Write experimentIds to file result = write(fd, experimentIds.data(), experimentIds.size()); if (result == experimentIds.size()) { VLOG("Successfully wrote %s", file_name.c_str()); for (size_t i = 0; i < experimentIdsCount; i++) { const int64_t experimentId = experimentIds[i]; const size_t experimentIdByteCount = sizeof(experimentId); result = write(fd, &experimentId, experimentIdByteCount); if (result == experimentIdByteCount) { VLOG("Successfully wrote experiment IDs"); } else { VLOG("Failed to write experiment ids for %s", file_name.c_str()); VLOG("Failed to write experiment ids"); close(fd); return false; } } result = fchown(fd, AID_STATSD, AID_STATSD); if (result) { VLOG("Failed to chown %s to statsd", file_name.c_str()); VLOG("Failed to chown train info file to statsd"); close(fd); return false; } Loading @@ -172,26 +199,33 @@ bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { std::lock_guard<std::mutex> lock(sTrainInfoMutex); unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir); if (dir == NULL) { VLOG("Directory does not exist: %s", TRAIN_INFO_DIR); int fd = open(TRAIN_INFO_PATH, O_RDONLY | O_CLOEXEC); if (fd == -1) { VLOG("Failed to open train-info.bin"); return false; } dirent* de; while ((de = readdir(dir.get()))) { char* name = de->d_name; if (name[0] == '.') { continue; // Read the magic word uint32_t magic; size_t result = read(fd, &magic, sizeof(magic)); if (result != sizeof(magic)) { VLOG("Failed to read train info magic"); close(fd); return false; } size_t result; if (magic != TRAIN_INFO_FILE_MAGIC) { VLOG("Train info magic was 0x%08x, expected 0x%08x", magic, TRAIN_INFO_FILE_MAGIC); close(fd); return false; } trainInfo.trainVersionCode = StrToInt64(name); string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name); int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC); if (fd == -1) { // Read the train version code const size_t trainVersionCodeByteCount(sizeof(trainInfo.trainVersionCode)); result = read(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount); if (result != trainVersionCodeByteCount) { VLOG("Failed to read train version code from train info file"); close(fd); return false; } Loading @@ -199,7 +233,7 @@ bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { size_t trainNameSize; result = read(fd, &trainNameSize, sizeof(size_t)); if (result != sizeof(size_t)) { VLOG("Failed to read train name size from file %s", fullPath.c_str()); VLOG("Failed to read train name size from train info file"); close(fd); return false; } Loading @@ -208,7 +242,7 @@ bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { trainInfo.trainName.resize(trainNameSize); result = read(fd, trainInfo.trainName.data(), trainNameSize); if (result != trainNameSize) { VLOG("Failed to read train name from file %s", fullPath.c_str()); VLOG("Failed to read train name from train info file"); close(fd); return false; } Loading @@ -217,44 +251,45 @@ bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) { const size_t statusByteCount = sizeof(trainInfo.status); result = read(fd, &trainInfo.status, statusByteCount); if (result != statusByteCount) { VLOG("Failed to read train status from file %s", fullPath.c_str()); VLOG("Failed to read train status from train info file"); close(fd); return false; } // Read experiment ids size. size_t experimentIdSize; result = read(fd, &experimentIdSize, sizeof(size_t)); // Read experiment ids count. size_t experimentIdsCount; result = read(fd, &experimentIdsCount, sizeof(size_t)); if (result != sizeof(size_t)) { VLOG("Failed to read train experiment id size from file %s", fullPath.c_str()); VLOG("Failed to read train experiment id count from train info file"); close(fd); return false; } // Read experimentIds trainInfo.experimentIds.resize(experimentIdSize); result = read(fd, trainInfo.experimentIds.data(), experimentIdSize); if (result != experimentIdSize) { VLOG("Failed to read train experiment ids from file %s", fullPath.c_str()); for (size_t i = 0; i < experimentIdsCount; i++) { int64_t experimentId; result = read(fd, &experimentId, sizeof(experimentId)); if (result != sizeof(experimentId)) { VLOG("Failed to read train experiment id from train info file"); close(fd); return false; } trainInfo.experimentIds.push_back(experimentId); } // Expect to be at EOF. char c; result = read(fd, &c, 1); if (result != 0) { VLOG("Failed to read train info from file %s. Did not get expected EOF.", fullPath.c_str()); VLOG("Failed to read train info from file. Did not get expected EOF."); close(fd); return false; } VLOG("Read train info file successful: %s", fullPath.c_str()); VLOG("Read train info file successful"); close(fd); return true; } return false; } void StorageManager::deleteFile(const char* file) { if (remove(file) != 0) { Loading