Add truncate_timestamp annotation

Mark privacy-sensitive atoms with truncate_timestamp annotation.

Factor out annotation collation to a helper method.

Add truncate_timestamp annotation support in stats-log-api-gen.

Add writeAnnotation* calls in Java and native generated code for
atom id annotations.

TODO: remove kTruncatingTimestampAtoms from atoms_info.
TODO: use truncate_timestamp annotation inside statsd.

Bug: 151111680
Test: stats-log-api-gen-test
Test: m statslog-framework-java-gen
Test: m libstatsmetadata

Change-Id: I3db5f4ffbf959bd36c62f890cc88606912798d40
This commit is contained in:
Muhammad Qureshi
2020-03-20 13:55:51 -07:00
parent ffd92af9a5
commit 9b995809fb
6 changed files with 164 additions and 128 deletions

View File

@@ -117,4 +117,6 @@ extend google.protobuf.FieldOptions {
optional bool allow_from_any_uid = 50003 [default = false];
repeated string module = 50004;
optional bool truncate_timestamp = 50005 [default = false];
}

View File

@@ -93,7 +93,8 @@ message Atom {
10 [(module) = "framework", (module) = "statsdtest"];
LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
11 [(module) = "framework"];
MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12 [(module) = "framework"];
MobileRadioPowerStateChanged mobile_radio_power_state_changed =
12 [(module) = "framework", (truncate_timestamp) = true];
WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13 [(module) = "framework"];
ActivityManagerSleepStateChanged activity_manager_sleep_state_changed =
14 [(module) = "framework"];
@@ -106,7 +107,8 @@ message Atom {
20 [(module) = "framework", (module) = "statsdtest"];
DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(module) = "framework"];
AudioStateChanged audio_state_changed = 23 [(module) = "framework"];
AudioStateChanged audio_state_changed =
23 [(module) = "framework", (truncate_timestamp) = true];
MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
@@ -127,7 +129,8 @@ message Atom {
WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
WifiScanStateChanged wifi_scan_state_changed = 39 [(module) = "wifi"];
PhoneSignalStrengthChanged phone_signal_strength_changed = 40 [(module) = "framework"];
PhoneSignalStrengthChanged phone_signal_strength_changed =
40 [(module) = "framework", (truncate_timestamp) = true];
SettingChanged setting_changed = 41 [(module) = "framework"];
ActivityForegroundStateChanged activity_foreground_state_changed =
42 [(module) = "framework", (module) = "statsdtest"];
@@ -153,7 +156,8 @@ message Atom {
59 [(module) = "framework", (module) = "statsdtest"];
ForegroundServiceStateChanged foreground_service_state_changed
= 60 [(module) = "framework"];
CallStateChanged call_state_changed = 61 [(module) = "telecom"];
CallStateChanged call_state_changed =
61 [(module) = "telecom", (truncate_timestamp) = true];
KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
@@ -419,8 +423,10 @@ message Atom {
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
MobileBytesTransfer mobile_bytes_transfer = 10002 [(module) = "framework"];
MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003 [(module) = "framework"];
MobileBytesTransfer mobile_bytes_transfer =
10002 [(module) = "framework", (truncate_timestamp) = true];
MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg =
10003 [(module) = "framework", (truncate_timestamp) = true];
BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];

View File

@@ -55,7 +55,8 @@ AtomDecl::AtomDecl(const AtomDecl &that)
resetState(that.resetState),
nested(that.nested),
uidField(that.uidField),
whitelisted(that.whitelisted) {}
whitelisted(that.whitelisted),
truncateTimestamp(that.truncateTimestamp) {}
AtomDecl::AtomDecl(int c, const string& n, const string& m)
:code(c),
@@ -173,6 +174,126 @@ static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
annotationId, atomDecl->code, annotationType, annotationValue));
}
static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
const int fieldNumber, const java_type_t& javaType) {
int errorCount = 0;
if (field->options().HasExtension(os::statsd::state_field_option)) {
const int option = field->options().GetExtension(os::statsd::state_field_option).option();
if (option != STATE_OPTION_UNSET) {
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_OPTION,
ANNOTATION_TYPE_INT, AnnotationValue(option));
}
if (option == STATE_OPTION_PRIMARY) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
print_error(
field,
"Invalid primary state field: '%s'\n",
atomDecl->message.c_str());
errorCount++;
}
atomDecl->primaryFields.push_back(fieldNumber);
}
if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
print_error(
field,
"PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n",
atomDecl->message.c_str());
errorCount++;
} else {
atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
}
}
if (option == STATE_OPTION_EXCLUSIVE) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
print_error(
field,
"Invalid exclusive state field: '%s'\n",
atomDecl->message.c_str());
errorCount++;
}
if (atomDecl->exclusiveField == 0) {
atomDecl->exclusiveField = fieldNumber;
} else {
print_error(
field,
"Cannot have more than one exclusive state field in an atom: '%s'\n",
atomDecl->message.c_str());
errorCount++;
}
if (field->options()
.GetExtension(os::statsd::state_field_option)
.has_default_state_value()) {
const int defaultState =
field->options().GetExtension(os::statsd::state_field_option)
.default_state_value();
atomDecl->defaultState = defaultState;
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
}
if (field->options().GetExtension(os::statsd::state_field_option)
.has_reset_state_value()) {
const int resetState = field->options()
.GetExtension(os::statsd::state_field_option)
.reset_state_value();
atomDecl->resetState = resetState;
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_RESET_STATE,
ANNOTATION_TYPE_INT, AnnotationValue(resetState));
}
if (field->options().GetExtension(os::statsd::state_field_option)
.has_nested()) {
const bool nested =
field->options().GetExtension(os::statsd::state_field_option).nested();
atomDecl->nested = nested;
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
}
}
}
if (field->options().GetExtension(os::statsd::is_uid) == true) {
if (javaType != JAVA_TYPE_INT) {
print_error(
field,
"is_uid annotation can only be applied to int32 fields: '%s'\n",
atomDecl->message.c_str());
errorCount++;
}
if (atomDecl->uidField == 0) {
atomDecl->uidField = fieldNumber;
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
ANNOTATION_TYPE_BOOL, AnnotationValue(true));
} else {
print_error(
field,
"Cannot have more than one field in an atom with is_uid annotation: '%s'\n",
atomDecl->message.c_str());
errorCount++;
}
}
return errorCount;
}
/**
* Gather the info about an atom proto.
*/
@@ -287,6 +408,12 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
os::statsd::LogMode::MODE_BYTES;
AtomField atField(field->name(), javaType);
if (javaType == JAVA_TYPE_ENUM) {
// All enums are treated as ints when it comes to function signatures.
collate_enums(*field->enum_type(), &atField);
}
// Generate signature for pushed atoms
if (atomDecl->code < PULL_ATOM_START_ID) {
if (javaType == JAVA_TYPE_ENUM) {
@@ -298,129 +425,10 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
signature->push_back(javaType);
}
}
if (javaType == JAVA_TYPE_ENUM) {
// All enums are treated as ints when it comes to function signatures.
collate_enums(*field->enum_type(), &atField);
}
atomDecl->fields.push_back(atField);
if (field->options().HasExtension(os::statsd::state_field_option)) {
const int option = field->options().GetExtension(os::statsd::state_field_option).option();
if (option != STATE_OPTION_UNSET) {
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_OPTION,
ANNOTATION_TYPE_INT, AnnotationValue(option));
}
if (option == STATE_OPTION_PRIMARY) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
print_error(
field,
"Invalid primary state field: '%s'\n",
atom->name().c_str());
errorCount++;
continue;
}
atomDecl->primaryFields.push_back(it->first);
}
if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
print_error(
field,
"PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n",
atom->name().c_str());
errorCount++;
continue;
} else {
atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
}
}
if (option == STATE_OPTION_EXCLUSIVE) {
if (javaType == JAVA_TYPE_UNKNOWN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
print_error(
field,
"Invalid exclusive state field: '%s'\n",
atom->name().c_str());
errorCount++;
continue;
}
if (atomDecl->exclusiveField == 0) {
atomDecl->exclusiveField = it->first;
} else {
print_error(
field,
"Cannot have more than one exclusive state field in an atom: '%s'\n",
atom->name().c_str());
errorCount++;
continue;
}
if (field->options()
.GetExtension(os::statsd::state_field_option)
.has_default_state_value()) {
const int defaultState =
field->options().GetExtension(os::statsd::state_field_option)
.default_state_value();
atomDecl->defaultState = defaultState;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_DEFAULT_STATE,
ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
}
if (field->options().GetExtension(os::statsd::state_field_option)
.has_reset_state_value()) {
const int resetState = field->options()
.GetExtension(os::statsd::state_field_option)
.reset_state_value();
atomDecl->resetState = resetState;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_RESET_STATE,
ANNOTATION_TYPE_INT, AnnotationValue(resetState));
}
if (field->options().GetExtension(os::statsd::state_field_option)
.has_nested()) {
const bool nested =
field->options().GetExtension(os::statsd::state_field_option).nested();
atomDecl->nested = nested;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_NESTED,
ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
}
}
}
if (field->options().GetExtension(os::statsd::is_uid) == true) {
if (javaType != JAVA_TYPE_INT) {
print_error(
field,
"is_uid annotation can only be applied to int32 fields: '%s'\n",
atom->name().c_str());
errorCount++;
continue;
}
if (atomDecl->uidField == 0) {
atomDecl->uidField = it->first;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_IS_UID,
ANNOTATION_TYPE_BOOL, AnnotationValue(true));
} else {
print_error(
field,
"Cannot have more than one field in an atom with is_uid annotation: '%s'\n",
atom->name().c_str());
errorCount++;
continue;
}
}
errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
}
return errorCount;
@@ -537,6 +545,18 @@ int collate_atoms(const Descriptor *descriptor, const string& moduleName, Atoms
if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
atomDecl.whitelisted = true;
if (dbg) {
printf("%s is whitelisted\n", atomField->name().c_str());
}
}
if (atomDecl.code < PULL_ATOM_START_ID
&& atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
addAnnotationToAtomDecl(&atomDecl, ATOM_ID_FIELD_NUMBER, ANNOTATION_ID_TRUNCATE_TIMESTAMP,
ANNOTATION_TYPE_BOOL, AnnotationValue(true));
if (dbg) {
printf("%s can have timestamp truncated\n", atomField->name().c_str());
}
}
vector<java_type_t> signature;

