Add whitelist atom field option

Whitelisted atoms can be triggered from any source
Test: stats-log-api-gen-test
Bug: 119217680
Change-Id: Ia5faed04d696b59ba4ffaab13f5046f943d8a8b7
This commit is contained in:
Andrei Onea
2019-01-30 15:28:36 +00:00
parent 72be7c2a2f
commit da01ea5b1c
9 changed files with 111 additions and 21 deletions

View File

@@ -82,4 +82,6 @@ extend google.protobuf.FieldOptions {
optional bool is_uid = 50001 [default = false];
optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
optional bool allow_from_any_uid = 50003 [default = false];
}

View File

@@ -110,7 +110,7 @@ message Atom {
PacketWakeupOccurred packet_wakeup_occurred = 44;
WallClockTimeShifted wall_clock_time_shifted = 45;
AnomalyDetected anomaly_detected = 46;
AppBreadcrumbReported app_breadcrumb_reported = 47;
AppBreadcrumbReported app_breadcrumb_reported = 47 [(allow_from_any_uid) = true];
AppStartOccurred app_start_occurred = 48;
AppStartCanceled app_start_canceled = 49;
AppStartFullyDrawn app_start_fully_drawn = 50;
@@ -121,7 +121,7 @@ message Atom {
AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
ShutdownSequenceReported shutdown_sequence_reported = 56;
BootSequenceReported boot_sequence_reported = 57;
DaveyOccurred davey_occurred = 58;
DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true];
OverlayStateChanged overlay_state_changed = 59;
ForegroundServiceStateChanged foreground_service_state_changed = 60;
CallStateChanged call_state_changed = 61;

View File

@@ -234,12 +234,22 @@ void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
VLOG("=========================Metric Reports End==========================");
}
// Consume the stats log if it's interesting to this metric.
void MetricsManager::onLogEvent(const LogEvent& event) {
if (!mConfigValid) {
return;
}
bool MetricsManager::checkLogCredentials(const LogEvent& event) {
if (android::util::AtomsInfo::kWhitelistedAtoms.find(event.GetTagId()) !=
android::util::AtomsInfo::kWhitelistedAtoms.end())
{
return true;
}
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
VLOG("log source %d not on the whitelist", event.GetUid());
return false;
}
return true;
}
bool MetricsManager::eventSanityCheck(const LogEvent& event) {
if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
// Check that app breadcrumb reported fields are valid.
status_t err = NO_ERROR;
@@ -249,23 +259,23 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
long appHookUid = event.GetLong(event.size()-2, &err);
if (err != NO_ERROR ) {
VLOG("APP_BREADCRUMB_REPORTED had error when parsing the uid");
return;
return false;
}
int32_t loggerUid = event.GetUid();
if (loggerUid != appHookUid && loggerUid != AID_STATSD) {
VLOG("APP_BREADCRUMB_REPORTED has invalid uid: claimed %ld but caller is %d",
appHookUid, loggerUid);
return;
return false;
}
// The state must be from 0,3. This part of code must be manually updated.
long appHookState = event.GetLong(event.size(), &err);
if (err != NO_ERROR ) {
VLOG("APP_BREADCRUMB_REPORTED had error when parsing the state field");
return;
return false;
} else if (appHookState < 0 || appHookState > 3) {
VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
return;
return false;
}
} else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
// Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
@@ -276,31 +286,42 @@ void MetricsManager::onLogEvent(const LogEvent& event) {
long jankUid = event.GetLong(1, &err);
if (err != NO_ERROR ) {
VLOG("Davey occurred had error when parsing the uid");
return;
return false;
}
int32_t loggerUid = event.GetUid();
if (loggerUid != jankUid && loggerUid != AID_STATSD) {
VLOG("DAVEY_OCCURRED has invalid uid: claimed %ld but caller is %d", jankUid,
loggerUid);
return;
return false;
}
long duration = event.GetLong(event.size(), &err);
if (err != NO_ERROR ) {
VLOG("Davey occurred had error when parsing the duration");
return;
return false;
} else if (duration > 100000) {
VLOG("Davey duration is unreasonably long: %ld", duration);
return;
}
} else {
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
VLOG("log source %d not on the whitelist", event.GetUid());
return;
return false;
}
}
return true;
}
// Consume the stats log if it's interesting to this metric.
void MetricsManager::onLogEvent(const LogEvent& event) {
if (!mConfigValid) {
return;
}
if (!checkLogCredentials(event)) {
return;
}
if (!eventSanityCheck(event)) {
return;
}
int tagId = event.GetTagId();
int64_t eventTimeNs = event.GetElapsedTimestampNs();

View File

@@ -48,6 +48,10 @@ public:
// Return whether the configuration is valid.
bool isConfigValid() const;
bool checkLogCredentials(const LogEvent& event);
bool eventSanityCheck(const LogEvent& event);
void onLogEvent(const LogEvent& event);
void onAnomalyAlarmFired(

View File

@@ -48,6 +48,7 @@ AtomDecl::AtomDecl(const AtomDecl& that)
primaryFields(that.primaryFields),
exclusiveField(that.exclusiveField),
uidField(that.uidField),
whitelisted(that.whitelisted),
binaryFields(that.binaryFields) {}
AtomDecl::AtomDecl(int c, const string& n, const string& m)
@@ -162,6 +163,7 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
vector<java_type_t> *signature) {
int errorCount = 0;
// Build a sorted list of the fields. Descriptor has them in source file
// order.
map<int, const FieldDescriptor *> fields;
@@ -387,6 +389,11 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
const Descriptor *atom = atomField->message_type();
AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
atomDecl.whitelisted = true;
}
vector<java_type_t> signature;
errorCount += collate_atom(atom, &atomDecl, &signature);
if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {

View File

@@ -89,6 +89,8 @@ struct AtomDecl {
int uidField = 0;
bool whitelisted = false;
vector<int> binaryFields;
AtomDecl();

View File

@@ -158,6 +158,20 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
}
}
}
fprintf(out, "};\n");
fprintf(out, "\n");
fprintf(out,
"const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
if (atom->whitelisted) {
string constant = make_constant_name(atom->name);
fprintf(out, " %s,\n", constant.c_str());
}
}
fprintf(out, "};\n");
fprintf(out, "\n");
@@ -728,6 +742,8 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio
fprintf(out,
" const static std::map<int, std::vector<int>> "
"kBytesFieldAtoms;");
fprintf(out,
" const static std::set<int> kWhitelistedAtoms;\n");
fprintf(out, "};\n");
fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",

View File

@@ -195,4 +195,22 @@ message GoodStateAtom3 {
[(android.os.statsd.state_field_option).option = PRIMARY];
optional int32 state = 3
[(android.os.statsd.state_field_option).option = EXCLUSIVE];
}
message WhitelistedAtom {
optional int32 field = 1;
}
message NonWhitelistedAtom {
optional int32 field = 1;
}
message ListedAtoms {
oneof event {
// Atoms can be whitelisted i.e. they can be triggered by any source
WhitelistedAtom whitelisted_atom = 1 [(android.os.statsd.allow_from_any_uid) = true];
// Atoms are not whitelisted by default, so they can only be triggered
// by whitelisted sources
NonWhitelistedAtom non_whitelisted_atom = 2;
}
}

View File

@@ -226,5 +226,25 @@ TEST(CollationTest, FailOnBadBinaryFieldAtom) {
EXPECT_TRUE(errorCount > 0);
}
TEST(CollationTest, PassOnWhitelistedAtom) {
Atoms atoms;
int errorCount =
collate_atoms(ListedAtoms::descriptor(), &atoms);
EXPECT_EQ(errorCount, 0);
EXPECT_EQ(atoms.decls.size(), 2ul);
}
TEST(CollationTest, RecogniseWhitelistedAtom) {
Atoms atoms;
collate_atoms(ListedAtoms::descriptor(), &atoms);
for (const auto& atomDecl : atoms.decls) {
if (atomDecl.code == 1) {
EXPECT_TRUE(atomDecl.whitelisted);
} else {
EXPECT_FALSE(atomDecl.whitelisted);
}
}
}
} // namespace stats_log_api_gen
} // namespace android