View File

@@ -52,6 +52,8 @@ const int STATE_OPTION_EXCLUSIVE = os::statsd::StateField::EXCLUSIVE_STATE;
const int STATE_OPTION_PRIMARY_FIELD_FIRST_UID = os::statsd::StateField::PRIMARY_FIELD_FIRST_UID;
const int STATE_OPTION_PRIMARY = os::statsd::StateField::PRIMARY_FIELD;
const int ATOM_ID_FIELD_NUMBER = -1;
const string DEFAULT_MODULE_NAME = "DEFAULT";
/**
@@ -147,6 +149,8 @@ struct AtomDecl {
bool whitelisted = false;
bool truncateTimestamp = false;
AtomDecl();
AtomDecl(const AtomDecl& that);
AtomDecl(int code, const string& name, const string& message);

View File

@@ -121,6 +121,7 @@ static int write_java_methods(
// Write atom code.
fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations);
// Write the args.
argIndex = 1;

View File

@@ -82,6 +82,7 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
if (supportQ) {
fprintf(out, " StatsEventCompat event;\n");
fprintf(out, " event.setAtomId(code);\n");
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "event.", "");
for (vector<java_type_t>::const_iterator arg = signature.begin();
arg != signature.end(); arg++) {
switch (*arg) {
@@ -124,6 +125,8 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
} else {
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "AStatsEvent_",
"event, ");
for (vector<java_type_t>::const_iterator arg = signature.begin();
arg != signature.end(); arg++) {
switch (*arg) {