Merge changes Iad76baea,I3db5f4ff into rvc-dev am: 6fe5fd6e2e

Change-Id: Ibd751ce32cc1ed3bec08712bf019af81fc595985
This commit is contained in:
Muhammad Qureshi
2020-03-25 17:40:28 +00:00
committed by Automerger Merge Worker
17 changed files with 1155 additions and 1165 deletions

View File

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

View File

@@ -94,7 +94,8 @@ message Atom {
10 [(module) = "framework", (module) = "statsdtest"]; 10 [(module) = "framework", (module) = "statsdtest"];
LongPartialWakelockStateChanged long_partial_wakelock_state_changed = LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
11 [(module) = "framework"]; 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"]; WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13 [(module) = "framework"];
ActivityManagerSleepStateChanged activity_manager_sleep_state_changed = ActivityManagerSleepStateChanged activity_manager_sleep_state_changed =
14 [(module) = "framework"]; 14 [(module) = "framework"];
@@ -107,7 +108,8 @@ message Atom {
20 [(module) = "framework", (module) = "statsdtest"]; 20 [(module) = "framework", (module) = "statsdtest"];
DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"]; DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(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"]; MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
CameraStateChanged camera_state_changed = 25 [(module) = "framework"]; CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"]; FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
@@ -128,7 +130,8 @@ message Atom {
WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"]; WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"]; WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
WifiScanStateChanged wifi_scan_state_changed = 39 [(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"]; SettingChanged setting_changed = 41 [(module) = "framework"];
ActivityForegroundStateChanged activity_foreground_state_changed = ActivityForegroundStateChanged activity_foreground_state_changed =
42 [(module) = "framework", (module) = "statsdtest"]; 42 [(module) = "framework", (module) = "statsdtest"];
@@ -154,7 +157,8 @@ message Atom {
59 [(module) = "framework", (module) = "statsdtest"]; 59 [(module) = "framework", (module) = "statsdtest"];
ForegroundServiceStateChanged foreground_service_state_changed ForegroundServiceStateChanged foreground_service_state_changed
= 60 [(module) = "framework"]; = 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"]; KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"]; KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"]; KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
@@ -420,8 +424,10 @@ message Atom {
oneof pulled { oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"]; WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"]; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
MobileBytesTransfer mobile_bytes_transfer = 10002 [(module) = "framework"]; MobileBytesTransfer mobile_bytes_transfer =
MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003 [(module) = "framework"]; 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"]; BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
KernelWakelock kernel_wakelock = 10004 [(module) = "framework"]; KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"]; SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];

View File

@@ -0,0 +1,17 @@
BasedOnStyle: Google
AllowShortIfStatementsOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortLoopsOnASingleLine: true
BinPackArguments: true
BinPackParameters: true
ColumnLimit: 100
CommentPragmas: NOLINT:.*
ContinuationIndentWidth: 8
DerivePointerAlignment: false
IndentWidth: 4
PointerAlignment: Left
TabWidth: 4
AccessModifierOffset: -4
IncludeCategories:
- Regex: '^"Log\.h"'
Priority: -1

View File

@@ -15,11 +15,13 @@
*/ */
#include "Collation.h" #include "Collation.h"
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include <stdio.h> #include <stdio.h>
#include <map> #include <map>
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
@@ -32,55 +34,47 @@ using std::map;
const bool dbg = false; const bool dbg = false;
// //
// AtomDecl class // AtomDecl class
// //
AtomDecl::AtomDecl() AtomDecl::AtomDecl() : code(0), name() {
:code(0),
name()
{
} }
AtomDecl::AtomDecl(const AtomDecl &that) AtomDecl::AtomDecl(const AtomDecl& that)
: code(that.code), : code(that.code),
name(that.name), name(that.name),
message(that.message), message(that.message),
fields(that.fields), fields(that.fields),
fieldNumberToAnnotations(that.fieldNumberToAnnotations), fieldNumberToAnnotations(that.fieldNumberToAnnotations),
primaryFields(that.primaryFields), primaryFields(that.primaryFields),
exclusiveField(that.exclusiveField), exclusiveField(that.exclusiveField),
defaultState(that.defaultState), defaultState(that.defaultState),
resetState(that.resetState), resetState(that.resetState),
nested(that.nested), nested(that.nested),
uidField(that.uidField), uidField(that.uidField),
whitelisted(that.whitelisted) {} whitelisted(that.whitelisted),
truncateTimestamp(that.truncateTimestamp) {
AtomDecl::AtomDecl(int c, const string& n, const string& m)
:code(c),
name(n),
message(m)
{
} }
AtomDecl::~AtomDecl() AtomDecl::AtomDecl(int c, const string& n, const string& m) : code(c), name(n), message(m) {
{
} }
AtomDecl::~AtomDecl() {
}
/** /**
* Print an error message for a FieldDescriptor, including the file name and line number. * Print an error message for a FieldDescriptor, including the file name and
* line number.
*/ */
static void static void print_error(const FieldDescriptor* field, const char* format, ...) {
print_error(const FieldDescriptor* field, const char* format, ...)
{
const Descriptor* message = field->containing_type(); const Descriptor* message = field->containing_type();
const FileDescriptor* file = message->file(); const FileDescriptor* file = message->file();
SourceLocation loc; SourceLocation loc;
if (field->GetSourceLocation(&loc)) { if (field->GetSourceLocation(&loc)) {
// TODO: this will work if we can figure out how to pass --include_source_info to protoc // TODO: this will work if we can figure out how to pass
// --include_source_info to protoc
fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line); fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
} else { } else {
fprintf(stderr, "%s: ", file->name().c_str()); fprintf(stderr, "%s: ", file->name().c_str());
@@ -88,15 +82,13 @@ print_error(const FieldDescriptor* field, const char* format, ...)
va_list args; va_list args;
va_start(args, format); va_start(args, format);
vfprintf(stderr, format, args); vfprintf(stderr, format, args);
va_end (args); va_end(args);
} }
/** /**
* Convert a protobuf type into a java type. * Convert a protobuf type into a java type.
*/ */
static java_type_t static java_type_t java_type(const FieldDescriptor* field) {
java_type(const FieldDescriptor* field)
{
int protoType = field->type(); int protoType = field->type();
switch (protoType) { switch (protoType) {
case FieldDescriptor::TYPE_DOUBLE: case FieldDescriptor::TYPE_DOUBLE:
@@ -121,12 +113,10 @@ java_type(const FieldDescriptor* field)
return JAVA_TYPE_UNKNOWN; return JAVA_TYPE_UNKNOWN;
case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_MESSAGE:
// TODO: not the final package name // TODO: not the final package name
if (field->message_type()->full_name() == if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
"android.os.statsd.AttributionNode") { return JAVA_TYPE_ATTRIBUTION_CHAIN;
return JAVA_TYPE_ATTRIBUTION_CHAIN; } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
} else if (field->message_type()->full_name() == return JAVA_TYPE_KEY_VALUE_PAIR;
"android.os.statsd.KeyValuePair") {
return JAVA_TYPE_KEY_VALUE_PAIR;
} else if (field->options().GetExtension(os::statsd::log_mode) == } else if (field->options().GetExtension(os::statsd::log_mode) ==
os::statsd::LogMode::MODE_BYTES) { os::statsd::LogMode::MODE_BYTES) {
return JAVA_TYPE_BYTE_ARRAY; return JAVA_TYPE_BYTE_ARRAY;
@@ -155,307 +145,298 @@ java_type(const FieldDescriptor* field)
/** /**
* Gather the enums info. * Gather the enums info.
*/ */
void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) { void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
for (int i = 0; i < enumDescriptor.value_count(); i++) { for (int i = 0; i < enumDescriptor.value_count(); i++) {
atomField->enumValues[enumDescriptor.value(i)->number()] = atomField->enumValues[enumDescriptor.value(i)->number()] =
enumDescriptor.value(i)->name().c_str(); enumDescriptor.value(i)->name().c_str();
} }
} }
static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber, static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
const int annotationId, const AnnotationType annotationType, const int annotationId, const AnnotationType annotationType,
const AnnotationValue annotationValue) { const AnnotationValue annotationValue) {
if (dbg) { if (dbg) {
printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n", printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
atomDecl->name.c_str(), fieldNumber, annotationId, annotationType); fieldNumber, annotationId, annotationType);
} }
atomDecl->fieldNumberToAnnotations[fieldNumber].insert(make_shared<Annotation>( atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
annotationId, atomDecl->code, annotationType, annotationValue)); make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
} }
/** static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
* Gather the info about an atom proto. const int fieldNumber, const java_type_t& javaType) {
*/ int errorCount = 0;
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;
for (int j = 0; j < atom->field_count(); j++) {
const FieldDescriptor *field = atom->field(j);
fields[field->number()] = field;
}
// Check that the parameters start at 1 and go up sequentially.
int expectedNumber = 1;
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
it != fields.end(); it++) {
const int number = it->first;
const FieldDescriptor *field = it->second;
if (number != expectedNumber) {
print_error(field,
"Fields must be numbered consecutively starting at 1:"
" '%s' is %d but should be %d\n",
field->name().c_str(), number, expectedNumber);
errorCount++;
expectedNumber = number;
continue;
}
expectedNumber++;
}
// Check that only allowed types are present. Remove any invalid ones.
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
it != fields.end(); it++) {
const FieldDescriptor *field = it->second;
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
os::statsd::LogMode::MODE_BYTES;
java_type_t javaType = java_type(field);
if (javaType == JAVA_TYPE_UNKNOWN) {
print_error(field, "Unkown type for field: %s\n", field->name().c_str());
errorCount++;
continue;
} else if (javaType == JAVA_TYPE_OBJECT &&
atomDecl->code < PULL_ATOM_START_ID) {
// Allow attribution chain, but only at position 1.
print_error(field,
"Message type not allowed for field in pushed atoms: %s\n",
field->name().c_str());
errorCount++;
continue;
} else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
print_error(field, "Raw bytes type not allowed for field: %s\n",
field->name().c_str());
errorCount++;
continue;
}
if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
print_error(field, "Cannot mark field %s as bytes.\n",
field->name().c_str());
errorCount++;
continue;
}
// Doubles are not supported yet.
if (javaType == JAVA_TYPE_DOUBLE) {
print_error(field, "Doubles are not supported in atoms. Please change field %s to float\n",
field->name().c_str());
errorCount++;
continue;
}
if (field->is_repeated() &&
!(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
print_error(field,
"Repeated fields are not supported in atoms. Please make field %s not "
"repeated.\n",
field->name().c_str());
errorCount++;
continue;
}
}
// Check that if there's an attribution chain, it's at position 1.
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
it != fields.end(); it++) {
int number = it->first;
if (number != 1) {
const FieldDescriptor *field = it->second;
java_type_t javaType = java_type(field);
if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
print_error(
field,
"AttributionChain fields must have field id 1, in message: '%s'\n",
atom->name().c_str());
errorCount++;
}
}
}
// Build the type signature and the atom data.
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
it != fields.end(); it++) {
const FieldDescriptor *field = it->second;
java_type_t javaType = java_type(field);
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
os::statsd::LogMode::MODE_BYTES;
AtomField atField(field->name(), javaType);
// Generate signature for pushed atoms
if (atomDecl->code < PULL_ATOM_START_ID) {
if (javaType == JAVA_TYPE_ENUM) {
// All enums are treated as ints when it comes to function signatures.
signature->push_back(JAVA_TYPE_INT);
} else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
signature->push_back(JAVA_TYPE_BYTE_ARRAY);
} else {
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)) { if (field->options().HasExtension(os::statsd::state_field_option)) {
const int option = field->options().GetExtension(os::statsd::state_field_option).option(); const int option = field->options().GetExtension(os::statsd::state_field_option).option();
if (option != STATE_OPTION_UNSET) { if (option != STATE_OPTION_UNSET) {
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_OPTION, addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_OPTION,
ANNOTATION_TYPE_INT, AnnotationValue(option)); ANNOTATION_TYPE_INT, AnnotationValue(option));
} }
if (option == STATE_OPTION_PRIMARY) { if (option == STATE_OPTION_PRIMARY) {
if (javaType == JAVA_TYPE_UNKNOWN || if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) { print_error(field, "Invalid primary state field: '%s'\n",
print_error( atomDecl->message.c_str());
field,
"Invalid primary state field: '%s'\n",
atom->name().c_str());
errorCount++; errorCount++;
continue;
} }
atomDecl->primaryFields.push_back(it->first); atomDecl->primaryFields.push_back(fieldNumber);
} }
if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) { if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) { if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
print_error( print_error(field,
field, "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
"PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n", "'%s'\n",
atom->name().c_str()); atomDecl->message.c_str());
errorCount++; errorCount++;
continue;
} else { } else {
atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID); atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
} }
} }
if (option == STATE_OPTION_EXCLUSIVE) { if (option == STATE_OPTION_EXCLUSIVE) {
if (javaType == JAVA_TYPE_UNKNOWN || if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) { print_error(field, "Invalid exclusive state field: '%s'\n",
print_error( atomDecl->message.c_str());
field,
"Invalid exclusive state field: '%s'\n",
atom->name().c_str());
errorCount++; errorCount++;
continue;
} }
if (atomDecl->exclusiveField == 0) { if (atomDecl->exclusiveField == 0) {
atomDecl->exclusiveField = it->first; atomDecl->exclusiveField = fieldNumber;
} else { } else {
print_error( print_error(field,
field, "Cannot have more than one exclusive state field in an "
"Cannot have more than one exclusive state field in an atom: '%s'\n", "atom: '%s'\n",
atom->name().c_str()); atomDecl->message.c_str());
errorCount++; errorCount++;
continue;
} }
if (field->options() if (field->options()
.GetExtension(os::statsd::state_field_option) .GetExtension(os::statsd::state_field_option)
.has_default_state_value()) { .has_default_state_value()) {
const int defaultState = const int defaultState = field->options()
field->options().GetExtension(os::statsd::state_field_option) .GetExtension(os::statsd::state_field_option)
.default_state_value(); .default_state_value();
atomDecl->defaultState = defaultState; atomDecl->defaultState = defaultState;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_DEFAULT_STATE, addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
ANNOTATION_TYPE_INT, AnnotationValue(defaultState)); ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
} }
if (field->options().GetExtension(os::statsd::state_field_option) if (field->options()
.has_reset_state_value()) {
const int resetState = field->options()
.GetExtension(os::statsd::state_field_option) .GetExtension(os::statsd::state_field_option)
.reset_state_value(); .has_reset_state_value()) {
const int resetState = field->options()
.GetExtension(os::statsd::state_field_option)
.reset_state_value();
atomDecl->resetState = resetState; atomDecl->resetState = resetState;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_RESET_STATE, addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_RESET_STATE,
ANNOTATION_TYPE_INT, AnnotationValue(resetState)); ANNOTATION_TYPE_INT, AnnotationValue(resetState));
} }
if (field->options().GetExtension(os::statsd::state_field_option) if (field->options().GetExtension(os::statsd::state_field_option).has_nested()) {
.has_nested()) {
const bool nested = const bool nested =
field->options().GetExtension(os::statsd::state_field_option).nested(); field->options().GetExtension(os::statsd::state_field_option).nested();
atomDecl->nested = nested; atomDecl->nested = nested;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_NESTED, addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
ANNOTATION_TYPE_BOOL, AnnotationValue(nested)); ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
} }
} }
} }
if (field->options().GetExtension(os::statsd::is_uid) == true) { if (field->options().GetExtension(os::statsd::is_uid) == true) {
if (javaType != JAVA_TYPE_INT) { if (javaType != JAVA_TYPE_INT) {
print_error( print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n",
field, atomDecl->message.c_str());
"is_uid annotation can only be applied to int32 fields: '%s'\n",
atom->name().c_str());
errorCount++; errorCount++;
continue;
} }
if (atomDecl->uidField == 0) { if (atomDecl->uidField == 0) {
atomDecl->uidField = it->first; atomDecl->uidField = fieldNumber;
addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_IS_UID, addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
ANNOTATION_TYPE_BOOL, AnnotationValue(true)); ANNOTATION_TYPE_BOOL, AnnotationValue(true));
} else { } else {
print_error( print_error(field,
field, "Cannot have more than one field in an atom with is_uid "
"Cannot have more than one field in an atom with is_uid annotation: '%s'\n", "annotation: '%s'\n",
atom->name().c_str()); atomDecl->message.c_str());
errorCount++;
}
}
return errorCount;
}
/**
* Gather the info about an atom proto.
*/
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;
for (int j = 0; j < atom->field_count(); j++) {
const FieldDescriptor* field = atom->field(j);
fields[field->number()] = field;
}
// Check that the parameters start at 1 and go up sequentially.
int expectedNumber = 1;
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
it++) {
const int number = it->first;
const FieldDescriptor* field = it->second;
if (number != expectedNumber) {
print_error(field,
"Fields must be numbered consecutively starting at 1:"
" '%s' is %d but should be %d\n",
field->name().c_str(), number, expectedNumber);
errorCount++;
expectedNumber = number;
continue;
}
expectedNumber++;
}
// Check that only allowed types are present. Remove any invalid ones.
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
it++) {
const FieldDescriptor* field = it->second;
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
os::statsd::LogMode::MODE_BYTES;
java_type_t javaType = java_type(field);
if (javaType == JAVA_TYPE_UNKNOWN) {
print_error(field, "Unknown type for field: %s\n", field->name().c_str());
errorCount++;
continue;
} else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) {
// Allow attribution chain, but only at position 1.
print_error(field, "Message type not allowed for field in pushed atoms: %s\n",
field->name().c_str());
errorCount++;
continue;
} else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
errorCount++;
continue;
}
if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
errorCount++;
continue;
}
// Doubles are not supported yet.
if (javaType == JAVA_TYPE_DOUBLE) {
print_error(field,
"Doubles are not supported in atoms. Please change field %s "
"to float\n",
field->name().c_str());
errorCount++;
continue;
}
if (field->is_repeated() &&
!(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
print_error(field,
"Repeated fields are not supported in atoms. Please make "
"field %s not "
"repeated.\n",
field->name().c_str());
errorCount++; errorCount++;
continue; continue;
} }
} }
}
return errorCount; // Check that if there's an attribution chain, it's at position 1.
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
it++) {
int number = it->first;
if (number != 1) {
const FieldDescriptor* field = it->second;
java_type_t javaType = java_type(field);
if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
print_error(field,
"AttributionChain fields must have field id 1, in message: '%s'\n",
atom->name().c_str());
errorCount++;
}
}
}
// Build the type signature and the atom data.
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
it++) {
const FieldDescriptor* field = it->second;
java_type_t javaType = java_type(field);
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
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) {
// All enums are treated as ints when it comes to function signatures.
signature->push_back(JAVA_TYPE_INT);
} else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
signature->push_back(JAVA_TYPE_BYTE_ARRAY);
} else {
signature->push_back(javaType);
}
}
atomDecl->fields.push_back(atField);
errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
}
return errorCount;
} }
// This function flattens the fields of the AttributionNode proto in an Atom proto and generates // This function flattens the fields of the AttributionNode proto in an Atom
// the corresponding atom decl and signature. // proto and generates the corresponding atom decl and signature.
bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl, bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
vector<java_type_t> *signature) { vector<java_type_t>* signature) {
// Build a sorted list of the fields. Descriptor has them in source file // Build a sorted list of the fields. Descriptor has them in source file
// order. // order.
map<int, const FieldDescriptor *> fields; map<int, const FieldDescriptor*> fields;
for (int j = 0; j < atom->field_count(); j++) { for (int j = 0; j < atom->field_count(); j++) {
const FieldDescriptor *field = atom->field(j); const FieldDescriptor* field = atom->field(j);
fields[field->number()] = field; fields[field->number()] = field;
} }
AtomDecl attributionDecl; AtomDecl attributionDecl;
vector<java_type_t> attributionSignature; vector<java_type_t> attributionSignature;
collate_atom(android::os::statsd::AttributionNode::descriptor(), collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
&attributionDecl, &attributionSignature); &attributionSignature);
// Build the type signature and the atom data. // Build the type signature and the atom data.
bool has_attribution_node = false; bool has_attribution_node = false;
for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin(); for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
it != fields.end(); it++) { it++) {
const FieldDescriptor *field = it->second; const FieldDescriptor* field = it->second;
java_type_t javaType = java_type(field); java_type_t javaType = java_type(field);
if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
atomDecl->fields.insert( atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
atomDecl->fields.end(), attributionDecl.fields.end());
attributionDecl.fields.begin(), attributionDecl.fields.end()); signature->insert(signature->end(), attributionSignature.begin(),
signature->insert( attributionSignature.end());
signature->end(),
attributionSignature.begin(), attributionSignature.end());
has_attribution_node = true; has_attribution_node = true;
} else { } else {
@@ -473,118 +454,129 @@ bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
return has_attribution_node; return has_attribution_node;
} }
static void populateFieldNumberToAnnotations( static void populateFieldNumberToAnnotations(const AtomDecl& atomDecl,
const AtomDecl& atomDecl, FieldNumberToAnnotations* fieldNumberToAnnotations) {
FieldNumberToAnnotations* fieldNumberToAnnotations) {
for (FieldNumberToAnnotations::const_iterator it = atomDecl.fieldNumberToAnnotations.begin(); for (FieldNumberToAnnotations::const_iterator it = atomDecl.fieldNumberToAnnotations.begin();
it != atomDecl.fieldNumberToAnnotations.end(); it++) { it != atomDecl.fieldNumberToAnnotations.end(); it++) {
const int fieldNumber = it->first; const int fieldNumber = it->first;
const set<shared_ptr<Annotation>>& insertAnnotationsSource = it->second; const set<shared_ptr<Annotation>>& insertAnnotationsSource = it->second;
set<shared_ptr<Annotation>>& insertAnnotationsTarget = set<shared_ptr<Annotation>>& insertAnnotationsTarget =
(*fieldNumberToAnnotations)[fieldNumber]; (*fieldNumberToAnnotations)[fieldNumber];
insertAnnotationsTarget.insert( insertAnnotationsTarget.insert(insertAnnotationsSource.begin(),
insertAnnotationsSource.begin(), insertAnnotationsSource.end());
insertAnnotationsSource.end());
} }
} }
/** /**
* Gather the info about the atoms. * Gather the info about the atoms.
*/ */
int collate_atoms(const Descriptor *descriptor, const string& moduleName, Atoms *atoms) { int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
int errorCount = 0; int errorCount = 0;
int maxPushedAtomId = 2; int maxPushedAtomId = 2;
for (int i = 0; i < descriptor->field_count(); i++) { for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor *atomField = descriptor->field(i); const FieldDescriptor* atomField = descriptor->field(i);
if (moduleName != DEFAULT_MODULE_NAME) { if (moduleName != DEFAULT_MODULE_NAME) {
const int moduleCount = atomField->options().ExtensionSize(os::statsd::module); const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
int j; int j;
for (j = 0; j < moduleCount; ++j) { for (j = 0; j < moduleCount; ++j) {
const string atomModuleName = atomField->options().GetExtension(os::statsd::module, j); const string atomModuleName =
if (atomModuleName == moduleName) { atomField->options().GetExtension(os::statsd::module, j);
break; if (atomModuleName == moduleName) {
break;
}
}
// This atom is not in the module we're interested in; skip it.
if (moduleCount == j) {
if (dbg) {
printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
}
continue;
} }
} }
// This atom is not in the module we're interested in; skip it. if (dbg) {
if (moduleCount == j) { printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
if (dbg) { }
printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
} // StatsEvent only has one oneof, which contains only messages. Don't allow
// other types.
if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
print_error(atomField,
"Bad type for atom. StatsEvent can only have message type "
"fields: %s\n",
atomField->name().c_str());
errorCount++;
continue; continue;
} }
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;
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;
errorCount += collate_atom(atom, &atomDecl, &signature);
if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
atomField->name().c_str());
errorCount++;
continue;
}
atoms->decls.insert(atomDecl);
FieldNumberToAnnotations& fieldNumberToAnnotations = atoms->signatureInfoMap[signature];
populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
vector<java_type_t> nonChainedSignature;
if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
atoms->non_chained_decls.insert(nonChainedAtomDecl);
FieldNumberToAnnotations& fieldNumberToAnnotations =
atoms->nonChainedSignatureInfoMap[nonChainedSignature];
populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
}
if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
maxPushedAtomId = atomDecl.code;
}
} }
atoms->maxPushedAtomId = maxPushedAtomId;
if (dbg) { if (dbg) {
printf(" %s (%d)\n", atomField->name().c_str(), atomField->number()); printf("signatures = [\n");
for (map<vector<java_type_t>, FieldNumberToAnnotations>::const_iterator it =
atoms->signatureInfoMap.begin();
it != atoms->signatureInfoMap.end(); it++) {
printf(" ");
for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
jt++) {
printf(" %d", (int)*jt);
}
printf("\n");
}
printf("]\n");
} }
// StatsEvent only has one oneof, which contains only messages. Don't allow return errorCount;
// other types.
if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
print_error(atomField,
"Bad type for atom. StatsEvent can only have message type "
"fields: %s\n",
atomField->name().c_str());
errorCount++;
continue;
}
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) {
print_error(atomField,
"Cannot have a primary field without an exclusive field: %s\n",
atomField->name().c_str());
errorCount++;
continue;
}
atoms->decls.insert(atomDecl);
FieldNumberToAnnotations& fieldNumberToAnnotations = atoms->signatureInfoMap[signature];
populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
vector<java_type_t> nonChainedSignature;
if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
atoms->non_chained_decls.insert(nonChainedAtomDecl);
FieldNumberToAnnotations& fieldNumberToAnnotations =
atoms->nonChainedSignatureInfoMap[nonChainedSignature];
populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
}
if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
maxPushedAtomId = atomDecl.code;
}
}
atoms->maxPushedAtomId = maxPushedAtomId;
if (dbg) {
printf("signatures = [\n");
for (map<vector<java_type_t>, FieldNumberToAnnotations>::const_iterator it =
atoms->signatureInfoMap.begin();
it != atoms->signatureInfoMap.end(); it++) {
printf(" ");
for (vector<java_type_t>::const_iterator jt = it->first.begin();
jt != it->first.end(); jt++){
printf(" %d", (int)*jt);
}
printf("\n");
}
printf("]\n");
}
return errorCount;
} }
} // namespace stats_log_api_gen } // namespace stats_log_api_gen

View File

@@ -17,24 +17,24 @@
#ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H #ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H
#define ANDROID_STATS_LOG_API_GEN_COLLATION_H #define ANDROID_STATS_LOG_API_GEN_COLLATION_H
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
#include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <map>
#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
using google::protobuf::Descriptor;
using google::protobuf::FieldDescriptor;
using std::map; using std::map;
using std::set; using std::set;
using std::shared_ptr; using std::shared_ptr;
using std::string; using std::string;
using std::vector; using std::vector;
using google::protobuf::Descriptor;
using google::protobuf::FieldDescriptor;
const int PULL_ATOM_START_ID = 10000; const int PULL_ATOM_START_ID = 10000;
@@ -52,26 +52,28 @@ 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_FIELD_FIRST_UID = os::statsd::StateField::PRIMARY_FIELD_FIRST_UID;
const int STATE_OPTION_PRIMARY = os::statsd::StateField::PRIMARY_FIELD; const int STATE_OPTION_PRIMARY = os::statsd::StateField::PRIMARY_FIELD;
const int ATOM_ID_FIELD_NUMBER = -1;
const string DEFAULT_MODULE_NAME = "DEFAULT"; const string DEFAULT_MODULE_NAME = "DEFAULT";
/** /**
* The types for atom parameters. * The types for atom parameters.
*/ */
typedef enum { typedef enum {
JAVA_TYPE_UNKNOWN = 0, JAVA_TYPE_UNKNOWN = 0,
JAVA_TYPE_ATTRIBUTION_CHAIN = 1, JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
JAVA_TYPE_BOOLEAN = 2, JAVA_TYPE_BOOLEAN = 2,
JAVA_TYPE_INT = 3, JAVA_TYPE_INT = 3,
JAVA_TYPE_LONG = 4, JAVA_TYPE_LONG = 4,
JAVA_TYPE_FLOAT = 5, JAVA_TYPE_FLOAT = 5,
JAVA_TYPE_DOUBLE = 6, JAVA_TYPE_DOUBLE = 6,
JAVA_TYPE_STRING = 7, JAVA_TYPE_STRING = 7,
JAVA_TYPE_ENUM = 8, JAVA_TYPE_ENUM = 8,
JAVA_TYPE_KEY_VALUE_PAIR = 9, JAVA_TYPE_KEY_VALUE_PAIR = 9,
JAVA_TYPE_OBJECT = -1, JAVA_TYPE_OBJECT = -1,
JAVA_TYPE_BYTE_ARRAY = -2, JAVA_TYPE_BYTE_ARRAY = -2,
} java_type_t; } java_type_t;
enum AnnotationType { enum AnnotationType {
@@ -84,8 +86,10 @@ union AnnotationValue {
int intValue; int intValue;
bool boolValue; bool boolValue;
AnnotationValue(const int value): intValue(value) {} AnnotationValue(const int value) : intValue(value) {
AnnotationValue(const bool value): boolValue(value) {} }
AnnotationValue(const bool value) : boolValue(value) {
}
}; };
struct Annotation { struct Annotation {
@@ -95,16 +99,18 @@ struct Annotation {
AnnotationValue value; AnnotationValue value;
inline Annotation(unsigned char annotationId, int atomId, AnnotationType type, inline Annotation(unsigned char annotationId, int atomId, AnnotationType type,
AnnotationValue value): AnnotationValue value)
annotationId(annotationId), atomId(atomId), type(type), value(value) {} : annotationId(annotationId), atomId(atomId), type(type), value(value) {
inline ~Annotation() {} }
inline ~Annotation() {
}
inline bool operator<(const Annotation& that) const { inline bool operator<(const Annotation& that) const {
return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId; return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId;
} }
}; };
using FieldNumberToAnnotations = map<int, set<shared_ptr<Annotation>>>; using FieldNumberToAnnotations = map<int, set<shared_ptr<Annotation>>>;
/** /**
* The name and type for an atom field. * The name and type for an atom field.
@@ -113,16 +119,20 @@ struct AtomField {
string name; string name;
java_type_t javaType; java_type_t javaType;
// If the field is of type enum, the following map contains the list of enum values. // If the field is of type enum, the following map contains the list of enum
// values.
map<int /* numeric value */, string /* value name */> enumValues; map<int /* numeric value */, string /* value name */> enumValues;
inline AtomField() :name(), javaType(JAVA_TYPE_UNKNOWN) {} inline AtomField() : name(), javaType(JAVA_TYPE_UNKNOWN) {
inline AtomField(const AtomField& that) :name(that.name), }
javaType(that.javaType), inline AtomField(const AtomField& that)
enumValues(that.enumValues) {} : name(that.name), javaType(that.javaType), enumValues(that.enumValues) {
}
inline AtomField(string n, java_type_t jt) :name(n), javaType(jt) {} inline AtomField(string n, java_type_t jt) : name(n), javaType(jt) {
inline ~AtomField() {} }
inline ~AtomField() {
}
}; };
/** /**
@@ -147,6 +157,8 @@ struct AtomDecl {
bool whitelisted = false; bool whitelisted = false;
bool truncateTimestamp = false;
AtomDecl(); AtomDecl();
AtomDecl(const AtomDecl& that); AtomDecl(const AtomDecl& that);
AtomDecl(int code, const string& name, const string& message); AtomDecl(int code, const string& name, const string& message);
@@ -169,10 +181,9 @@ struct Atoms {
* Gather the information about the atoms. Returns the number of errors. * Gather the information about the atoms. Returns the number of errors.
*/ */
int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms); int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms);
int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, vector<java_type_t> *signature); int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature);
} // namespace stats_log_api_gen } // namespace stats_log_api_gen
} // namespace android } // namespace android
#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H

View File

@@ -15,12 +15,13 @@
*/ */
#include "atoms_info_writer.h" #include "atoms_info_writer.h"
#include "utils.h"
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include "utils.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
@@ -42,32 +43,27 @@ static void write_atoms_info_header_body(FILE* out, const Atoms& atoms) {
" const static std::set<int> " " const static std::set<int> "
"kTruncatingTimestampAtomBlackList;\n"); "kTruncatingTimestampAtomBlackList;\n");
fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n"); fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
fprintf(out, fprintf(out, " const static std::set<int> kAtomsWithAttributionChain;\n");
" const static std::set<int> kAtomsWithAttributionChain;\n");
fprintf(out, fprintf(out,
" const static std::map<int, StateAtomFieldOptions> " " const static std::map<int, StateAtomFieldOptions> "
"kStateAtomsFieldOptions;\n"); "kStateAtomsFieldOptions;\n");
fprintf(out, fprintf(out, " const static std::set<int> kWhitelistedAtoms;\n");
" const static std::set<int> kWhitelistedAtoms;\n");
fprintf(out, "};\n"); fprintf(out, "};\n");
fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId); fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId);
} }
static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) { static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
std::set<string> kTruncatingAtomNames = { std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
"mobile_radio_power_state_changed", "audio_state_changed",
"audio_state_changed", "call_state_changed",
"call_state_changed", "phone_signal_strength_changed",
"phone_signal_strength_changed", "mobile_bytes_transfer_by_fg_bg",
"mobile_bytes_transfer_by_fg_bg", "mobile_bytes_transfer"};
"mobile_bytes_transfer"
};
fprintf(out, fprintf(out,
"const std::set<int> " "const std::set<int> "
"AtomsInfo::kTruncatingTimestampAtomBlackList = {\n"); "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) { if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) {
const string constant = make_constant_name(atom->name); const string constant = make_constant_name(atom->name);
fprintf(out, " %d, // %s\n", atom->code, constant.c_str()); fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
@@ -77,10 +73,9 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "};\n"); fprintf(out, "};\n");
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, fprintf(out, "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
"const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n"); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom++) {
atom != atoms.decls.end(); atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin(); for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) { field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -94,10 +89,9 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "};\n"); fprintf(out, "};\n");
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, fprintf(out, "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
"const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n"); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom++) {
atom != atoms.decls.end(); atom++) {
if (atom->whitelisted) { if (atom->whitelisted) {
const string constant = make_constant_name(atom->name); const string constant = make_constant_name(atom->name);
fprintf(out, " %d, // %s\n", atom->code, constant.c_str()); fprintf(out, " %d, // %s\n", atom->code, constant.c_str());
@@ -109,8 +103,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
fprintf(out, "static std::map<int, int> getAtomUidField() {\n"); fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
fprintf(out, " std::map<int, int> uidField;\n"); fprintf(out, " std::map<int, int> uidField;\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
if (atom->uidField == 0) { if (atom->uidField == 0) {
continue; continue;
} }
@@ -118,8 +112,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding uid field for atom " "\n // Adding uid field for atom "
"(%d)%s\n", "(%d)%s\n",
atom->code, atom->name.c_str()); atom->code, atom->name.c_str());
fprintf(out, " uidField[%d /* %s */] = %d;\n", fprintf(out, " uidField[%d /* %s */] = %d;\n", atom->code,
atom->code, make_constant_name(atom->name).c_str(), atom->uidField); make_constant_name(atom->name).c_str(), atom->uidField);
} }
fprintf(out, " return uidField;\n"); fprintf(out, " return uidField;\n");
@@ -134,8 +128,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"getStateAtomFieldOptions() {\n"); "getStateAtomFieldOptions() {\n");
fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n"); fprintf(out, " std::map<int, StateAtomFieldOptions> options;\n");
fprintf(out, " StateAtomFieldOptions* opt;\n"); fprintf(out, " StateAtomFieldOptions* opt;\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) { if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
continue; continue;
} }
@@ -143,8 +137,8 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"\n // Adding primary and exclusive fields for atom " "\n // Adding primary and exclusive fields for atom "
"(%d)%s\n", "(%d)%s\n",
atom->code, atom->name.c_str()); atom->code, atom->name.c_str());
fprintf(out, " opt = &(options[%d /* %s */]);\n", fprintf(out, " opt = &(options[%d /* %s */]);\n", atom->code,
atom->code, make_constant_name(atom->name).c_str()); make_constant_name(atom->name).c_str());
fprintf(out, " opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size()); fprintf(out, " opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
for (const auto& field : atom->primaryFields) { for (const auto& field : atom->primaryFields) {
fprintf(out, " opt->primaryFields.push_back(%d);\n", field); fprintf(out, " opt->primaryFields.push_back(%d);\n", field);
@@ -174,7 +168,7 @@ static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
"getStateAtomFieldOptions();\n"); "getStateAtomFieldOptions();\n");
} }
int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespaceStr) { int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr) {
// Print prelude // Print prelude
fprintf(out, "// This file is autogenerated\n"); fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n"); fprintf(out, "\n");
@@ -195,8 +189,8 @@ int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespa
return 0; return 0;
} }
int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr, int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
const string& importHeader) { const string& importHeader) {
// Print prelude // Print prelude
fprintf(out, "// This file is autogenerated\n"); fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n"); fprintf(out, "\n");

View File

@@ -16,18 +16,18 @@
#pragma once #pragma once
#include "Collation.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "Collation.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
using namespace std; using namespace std;
int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr, int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
const string& importHeader); const string& importHeader);
int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr); int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);

View File

@@ -15,6 +15,7 @@
*/ */
#include "java_writer.h" #include "java_writer.h"
#include "java_writer_q.h" #include "java_writer_q.h"
#include "utils.h" #include "utils.h"
@@ -22,9 +23,8 @@ namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
static int write_java_q_logger_class( static int write_java_q_logger_class(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap, const AtomDecl& attributionDecl) {
const AtomDecl &attributionDecl) {
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n"); fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n");
fprintf(out, " private static class QLogger {\n"); fprintf(out, " private static class QLogger {\n");
@@ -34,29 +34,27 @@ static int write_java_q_logger_class(
// Print Q write methods. // Print Q write methods.
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, " // Write methods.\n"); fprintf(out, " // Write methods.\n");
write_java_methods_q_schema( write_java_methods_q_schema(out, signatureInfoMap, attributionDecl, " ");
out, signatureInfoMap, attributionDecl, " ");
fprintf(out, " }\n"); fprintf(out, " }\n");
return 0; return 0;
} }
static void write_annotations( static void write_annotations(FILE* out, int argIndex,
FILE* out, int argIndex, const FieldNumberToAnnotations& fieldNumberToAnnotations) {
const FieldNumberToAnnotations& fieldNumberToAnnotations) {
auto it = fieldNumberToAnnotations.find(argIndex); auto it = fieldNumberToAnnotations.find(argIndex);
if (it == fieldNumberToAnnotations.end()) { if (it == fieldNumberToAnnotations.end()) {
return; return;
} }
const set<shared_ptr<Annotation>>& annotations = it->second; const set<shared_ptr<Annotation>>& annotations = it->second;
for (auto& annotation: annotations) { for (auto& annotation : annotations) {
// TODO(b/151744250): Group annotations for same atoms. // TODO(b/151744250): Group annotations for same atoms.
// TODO(b/151786433): Write atom constant name instead of atom id literal. // TODO(b/151786433): Write atom constant name instead of atom id literal.
fprintf(out, " if (code == %d) {\n", annotation->atomId); fprintf(out, " if (code == %d) {\n", annotation->atomId);
switch(annotation->type) { switch (annotation->type) {
case ANNOTATION_TYPE_INT: case ANNOTATION_TYPE_INT:
// TODO(b/151776731): Check for reset state annotation and only include reset state // TODO(b/151776731): Check for reset state annotation and only include
// when field value == default state annotation value. // reset state when field value == default state annotation value.
// TODO(b/151786433): Write annotation constant name instead of // TODO(b/151786433): Write annotation constant name instead of
// annotation id literal. // annotation id literal.
fprintf(out, " builder.addIntAnnotation((byte) %d, %d);\n", fprintf(out, " builder.addIntAnnotation((byte) %d, %d);\n",
@@ -66,8 +64,7 @@ static void write_annotations(
// TODO(b/151786433): Write annotation constant name instead of // TODO(b/151786433): Write annotation constant name instead of
// annotation id literal. // annotation id literal.
fprintf(out, " builder.addBooleanAnnotation((byte) %d, %s);\n", fprintf(out, " builder.addBooleanAnnotation((byte) %d, %s);\n",
annotation->annotationId, annotation->annotationId, annotation->value.boolValue ? "true" : "false");
annotation->value.boolValue ? "true" : "false");
break; break;
default: default:
break; break;
@@ -77,24 +74,21 @@ static void write_annotations(
} }
static int write_java_methods( static int write_java_methods(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap, const AtomDecl& attributionDecl, const bool supportQ) {
const AtomDecl &attributionDecl,
const bool supportQ
) {
for (auto signatureInfoMapIt = signatureInfoMap.begin(); for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature. // Print method signature.
fprintf(out, " public static void write(int code"); fprintf(out, " public static void write(int code");
const vector<java_type_t>& signature = signatureInfoMapIt->first; const vector<java_type_t>& signature = signatureInfoMapIt->first;
const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second; const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second;
int argIndex = 1; int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) { for (auto chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
java_type_name(chainField.javaType), chainField.name.c_str()); chainField.name.c_str());
} }
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", android.util.SparseArray<Object> valueMap"); fprintf(out, ", android.util.SparseArray<Object> valueMap");
@@ -108,134 +102,134 @@ static int write_java_methods(
// Print method body. // Print method body.
string indent(""); string indent("");
if (supportQ) { if (supportQ) {
// TODO(b/146235828): Use just SDK_INT check once it is incremented from Q. // TODO(b/146235828): Use just SDK_INT check once it is incremented from
// Q.
fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n"); fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
fprintf(out, " || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n"); fprintf(out,
" || (Build.VERSION.SDK_INT == "
"Build.VERSION_CODES.Q\n");
fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n"); fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
indent = " "; indent = " ";
} }
// Start StatsEvent.Builder. // Start StatsEvent.Builder.
fprintf(out, "%s final StatsEvent.Builder builder = StatsEvent.newBuilder();\n", fprintf(out,
"%s final StatsEvent.Builder builder = "
"StatsEvent.newBuilder();\n",
indent.c_str()); indent.c_str());
// Write atom code. // Write atom code.
fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str()); fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations);
// Write the args. // Write the args.
argIndex = 1; argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
switch (*arg) { switch (*arg) {
case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BOOLEAN:
fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(), argIndex); fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
break; argIndex);
case JAVA_TYPE_INT: break;
case JAVA_TYPE_ENUM: case JAVA_TYPE_INT:
fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex); case JAVA_TYPE_ENUM:
break; fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
case JAVA_TYPE_FLOAT: break;
fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(), argIndex); case JAVA_TYPE_FLOAT:
break; fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
case JAVA_TYPE_LONG: argIndex);
fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex); break;
break; case JAVA_TYPE_LONG:
case JAVA_TYPE_STRING: fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(), argIndex); break;
break; case JAVA_TYPE_STRING:
case JAVA_TYPE_BYTE_ARRAY: fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
fprintf(out, "%s builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n", argIndex);
indent.c_str(), argIndex, argIndex); break;
break; case JAVA_TYPE_BYTE_ARRAY:
case JAVA_TYPE_ATTRIBUTION_CHAIN: fprintf(out,
{ "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
const char* uidName = attributionDecl.fields.front().name.c_str(); "arg%d);\n",
const char* tagName = attributionDecl.fields.back().name.c_str(); indent.c_str(), argIndex, argIndex);
break;
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str()); fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
fprintf(out, "%s null == %s ? new int[0] : %s,\n", fprintf(out, "%s null == %s ? new int[0] : %s,\n",
indent.c_str(), uidName, uidName); indent.c_str(), uidName, uidName);
fprintf(out, "%s null == %s ? new String[0] : %s);\n", fprintf(out, "%s null == %s ? new String[0] : %s);\n",
indent.c_str(), tagName, tagName); indent.c_str(), tagName, tagName);
break; break;
} }
case JAVA_TYPE_KEY_VALUE_PAIR: case JAVA_TYPE_KEY_VALUE_PAIR:
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
"%s // Write KeyValuePairs.\n", indent.c_str()); fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
fprintf(out, fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
"%s final int count = valueMap.size();\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
"%s android.util.SparseIntArray intMap = null;\n", indent.c_str());
indent.c_str()); fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
fprintf(out, indent.c_str());
"%s android.util.SparseLongArray longMap = null;\n", fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
"%s android.util.SparseArray<String> stringMap = null;\n", fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
"%s android.util.SparseArray<Float> floatMap = null;\n", indent.c_str());
indent.c_str()); fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
fprintf(out, fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
"%s for (int i = 0; i < count; i++) {\n", indent.c_str()); fprintf(out,
fprintf(out, "%s intMap = new "
"%s final int key = valueMap.keyAt(i);\n", indent.c_str()); "android.util.SparseIntArray();\n",
fprintf(out, indent.c_str());
"%s final Object value = valueMap.valueAt(i);\n", fprintf(out, "%s }\n", indent.c_str());
indent.c_str()); fprintf(out, "%s intMap.put(key, (Integer) value);\n",
fprintf(out, indent.c_str());
"%s if (value instanceof Integer) {\n", indent.c_str()); fprintf(out, "%s } else if (value instanceof Long) {\n",
fprintf(out, indent.c_str());
"%s if (null == intMap) {\n", indent.c_str()); fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
fprintf(out, fprintf(out,
"%s intMap = new android.util.SparseIntArray();\n", indent.c_str()); "%s longMap = new "
fprintf(out, "android.util.SparseLongArray();\n",
"%s }\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s intMap.put(key, (Integer) value);\n", indent.c_str()); fprintf(out, "%s longMap.put(key, (Long) value);\n",
fprintf(out, indent.c_str());
"%s } else if (value instanceof Long) {\n", indent.c_str()); fprintf(out, "%s } else if (value instanceof String) {\n",
fprintf(out, indent.c_str());
"%s if (null == longMap) {\n", indent.c_str()); fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
fprintf(out, fprintf(out,
"%s longMap = new android.util.SparseLongArray();\n", indent.c_str()); "%s stringMap = new "
fprintf(out, "android.util.SparseArray<>();\n",
"%s }\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s longMap.put(key, (Long) value);\n", indent.c_str()); fprintf(out, "%s stringMap.put(key, (String) value);\n",
fprintf(out, indent.c_str());
"%s } else if (value instanceof String) {\n", indent.c_str()); fprintf(out, "%s } else if (value instanceof Float) {\n",
fprintf(out, indent.c_str());
"%s if (null == stringMap) {\n", indent.c_str()); fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
fprintf(out, fprintf(out,
"%s stringMap = new android.util.SparseArray<>();\n", indent.c_str()); "%s floatMap = new "
fprintf(out, "android.util.SparseArray<>();\n",
"%s }\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s stringMap.put(key, (String) value);\n", indent.c_str()); fprintf(out, "%s floatMap.put(key, (Float) value);\n",
fprintf(out, indent.c_str());
"%s } else if (value instanceof Float) {\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s if (null == floatMap) {\n", indent.c_str()); fprintf(out,
fprintf(out, "%s builder.writeKeyValuePairs("
"%s floatMap = new android.util.SparseArray<>();\n", indent.c_str()); "intMap, longMap, stringMap, floatMap);\n",
fprintf(out, indent.c_str());
"%s }\n", indent.c_str()); break;
fprintf(out, default:
"%s floatMap.put(key, (Float) value);\n", indent.c_str()); // Unsupported types: OBJECT, DOUBLE.
fprintf(out, fprintf(stderr, "Encountered unsupported type.");
"%s }\n", indent.c_str()); return 1;
fprintf(out,
"%s }\n", indent.c_str());
fprintf(out,
"%s builder.writeKeyValuePairs("
"intMap, longMap, stringMap, floatMap);\n", indent.c_str());
break;
default:
// Unsupported types: OBJECT, DOUBLE.
fprintf(stderr, "Encountered unsupported type.");
return 1;
} }
write_annotations(out, argIndex, fieldNumberToAnnotations); write_annotations(out, argIndex, fieldNumberToAnnotations);
argIndex++; argIndex++;
@@ -251,7 +245,7 @@ static int write_java_methods(
fprintf(out, " QLogger.write(code"); fprintf(out, " QLogger.write(code");
argIndex = 1; argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin();
arg != signature.end(); arg++) { arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
const char* uidName = attributionDecl.fields.front().name.c_str(); const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str(); const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -266,20 +260,18 @@ static int write_java_methods(
argIndex++; argIndex++;
} }
fprintf(out, ");\n"); fprintf(out, ");\n");
fprintf(out, " }\n"); // if fprintf(out, " }\n"); // if
} }
fprintf(out, " }\n"); // method fprintf(out, " }\n"); // method
fprintf(out, "\n"); fprintf(out, "\n");
} }
return 0; return 0;
} }
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& javaClass, const string& javaClass, const string& javaPackage, const bool supportQ,
const string& javaPackage, const bool supportQ, const bool supportWorkSource) {
const bool supportWorkSource) {
// Print prelude // Print prelude
fprintf(out, "// This file is autogenerated\n"); fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n"); fprintf(out, "\n");
@@ -308,17 +300,14 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attribut
// Print write methods. // Print write methods.
fprintf(out, " // Write methods\n"); fprintf(out, " // Write methods\n");
errors += write_java_methods( errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
out, atoms.signatureInfoMap, attributionDecl, supportQ); errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
errors += write_java_non_chained_methods(
out, atoms.nonChainedSignatureInfoMap);
if (supportWorkSource) { if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap); errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
} }
if (supportQ) { if (supportQ) {
errors += write_java_q_logger_class( errors += write_java_q_logger_class(out, atoms.signatureInfoMap, attributionDecl);
out, atoms.signatureInfoMap, attributionDecl);
} }
fprintf(out, "}\n"); fprintf(out, "}\n");

View File

@@ -16,25 +16,23 @@
#pragma once #pragma once
#include "Collation.h" #include <stdio.h>
#include <string.h>
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <stdio.h> #include "Collation.h"
#include <string.h>
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
using namespace std; using namespace std;
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& javaClass, const string& javaClass, const string& javaPackage, const bool supportQ,
const string& javaPackage, const bool supportQ,
const bool supportWorkSource); const bool supportWorkSource);
} // namespace stats_log_api_gen } // namespace stats_log_api_gen
} // namespace android } // namespace android

View File

@@ -15,6 +15,7 @@
*/ */
#include "java_writer_q.h" #include "java_writer_q.h"
#include "utils.h" #include "utils.h"
namespace android { namespace android {
@@ -24,7 +25,8 @@ void write_java_q_logging_constants(FILE* out, const string& indent) {
fprintf(out, "%s// Payload limits.\n", indent.c_str()); fprintf(out, "%s// Payload limits.\n", indent.c_str());
fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str()); fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str());
fprintf(out, fprintf(out,
"%sprivate static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n", "%sprivate static final int MAX_EVENT_PAYLOAD = "
"LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
indent.c_str()); indent.c_str());
// Value types. Must match with EventLog.java and log.h. // Value types. Must match with EventLog.java and log.h.
@@ -37,36 +39,36 @@ void write_java_q_logging_constants(FILE* out, const string& indent) {
fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str()); fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str());
// Size of each value type. // Size of each value type.
// Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value. // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for
// the value.
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, "%s// Size of each value type.\n", indent.c_str()); fprintf(out, "%s// Size of each value type.\n", indent.c_str());
fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str()); fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str());
fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str()); fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str());
// Longs take 9 bytes, 1 for the type and 8 for the value. // Longs take 9 bytes, 1 for the type and 8 for the value.
fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str()); fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str());
// Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length. // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the
// length.
fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str()); fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str());
fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str()); fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str());
} }
int write_java_methods_q_schema( int write_java_methods_q_schema(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap, const AtomDecl& attributionDecl, const string& indent) {
const AtomDecl &attributionDecl,
const string& indent) {
int requiredHelpers = 0; int requiredHelpers = 0;
for (auto signatureInfoMapIt = signatureInfoMap.begin(); for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature. // Print method signature.
vector<java_type_t> signature = signatureInfoMapIt->first; vector<java_type_t> signature = signatureInfoMapIt->first;
fprintf(out, "%spublic static void write(int code", indent.c_str()); fprintf(out, "%spublic static void write(int code", indent.c_str());
int argIndex = 1; int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) { for (auto chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
java_type_name(chainField.javaType), chainField.name.c_str()); chainField.name.c_str());
} }
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", android.util.SparseArray<Object> valueMap"); fprintf(out, ", android.util.SparseArray<Object> valueMap");
@@ -81,190 +83,174 @@ int write_java_methods_q_schema(
fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n", fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out,
"%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n", "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + "
"INT_TYPE_SIZE;\n",
indent.c_str()); indent.c_str());
argIndex = 1; argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
switch (*arg) { switch (*arg) {
case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BOOLEAN:
case JAVA_TYPE_INT: case JAVA_TYPE_INT:
case JAVA_TYPE_FLOAT: case JAVA_TYPE_FLOAT:
case JAVA_TYPE_ENUM: case JAVA_TYPE_ENUM:
fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str());
break; break;
case JAVA_TYPE_LONG: case JAVA_TYPE_LONG:
// Longs take 9 bytes, 1 for the type and 8 for the value. // Longs take 9 bytes, 1 for the type and 8 for the value.
fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str());
break; break;
case JAVA_TYPE_STRING: case JAVA_TYPE_STRING:
// Strings take 5 metadata bytes + length of byte encoded string. // Strings take 5 metadata bytes + length of byte encoded string.
fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex); fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex);
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, fprintf(out,
"%s byte[] arg%dBytes = " "%s byte[] arg%dBytes = "
"arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
indent.c_str(), argIndex, argIndex); indent.c_str(), argIndex, argIndex);
fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
indent.c_str(), argIndex); indent.c_str(), argIndex);
break; break;
case JAVA_TYPE_BYTE_ARRAY: case JAVA_TYPE_BYTE_ARRAY:
// Byte arrays take 5 metadata bytes + length of byte array. // Byte arrays take 5 metadata bytes + length of byte array.
fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex); fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex); fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex);
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
indent.c_str(), argIndex); indent.c_str(), argIndex);
break; break;
case JAVA_TYPE_ATTRIBUTION_CHAIN: case JAVA_TYPE_ATTRIBUTION_CHAIN: {
{ const char* uidName = attributionDecl.fields.front().name.c_str();
const char* uidName = attributionDecl.fields.front().name.c_str(); const char* tagName = attributionDecl.fields.back().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str(); // Null checks on the params.
// Null checks on the params. fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName);
fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName); fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName,
fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName, java_type_name(attributionDecl.fields.front().javaType));
java_type_name(attributionDecl.fields.front().javaType)); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName);
fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName); fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName,
fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName, java_type_name(attributionDecl.fields.back().javaType));
java_type_name(attributionDecl.fields.back().javaType)); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, "%s }\n", indent.c_str());
// First check that the lengths of the uid and tag arrays are the same. // First check that the lengths of the uid and tag arrays are the
fprintf(out, "%s if (%s.length != %s.length) {\n", // same.
indent.c_str(), uidName, tagName); fprintf(out, "%s if (%s.length != %s.length) {\n", indent.c_str(), uidName,
fprintf(out, "%s return;\n", indent.c_str()); tagName);
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s return;\n", indent.c_str());
fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
indent.c_str(), tagName); fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(),
fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n", tagName);
indent.c_str(), argIndex, tagName, tagName); fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
fprintf(out, indent.c_str(), argIndex, tagName, tagName);
"%s int str%dlen = " fprintf(out,
"str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n", "%s int str%dlen = "
indent.c_str(), argIndex, argIndex); "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8)."
fprintf(out, "length;\n",
"%s attrSize += " indent.c_str(), argIndex, argIndex);
"LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n", fprintf(out,
indent.c_str(), argIndex); "%s attrSize += "
fprintf(out, "%s }\n", indent.c_str()); "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + "
fprintf(out, "%s needed += attrSize;\n", indent.c_str()); "str%dlen;\n",
break; indent.c_str(), argIndex);
} fprintf(out, "%s }\n", indent.c_str());
case JAVA_TYPE_KEY_VALUE_PAIR: fprintf(out, "%s needed += attrSize;\n", indent.c_str());
{ break;
fprintf(out, }
"%s // Calculate bytes needed by Key Value Pairs.\n", case JAVA_TYPE_KEY_VALUE_PAIR: {
indent.c_str()); fprintf(out, "%s // Calculate bytes needed by Key Value Pairs.\n",
fprintf(out, indent.c_str());
"%s final int count = valueMap.size();\n", indent.c_str()); fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
fprintf(out, fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
"%s android.util.SparseIntArray intMap = null;\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
"%s android.util.SparseLongArray longMap = null;\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
"%s android.util.SparseArray<String> stringMap = null;\n", indent.c_str());
indent.c_str()); fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
fprintf(out, indent.c_str());
"%s android.util.SparseArray<Float> floatMap = null;\n", indent.c_str()); fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n",
fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
"%s for (int i = 0; i < count; i++) {\n", indent.c_str()); fprintf(out, "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
fprintf(out, fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
"%s final int key = valueMap.keyAt(i);\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
"%s final Object value = valueMap.valueAt(i);\n", fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
"%s if (value instanceof Integer) {\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
"%s keyValuePairSize += LIST_TYPE_OVERHEAD\n", fprintf(out, "%s intMap = new android.util.SparseIntArray();\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n", fprintf(out, "%s intMap.put(key, (Integer) value);\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s } else if (value instanceof Long) {\n", indent.c_str());
"%s if (null == intMap) {\n", indent.c_str()); fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
fprintf(out, indent.c_str());
"%s intMap = new android.util.SparseIntArray();\n", indent.c_str()); fprintf(out, "%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
fprintf(out, indent.c_str());
"%s }\n", indent.c_str()); fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
fprintf(out, fprintf(out,
"%s intMap.put(key, (Integer) value);\n", indent.c_str()); "%s longMap = new "
fprintf(out, "android.util.SparseLongArray();\n",
"%s } else if (value instanceof Long) {\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s keyValuePairSize += LIST_TYPE_OVERHEAD\n", fprintf(out, "%s longMap.put(key, (Long) value);\n", indent.c_str());
indent.c_str()); fprintf(out, "%s } else if (value instanceof String) {\n",
fprintf(out, indent.c_str());
"%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n", fprintf(out,
indent.c_str()); "%s final String str = (value == null) ? \"\" : "
fprintf(out, "(String) value;\n",
"%s if (null == longMap) {\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out,
"%s longMap = new android.util.SparseLongArray();\n", indent.c_str()); "%s final int len = "
fprintf(out, "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
"%s }\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out,
"%s longMap.put(key, (Long) value);\n", indent.c_str()); "%s keyValuePairSize += LIST_TYPE_OVERHEAD + "
fprintf(out, "INT_TYPE_SIZE\n",
"%s } else if (value instanceof String) {\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s + STRING_TYPE_OVERHEAD + len;\n",
"%s final String str = (value == null) ? \"\" : " indent.c_str());
"(String) value;\n", fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
indent.c_str()); fprintf(out,
fprintf(out, "%s stringMap = new "
"%s final int len = " "android.util.SparseArray<>();\n",
"str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n", indent.c_str());
indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, fprintf(out, "%s stringMap.put(key, str);\n", indent.c_str());
"%s keyValuePairSize += LIST_TYPE_OVERHEAD + INT_TYPE_SIZE\n", fprintf(out, "%s } else if (value instanceof Float) {\n",
indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
"%s + STRING_TYPE_OVERHEAD + len;\n", indent.c_str());
indent.c_str()); fprintf(out, "%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
fprintf(out, indent.c_str());
"%s if (null == stringMap) {\n", indent.c_str()); fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
fprintf(out, fprintf(out,
"%s stringMap = new android.util.SparseArray<>();\n", indent.c_str()); "%s floatMap = new "
fprintf(out, "android.util.SparseArray<>();\n",
"%s }\n", indent.c_str()); indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s stringMap.put(key, str);\n", indent.c_str()); fprintf(out, "%s floatMap.put(key, (Float) value);\n",
fprintf(out, indent.c_str());
"%s } else if (value instanceof Float) {\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, fprintf(out, "%s }\n", indent.c_str());
"%s keyValuePairSize += LIST_TYPE_OVERHEAD\n", fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str());
indent.c_str()); break;
fprintf(out, }
"%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n", default:
indent.c_str()); // Unsupported types: OBJECT, DOUBLE.
fprintf(out, fprintf(stderr, "Module logging does not yet support Object and Double.\n");
"%s if (null == floatMap) {\n", indent.c_str()); return 1;
fprintf(out,
"%s floatMap = new android.util.SparseArray<>();\n", indent.c_str());
fprintf(out,
"%s }\n", indent.c_str());
fprintf(out,
"%s floatMap.put(key, (Float) value);\n", indent.c_str());
fprintf(out,
"%s }\n", indent.c_str());
fprintf(out,
"%s }\n", indent.c_str());
fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str());
break;
}
default:
// Unsupported types: OBJECT, DOUBLE.
fprintf(stderr, "Module logging does not yet support Object and Double.\n");
return 1;
} }
argIndex++; argIndex++;
} }
// Now we have the size that is needed. Check for overflow and return if needed. // Now we have the size that is needed. Check for overflow and return if
// needed.
fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str()); fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str());
fprintf(out, "%s return;\n", indent.c_str()); fprintf(out, "%s return;\n", indent.c_str());
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
@@ -279,7 +265,8 @@ int write_java_methods_q_schema(
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
// Write timestamp. // Write timestamp.
fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n", indent.c_str()); fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n",
indent.c_str());
fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str()); fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str());
fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
@@ -291,77 +278,82 @@ int write_java_methods_q_schema(
// Write the args. // Write the args.
argIndex = 1; argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
switch (*arg) { switch (*arg) {
case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BOOLEAN:
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", indent.c_str(),
indent.c_str(), argIndex); argIndex);
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
break; break;
case JAVA_TYPE_INT: case JAVA_TYPE_INT:
case JAVA_TYPE_ENUM: case JAVA_TYPE_ENUM:
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(),
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); argIndex);
break; fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
case JAVA_TYPE_FLOAT: break;
requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; case JAVA_TYPE_FLOAT:
fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str()); requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(),
break; argIndex);
case JAVA_TYPE_LONG: fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str()); break;
fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex); case JAVA_TYPE_LONG:
fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
break; fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(),
case JAVA_TYPE_STRING: argIndex);
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n", break;
indent.c_str(), argIndex); case JAVA_TYPE_STRING:
fprintf(out, "%s System.arraycopy(" fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
"arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n", fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n",
indent.c_str(), argIndex, argIndex); indent.c_str(), argIndex);
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n", fprintf(out,
indent.c_str(), argIndex); "%s System.arraycopy("
break; "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
case JAVA_TYPE_BYTE_ARRAY: "arg%dBytes.length);\n",
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); indent.c_str(), argIndex, argIndex);
fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
indent.c_str(), argIndex); indent.c_str(), argIndex);
fprintf(out, "%s System.arraycopy(" break;
"arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n", case JAVA_TYPE_BYTE_ARRAY:
indent.c_str(), argIndex, argIndex); fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", indent.c_str(),
indent.c_str(), argIndex); argIndex);
break; fprintf(out,
case JAVA_TYPE_ATTRIBUTION_CHAIN: "%s System.arraycopy("
{ "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION; indent.c_str(), argIndex, argIndex);
const char* uidName = attributionDecl.fields.front().name.c_str(); fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
const char* tagName = attributionDecl.fields.back().name.c_str(); indent.c_str(), argIndex);
break;
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n", indent.c_str(), fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n",
uidName, tagName); indent.c_str(), uidName, tagName);
fprintf(out, "%s pos += attrSize;\n", indent.c_str()); fprintf(out, "%s pos += attrSize;\n", indent.c_str());
break; break;
} }
case JAVA_TYPE_KEY_VALUE_PAIR: case JAVA_TYPE_KEY_VALUE_PAIR:
requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT; requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS; requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
fprintf(out, fprintf(out,
"%s writeKeyValuePairs(buff, pos, (byte) count, intMap, longMap, " "%s writeKeyValuePairs(buff, pos, (byte) count, intMap, "
"stringMap, floatMap);\n", "longMap, "
indent.c_str()); "stringMap, floatMap);\n",
fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str()); indent.c_str());
break; fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str());
default: break;
// Unsupported types: OBJECT, DOUBLE. default:
fprintf(stderr, // Unsupported types: OBJECT, DOUBLE.
"Object and Double are not supported in module logging"); fprintf(stderr, "Object and Double are not supported in module logging");
return 1; return 1;
} }
argIndex++; argIndex++;
} }
@@ -376,11 +368,8 @@ int write_java_methods_q_schema(
return 0; return 0;
} }
void write_java_helpers_for_q_schema_methods( void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
FILE* out, const int requiredHelpers, const string& indent) {
const AtomDecl &attributionDecl,
const int requiredHelpers,
const string& indent) {
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str()); fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str());
fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n", fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n",
@@ -420,8 +409,7 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos", fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
indent.c_str()); indent.c_str());
for (auto chainField : attributionDecl.fields) { for (auto chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
java_type_name(chainField.javaType), chainField.name.c_str());
} }
fprintf(out, ") {\n"); fprintf(out, ") {\n");
@@ -437,8 +425,8 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName); fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName);
// Write the list begin. // Write the list begin.
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
fprintf(out, "%s buff[pos + 1] = %lu;\n", fprintf(out, "%s buff[pos + 1] = %lu;\n", indent.c_str(),
indent.c_str(), attributionDecl.fields.size()); attributionDecl.fields.size());
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
// Write the uid. // Write the uid.
@@ -447,18 +435,20 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
// Write the tag. // Write the tag.
fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", indent.c_str(),
indent.c_str(), tagName, tagName, tagName); tagName, tagName, tagName);
fprintf(out, "%s byte[] %sByte = " fprintf(out,
"%s byte[] %sByte = "
"%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", "%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
indent.c_str(), tagName, tagName); indent.c_str(), tagName, tagName);
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName); fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName);
fprintf(out, "%s System.arraycopy(" fprintf(out,
"%s System.arraycopy("
"%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n", "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
indent.c_str(), tagName, tagName); indent.c_str(), tagName, tagName);
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", indent.c_str(),
indent.c_str(), tagName); tagName);
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
fprintf(out, "%s}\n", indent.c_str()); fprintf(out, "%s}\n", indent.c_str());
fprintf(out, "\n"); fprintf(out, "\n");
@@ -466,7 +456,8 @@ void write_java_helpers_for_q_schema_methods(
if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) { if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) {
fprintf(out, fprintf(out,
"%sprivate static void writeKeyValuePairs(byte[] buff, int pos, byte numPairs,\n", "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, "
"byte numPairs,\n",
indent.c_str()); indent.c_str());
fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str()); fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str());
fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str()); fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str());
@@ -515,7 +506,9 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
// Write Strings. // Write Strings.
fprintf(out, "%s final int stringMapSize = null == stringMap ? 0 : stringMap.size();\n", fprintf(out,
"%s final int stringMapSize = null == stringMap ? 0 : "
"stringMap.size();\n",
indent.c_str()); indent.c_str());
fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str()); fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
@@ -523,7 +516,8 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str()); fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
fprintf(out, "%s final int key = stringMap.keyAt(i);\n", indent.c_str()); fprintf(out, "%s final int key = stringMap.keyAt(i);\n", indent.c_str());
fprintf(out, "%s final String value = stringMap.valueAt(i);\n", indent.c_str()); fprintf(out, "%s final String value = stringMap.valueAt(i);\n", indent.c_str());
fprintf(out, "%s final byte[] valueBytes = " fprintf(out,
"%s final byte[] valueBytes = "
"value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n", "value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
indent.c_str()); indent.c_str());
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
@@ -531,15 +525,19 @@ void write_java_helpers_for_q_schema_methods(
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str()); fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
fprintf(out, "%s copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str()); fprintf(out, "%s copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str());
fprintf(out, "%s System.arraycopy(" fprintf(out,
"valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, valueBytes.length);\n", "%s System.arraycopy("
"valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
"valueBytes.length);\n",
indent.c_str()); indent.c_str());
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n", fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n",
indent.c_str()); indent.c_str());
fprintf(out, "%s }\n", indent.c_str()); fprintf(out, "%s }\n", indent.c_str());
// Write floats. // Write floats.
fprintf(out, "%s final int floatMapSize = null == floatMap ? 0 : floatMap.size();\n", fprintf(out,
"%s final int floatMapSize = null == floatMap ? 0 : "
"floatMap.size();\n",
indent.c_str()); indent.c_str());
fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str()); fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str());
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str()); fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
@@ -559,12 +557,11 @@ void write_java_helpers_for_q_schema_methods(
} }
} }
// This method is called in main.cpp to generate StatsLog for modules that's compatible with // This method is called in main.cpp to generate StatsLog for modules that's
// Q at compile-time. // compatible with Q at compile-time.
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
const AtomDecl &attributionDecl, const AtomDecl& attributionDecl, const string& javaClass,
const string& javaClass, const string& javaPackage, const string& javaPackage, const bool supportWorkSource) {
const bool supportWorkSource) {
// Print prelude // Print prelude
fprintf(out, "// This file is autogenerated\n"); fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n"); fprintf(out, "\n");
@@ -590,8 +587,7 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
int errors = 0; int errors = 0;
// Print write methods // Print write methods
fprintf(out, " // Write methods\n"); fprintf(out, " // Write methods\n");
errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, " ");
" ");
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap); errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
if (supportWorkSource) { if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap); errors += write_java_work_source_methods(out, atoms.signatureInfoMap);

View File

@@ -16,14 +16,14 @@
#pragma once #pragma once
#include "Collation.h" #include <stdio.h>
#include <string.h>
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <stdio.h> #include "Collation.h"
#include <string.h>
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
@@ -33,20 +33,15 @@ using namespace std;
void write_java_q_logging_constants(FILE* out, const string& indent); void write_java_q_logging_constants(FILE* out, const string& indent);
int write_java_methods_q_schema( int write_java_methods_q_schema(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap, const AtomDecl& attributionDecl, const string& indent);
const AtomDecl &attributionDecl,
const string& indent);
void write_java_helpers_for_q_schema_methods( void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
FILE * out, const int requiredHelpers, const string& indent);
const AtomDecl &attributionDecl,
const int requiredHelpers,
const string& indent);
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
const AtomDecl &attributionDecl, const string& javaClass, const AtomDecl& attributionDecl, const string& javaClass,
const string& javaPackage, const bool supportWorkSource); const string& javaPackage, const bool supportWorkSource);
} // namespace stats_log_api_gen } // namespace stats_log_api_gen
} // namespace android } // namespace android

View File

@@ -1,22 +1,21 @@
#include "Collation.h"
#include "atoms_info_writer.h"
#include "java_writer.h"
#include "java_writer_q.h"
#include "native_writer.h"
#include "utils.h"
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include <map>
#include <set>
#include <vector>
#include <getopt.h> #include <getopt.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <map>
#include <set>
#include <vector>
#include "Collation.h"
#include "atoms_info_writer.h"
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include "java_writer.h"
#include "java_writer_q.h"
#include "native_writer.h"
#include "utils.h"
using namespace google::protobuf; using namespace google::protobuf;
using namespace std; using namespace std;
@@ -25,25 +24,34 @@ namespace stats_log_api_gen {
using android::os::statsd::Atom; using android::os::statsd::Atom;
static void static void print_usage() {
print_usage()
{
fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n"); fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "OPTIONS\n"); fprintf(stderr, "OPTIONS\n");
fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n"); fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n");
fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n"); fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n");
fprintf(stderr, fprintf(stderr,
" --atomsInfoCpp FILENAME the header file to output for statsd metadata\n"); " --atomsInfoCpp FILENAME the header file to output for "
fprintf(stderr, " --atomsInfoHeader FILENAME the cpp file to output for statsd metadata\n"); "statsd metadata\n");
fprintf(stderr,
" --atomsInfoHeader FILENAME the cpp file to output for statsd "
"metadata\n");
fprintf(stderr, " --help this message\n"); fprintf(stderr, " --help this message\n");
fprintf(stderr, " --java FILENAME the java file to output\n"); fprintf(stderr, " --java FILENAME the java file to output\n");
fprintf(stderr, " --module NAME optional, module name to generate outputs for\n"); fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n"); fprintf(stderr,
fprintf(stderr, " comma separated namespace of the files\n"); " --namespace COMMA,SEP,NAMESPACE required for cpp/header with "
fprintf(stderr," --importHeader NAME required for cpp/jni to say which header to import " "module\n");
fprintf(stderr,
" comma separated namespace of "
"the files\n");
fprintf(stderr,
" --importHeader NAME required for cpp/jni to say which header to "
"import "
"for write helpers\n"); "for write helpers\n");
fprintf(stderr," --atomsInfoImportHeader NAME required for cpp to say which header to import " fprintf(stderr,
" --atomsInfoImportHeader NAME required for cpp to say which "
"header to import "
"for statsd metadata\n"); "for statsd metadata\n");
fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n"); fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n");
fprintf(stderr, " required for java with module\n"); fprintf(stderr, " required for java with module\n");
@@ -51,17 +59,18 @@ print_usage()
fprintf(stderr, " Optional for Java with module.\n"); fprintf(stderr, " Optional for Java with module.\n");
fprintf(stderr, " Default is \"StatsLogInternal\"\n"); fprintf(stderr, " Default is \"StatsLogInternal\"\n");
fprintf(stderr, " --supportQ Include runtime support for Android Q.\n"); fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
fprintf(stderr, " --worksource Include support for logging WorkSource objects.\n"); fprintf(stderr,
fprintf(stderr, " --compileQ Include compile-time support for Android Q " " --worksource Include support for logging WorkSource "
"objects.\n");
fprintf(stderr,
" --compileQ Include compile-time support for Android Q "
"(Java only).\n"); "(Java only).\n");
} }
/** /**
* Do the argument parsing and execute the tasks. * Do the argument parsing and execute the tasks.
*/ */
static int static int run(int argc, char const* const* argv) {
run(int argc, char const*const* argv)
{
string cppFilename; string cppFilename;
string headerFilename; string headerFilename;
string javaFilename; string javaFilename;
@@ -171,11 +180,8 @@ run(int argc, char const*const* argv)
index++; index++;
} }
if (cppFilename.size() == 0 if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0 &&
&& headerFilename.size() == 0 atomsInfoHeaderFilename.size() == 0 && atomsInfoCppFilename.size() == 0) {
&& javaFilename.size() == 0
&& atomsInfoHeaderFilename.size() == 0
&& atomsInfoCppFilename.size() == 0) {
print_usage(); print_usage();
return 1; return 1;
} }
@@ -201,8 +207,8 @@ run(int argc, char const*const* argv)
AtomDecl attributionDecl; AtomDecl attributionDecl;
vector<java_type_t> attributionSignature; vector<java_type_t> attributionSignature;
collate_atom(android::os::statsd::AttributionNode::descriptor(), collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
&attributionDecl, &attributionSignature); &attributionSignature);
// Write the atoms info .cpp file // Write the atoms info .cpp file
if (atomsInfoCppFilename.size() != 0) { if (atomsInfoCppFilename.size() != 0) {
@@ -211,8 +217,8 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str()); fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str());
return 1; return 1;
} }
errorCount = android::stats_log_api_gen::write_atoms_info_cpp( errorCount = android::stats_log_api_gen::write_atoms_info_cpp(out, atoms, cppNamespace,
out, atoms, cppNamespace, atomsInfoCppHeaderImport); atomsInfoCppHeaderImport);
fclose(out); fclose(out);
} }
@@ -227,7 +233,6 @@ run(int argc, char const*const* argv)
fclose(out); fclose(out);
} }
// Write the .cpp file // Write the .cpp file
if (cppFilename.size() != 0) { if (cppFilename.size() != 0) {
FILE* out = fopen(cppFilename.c_str(), "w"); FILE* out = fopen(cppFilename.c_str(), "w");
@@ -240,13 +245,14 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
return 1; return 1;
} }
// If this is for a specific module, the header file to import must also be provided. // If this is for a specific module, the header file to import must also be
// provided.
if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) { if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
fprintf(stderr, "Must supply --headerImport if supplying a specific module\n"); fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
return 1; return 1;
} }
errorCount = android::stats_log_api_gen::write_stats_log_cpp( errorCount = android::stats_log_api_gen::write_stats_log_cpp(
out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ); out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
fclose(out); fclose(out);
} }
@@ -261,8 +267,8 @@ run(int argc, char const*const* argv)
if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
} }
errorCount = android::stats_log_api_gen::write_stats_log_header( errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl,
out, atoms, attributionDecl, cppNamespace); cppNamespace);
fclose(out); fclose(out);
} }
@@ -291,8 +297,7 @@ run(int argc, char const*const* argv)
if (compileQ) { if (compileQ) {
errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module( errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
out, atoms, attributionDecl, javaClass, javaPackage, out, atoms, attributionDecl, javaClass, javaPackage, supportWorkSource);
supportWorkSource);
} else { } else {
errorCount = android::stats_log_api_gen::write_stats_log_java( errorCount = android::stats_log_api_gen::write_stats_log_java(
out, atoms, attributionDecl, javaClass, javaPackage, supportQ, out, atoms, attributionDecl, javaClass, javaPackage, supportQ,
@@ -311,9 +316,7 @@ run(int argc, char const*const* argv)
/** /**
* Main. * Main.
*/ */
int int main(int argc, char const* const* argv) {
main(int argc, char const*const* argv)
{
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
return android::stats_log_api_gen::run(argc, argv); return android::stats_log_api_gen::run(argc, argv);

View File

@@ -15,45 +15,38 @@
*/ */
#include "native_writer.h" #include "native_writer.h"
#include "utils.h" #include "utils.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
static void write_annotations( static void write_annotations(FILE* out, int argIndex,
FILE* out, int argIndex, const FieldNumberToAnnotations& fieldNumberToAnnotations,
const FieldNumberToAnnotations& fieldNumberToAnnotations, const string& methodPrefix, const string& methodSuffix) {
const string& methodPrefix,
const string& methodSuffix) {
auto fieldNumberToAnnotationsIt = fieldNumberToAnnotations.find(argIndex); auto fieldNumberToAnnotationsIt = fieldNumberToAnnotations.find(argIndex);
if (fieldNumberToAnnotationsIt == fieldNumberToAnnotations.end()) { if (fieldNumberToAnnotationsIt == fieldNumberToAnnotations.end()) {
return; return;
} }
const set<shared_ptr<Annotation>>& annotations = const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotationsIt->second;
fieldNumberToAnnotationsIt->second;
for (const shared_ptr<Annotation>& annotation : annotations) { for (const shared_ptr<Annotation>& annotation : annotations) {
// TODO(b/151744250): Group annotations for same atoms. // TODO(b/151744250): Group annotations for same atoms.
// TODO(b/151786433): Write atom constant name instead of atom id literal. // TODO(b/151786433): Write atom constant name instead of atom id literal.
fprintf(out, " if (code == %d) {\n", annotation->atomId); fprintf(out, " if (code == %d) {\n", annotation->atomId);
switch(annotation->type) { switch (annotation->type) {
// TODO(b/151776731): Check for reset state annotation and only include reset state // TODO(b/151776731): Check for reset state annotation and only include
// when field value == default state annotation value. // reset state when field value == default state annotation value.
case ANNOTATION_TYPE_INT: case ANNOTATION_TYPE_INT:
// TODO(b/151786433): Write annotation constant name instead of // TODO(b/151786433): Write annotation constant name instead of
// annotation id literal. // annotation id literal.
fprintf(out, " %saddInt32Annotation(%s%d, %d);\n", fprintf(out, " %saddInt32Annotation(%s%d, %d);\n", methodPrefix.c_str(),
methodPrefix.c_str(), methodSuffix.c_str(), annotation->annotationId, annotation->value.intValue);
methodSuffix.c_str(),
annotation->annotationId,
annotation->value.intValue);
break; break;
case ANNOTATION_TYPE_BOOL: case ANNOTATION_TYPE_BOOL:
// TODO(b/151786433): Write annotation constant name instead of // TODO(b/151786433): Write annotation constant name instead of
// annotation id literal. // annotation id literal.
fprintf(out, " %saddBoolAnnotation(%s%d, %s);\n", fprintf(out, " %saddBoolAnnotation(%s%d, %s);\n", methodPrefix.c_str(),
methodPrefix.c_str(), methodSuffix.c_str(), annotation->annotationId,
methodSuffix.c_str(),
annotation->annotationId,
annotation->value.boolValue ? "true" : "false"); annotation->value.boolValue ? "true" : "false");
break; break;
default: default:
@@ -61,29 +54,28 @@ static void write_annotations(
} }
fprintf(out, " }\n"); fprintf(out, " }\n");
} }
} }
static int write_native_stats_write_methods(FILE* out, const Atoms& atoms, static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
const AtomDecl& attributionDecl, const bool supportQ) { const AtomDecl& attributionDecl, const bool supportQ) {
fprintf(out, "\n"); fprintf(out, "\n");
for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin(); for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) { signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first; vector<java_type_t> signature = signatureInfoMapIt->first;
const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second; const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second;
// Key value pairs not supported in native. // Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) { if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
continue; continue;
} }
write_native_method_signature(out, "int stats_write", signature, write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
attributionDecl, " {");
int argIndex = 1; int argIndex = 1;
if (supportQ) { if (supportQ) {
fprintf(out, " StatsEventCompat event;\n"); fprintf(out, " StatsEventCompat event;\n");
fprintf(out, " event.setAtomId(code);\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(); for (vector<java_type_t>::const_iterator arg = signature.begin();
arg != signature.end(); arg++) { arg != signature.end(); arg++) {
switch (*arg) { switch (*arg) {
case JAVA_TYPE_ATTRIBUTION_CHAIN: { case JAVA_TYPE_ATTRIBUTION_CHAIN: {
const char* uidName = attributionDecl.fields.front().name.c_str(); const char* uidName = attributionDecl.fields.front().name.c_str();
@@ -99,7 +91,7 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BOOLEAN:
fprintf(out, " event.writeBool(arg%d);\n", argIndex); fprintf(out, " event.writeBool(arg%d);\n", argIndex);
break; break;
case JAVA_TYPE_INT: // Fall through. case JAVA_TYPE_INT: // Fall through.
case JAVA_TYPE_ENUM: case JAVA_TYPE_ENUM:
fprintf(out, " event.writeInt32(arg%d);\n", argIndex); fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
break; break;
@@ -124,8 +116,10 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
} else { } else {
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n"); fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
fprintf(out, " AStatsEvent_setAtomId(event, code);\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(); for (vector<java_type_t>::const_iterator arg = signature.begin();
arg != signature.end(); arg++) { arg != signature.end(); arg++) {
switch (*arg) { switch (*arg) {
case JAVA_TYPE_ATTRIBUTION_CHAIN: { case JAVA_TYPE_ATTRIBUTION_CHAIN: {
const char* uidName = attributionDecl.fields.front().name.c_str(); const char* uidName = attributionDecl.fields.front().name.c_str();
@@ -140,13 +134,14 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
case JAVA_TYPE_BYTE_ARRAY: case JAVA_TYPE_BYTE_ARRAY:
fprintf(out, fprintf(out,
" AStatsEvent_writeByteArray(event, " " AStatsEvent_writeByteArray(event, "
"reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n", "reinterpret_cast<const uint8_t*>(arg%d.arg), "
"arg%d.arg_length);\n",
argIndex, argIndex); argIndex, argIndex);
break; break;
case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BOOLEAN:
fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex); fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
break; break;
case JAVA_TYPE_INT: // Fall through. case JAVA_TYPE_INT: // Fall through.
case JAVA_TYPE_ENUM: case JAVA_TYPE_ENUM:
fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex); fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
break; break;
@@ -165,7 +160,7 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
return 1; return 1;
} }
write_annotations(out, argIndex, fieldNumberToAnnotations, "AStatsEvent_", write_annotations(out, argIndex, fieldNumberToAnnotations, "AStatsEvent_",
"event, "); "event, ");
argIndex++; argIndex++;
} }
fprintf(out, " const int ret = AStatsEvent_write(event);\n"); fprintf(out, " const int ret = AStatsEvent_write(event);\n");
@@ -178,10 +173,10 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
} }
static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms, static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
const AtomDecl& attributionDecl) { const AtomDecl& attributionDecl) {
fprintf(out, "\n"); fprintf(out, "\n");
for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin(); for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) { signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
vector<java_type_t> signature = signature_it->first; vector<java_type_t> signature = signature_it->first;
// Key value pairs not supported in native. // Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) { if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
@@ -189,7 +184,7 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
} }
write_native_method_signature(out, "int stats_write_non_chained", signature, write_native_method_signature(out, "int stats_write_non_chained", signature,
attributionDecl, " {"); attributionDecl, " {");
vector<java_type_t> newSignature; vector<java_type_t> newSignature;
@@ -212,17 +207,14 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
fprintf(out, "}\n\n"); fprintf(out, "}\n\n");
} }
} }
static void write_native_method_header( static void write_native_method_header(
FILE* out, FILE* out, const string& methodName,
const string& methodName,
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
const AtomDecl &attributionDecl) { const AtomDecl& attributionDecl) {
for (auto signatureInfoMapIt = signatureInfoMap.begin(); for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first; vector<java_type_t> signature = signatureInfoMapIt->first;
// Key value pairs not supported in native. // Key value pairs not supported in native.
@@ -233,9 +225,9 @@ static void write_native_method_header(
} }
} }
int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& cppNamespace, const string& cppNamespace, const string& importHeader,
const string& importHeader, const bool supportQ) { const bool supportQ) {
// Print prelude // Print prelude
fprintf(out, "// This file is autogenerated\n"); fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n"); fprintf(out, "\n");
@@ -260,8 +252,8 @@ int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributi
return 0; return 0;
} }
int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& cppNamespace) { const string& cppNamespace) {
// Print prelude // Print prelude
fprintf(out, "// This file is autogenerated\n"); fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n"); fprintf(out, "\n");
@@ -286,21 +278,18 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attrib
fprintf(out, "//\n"); fprintf(out, "//\n");
fprintf(out, "// Constants for enum values\n"); fprintf(out, "// Constants for enum values\n");
fprintf(out, "//\n\n"); fprintf(out, "//\n\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin(); for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) { field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ENUM) { if (field->javaType == JAVA_TYPE_ENUM) {
fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
field->name.c_str());
for (map<int, string>::const_iterator value = field->enumValues.begin(); for (map<int, string>::const_iterator value = field->enumValues.begin();
value != field->enumValues.end(); value++) { value != field->enumValues.end(); value++) {
fprintf(out, "const int32_t %s__%s__%s = %d;\n", fprintf(out, "const int32_t %s__%s__%s = %d;\n",
make_constant_name(atom->message).c_str(), make_constant_name(atom->message).c_str(),
make_constant_name(field->name).c_str(), make_constant_name(field->name).c_str(),
make_constant_name(value->second).c_str(), make_constant_name(value->second).c_str(), value->first);
value->first);
} }
fprintf(out, "\n"); fprintf(out, "\n");
} }
@@ -325,8 +314,8 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attrib
fprintf(out, "//\n"); fprintf(out, "//\n");
fprintf(out, "// Write flattened methods\n"); fprintf(out, "// Write flattened methods\n");
fprintf(out, "//\n"); fprintf(out, "//\n");
write_native_method_header(out, "int stats_write_non_chained", write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
atoms.nonChainedSignatureInfoMap, attributionDecl); attributionDecl);
fprintf(out, "\n"); fprintf(out, "\n");
write_closing_namespace(out, cppNamespace); write_closing_namespace(out, cppNamespace);

View File

@@ -16,22 +16,22 @@
#pragma once #pragma once
#include "Collation.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "Collation.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
using namespace std; using namespace std;
int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& cppNamespace, const string& importHeader, const string& cppNamespace, const string& importHeader,
const bool supportQ); const bool supportQ);
int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& cppNamespace); const string& cppNamespace);
} // namespace stats_log_api_gen } // namespace stats_log_api_gen
} // namespace android } // namespace android

View File

@@ -15,12 +15,11 @@
*/ */
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
#include "Collation.h"
#include <stdio.h> #include <stdio.h>
#include "Collation.h"
#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
@@ -31,14 +30,13 @@ using std::vector;
/** /**
* Return whether the map contains a vector of the elements provided. * Return whether the map contains a vector of the elements provided.
*/ */
static bool static bool map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s,
map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s, int count, ...) int count, ...) {
{
va_list args; va_list args;
vector<java_type_t> v; vector<java_type_t> v;
va_start(args, count); va_start(args, count);
for (int i=0; i<count; i++) { for (int i = 0; i < count; i++) {
v.push_back((java_type_t)va_arg(args, int)); v.push_back((java_type_t)va_arg(args, int));
} }
va_end(args); va_end(args);
@@ -49,34 +47,33 @@ map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s,
/** /**
* Expect that the provided map contains the elements provided. * Expect that the provided map contains the elements provided.
*/ */
#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \ #define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \
do { \ do { \
int count = sizeof((int[]){__VA_ARGS__})/sizeof(int); \ int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int); \
EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \ EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \
} while(0) } while (0)
/** Expects that the provided atom has no enum values for any field. */ /** Expects that the provided atom has no enum values for any field. */
#define EXPECT_NO_ENUM_FIELD(atom) \ #define EXPECT_NO_ENUM_FIELD(atom) \
do { \ do { \
for (vector<AtomField>::const_iterator field = atom->fields.begin(); \ for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
field != atom->fields.end(); field++) { \ field != atom->fields.end(); field++) { \
EXPECT_TRUE(field->enumValues.empty()); \ EXPECT_TRUE(field->enumValues.empty()); \
} \ } \
} while(0) } while (0)
/** Expects that exactly one specific field has expected enum values. */ /** Expects that exactly one specific field has expected enum values. */
#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \ #define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \
do { \ do { \
for (vector<AtomField>::const_iterator field = atom->fields.begin(); \ for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
field != atom->fields.end(); field++) { \ field != atom->fields.end(); field++) { \
if (field->name == field_name) { \ if (field->name == field_name) { \
EXPECT_EQ(field->enumValues, values); \ EXPECT_EQ(field->enumValues, values); \
} else { \ } else { \
EXPECT_TRUE(field->enumValues.empty()); \ EXPECT_TRUE(field->enumValues.empty()); \
} \ } \
} \ } \
} while(0) } while (0)
/** /**
* Test a correct collation, with all the types. * Test a correct collation, with all the types.
@@ -95,23 +92,22 @@ TEST(CollationTest, CollateStats) {
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT); EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
// AllTypesAtom // AllTypesAtom
EXPECT_MAP_CONTAINS_SIGNATURE( EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap,
atoms.signatureInfoMap, JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain JAVA_TYPE_FLOAT, // float
JAVA_TYPE_FLOAT, // float JAVA_TYPE_LONG, // int64
JAVA_TYPE_LONG, // int64 JAVA_TYPE_LONG, // uint64
JAVA_TYPE_LONG, // uint64 JAVA_TYPE_INT, // int32
JAVA_TYPE_INT, // int32 JAVA_TYPE_LONG, // fixed64
JAVA_TYPE_LONG, // fixed64 JAVA_TYPE_INT, // fixed32
JAVA_TYPE_INT, // fixed32 JAVA_TYPE_BOOLEAN, // bool
JAVA_TYPE_BOOLEAN, // bool JAVA_TYPE_STRING, // string
JAVA_TYPE_STRING, // string JAVA_TYPE_INT, // uint32
JAVA_TYPE_INT, // uint32 JAVA_TYPE_INT, // AnEnum
JAVA_TYPE_INT, // AnEnum JAVA_TYPE_INT, // sfixed32
JAVA_TYPE_INT, // sfixed32 JAVA_TYPE_LONG, // sfixed64
JAVA_TYPE_LONG, // sfixed64 JAVA_TYPE_INT, // sint32
JAVA_TYPE_INT, // sint32 JAVA_TYPE_LONG // sint64
JAVA_TYPE_LONG // sint64
); );
set<AtomDecl>::const_iterator atom = atoms.decls.begin(); set<AtomDecl>::const_iterator atom = atoms.decls.begin();
@@ -156,7 +152,8 @@ TEST(CollationTest, NonMessageTypeFails) {
} }
/** /**
* Test that atoms that have non-primitive types or repeated fields are rejected. * Test that atoms that have non-primitive types or repeated fields are
* rejected.
*/ */
TEST(CollationTest, FailOnBadTypes) { TEST(CollationTest, FailOnBadTypes) {
Atoms atoms; Atoms atoms;
@@ -170,18 +167,20 @@ TEST(CollationTest, FailOnBadTypes) {
*/ */
TEST(CollationTest, FailOnSkippedFieldsSingle) { TEST(CollationTest, FailOnSkippedFieldsSingle) {
Atoms atoms; Atoms atoms;
int errorCount = collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms); int errorCount =
collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
EXPECT_EQ(1, errorCount); EXPECT_EQ(1, errorCount);
} }
/** /**
* Test that atoms that skip field numbers (not in the first position, and multiple * Test that atoms that skip field numbers (not in the first position, and
* times) are rejected. * multiple times) are rejected.
*/ */
TEST(CollationTest, FailOnSkippedFieldsMultiple) { TEST(CollationTest, FailOnSkippedFieldsMultiple) {
Atoms atoms; Atoms atoms;
int errorCount = collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms); int errorCount =
collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
EXPECT_EQ(2, errorCount); EXPECT_EQ(2, errorCount);
} }
@@ -191,11 +190,11 @@ TEST(CollationTest, FailOnSkippedFieldsMultiple) {
* rejected. * rejected.
*/ */
TEST(CollationTest, FailBadAttributionNodePosition) { TEST(CollationTest, FailBadAttributionNodePosition) {
Atoms atoms; Atoms atoms;
int errorCount = int errorCount =
collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms); collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
EXPECT_EQ(1, errorCount); EXPECT_EQ(1, errorCount);
} }
TEST(CollationTest, FailOnBadStateAtomOptions) { TEST(CollationTest, FailOnBadStateAtomOptions) {
@@ -270,8 +269,8 @@ TEST(CollationTest, RecognizeModuleAtom) {
const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(1); const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(1);
EXPECT_EQ(2u, annotations.size()); EXPECT_EQ(2u, annotations.size());
for (const shared_ptr<Annotation> annotation : annotations) { for (const shared_ptr<Annotation> annotation : annotations) {
EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID ||
|| annotation->annotationId == ANNOTATION_ID_STATE_OPTION); annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
if (ANNOTATION_ID_IS_UID == annotation->annotationId) { if (ANNOTATION_ID_IS_UID == annotation->annotationId) {
EXPECT_EQ(1, annotation->atomId); EXPECT_EQ(1, annotation->atomId);
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
@@ -303,12 +302,11 @@ TEST(CollationTest, RecognizeModule1Atom) {
EXPECT_EQ(1u, fieldNumberToAnnotations.size()); EXPECT_EQ(1u, fieldNumberToAnnotations.size());
int fieldNumber = 1; int fieldNumber = 1;
EXPECT_NE(fieldNumberToAnnotations.end(), fieldNumberToAnnotations.find(fieldNumber)); EXPECT_NE(fieldNumberToAnnotations.end(), fieldNumberToAnnotations.find(fieldNumber));
const set<shared_ptr<Annotation>>& annotations = const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(fieldNumber);
fieldNumberToAnnotations.at(fieldNumber);
EXPECT_EQ(2u, annotations.size()); EXPECT_EQ(2u, annotations.size());
for (const shared_ptr<Annotation> annotation : annotations) { for (const shared_ptr<Annotation> annotation : annotations) {
EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID ||
|| annotation->annotationId == ANNOTATION_ID_STATE_OPTION); annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
if (ANNOTATION_ID_IS_UID == annotation->annotationId) { if (ANNOTATION_ID_IS_UID == annotation->annotationId) {
EXPECT_EQ(1, annotation->atomId); EXPECT_EQ(1, annotation->atomId);
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type); EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);

View File

@@ -22,9 +22,9 @@ namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
static void build_non_chained_decl_map(const Atoms& atoms, static void build_non_chained_decl_map(const Atoms& atoms,
std::map<int, set<AtomDecl>::const_iterator>* decl_map) { std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
atom != atoms.non_chained_decls.end(); atom++) { atom != atoms.non_chained_decls.end(); atom++) {
decl_map->insert(std::make_pair(atom->code, atom)); decl_map->insert(std::make_pair(atom->code, atom));
} }
} }
@@ -36,7 +36,7 @@ string make_constant_name(const string& str) {
string result; string result;
const int N = str.size(); const int N = str.size();
bool underscore_next = false; bool underscore_next = false;
for (int i=0; i<N; i++) { for (int i = 0; i < N; i++) {
char c = str[i]; char c = str[i];
if (c >= 'A' && c <= 'Z') { if (c >= 'A' && c <= 'Z') {
if (underscore_next) { if (underscore_next) {
@@ -99,7 +99,8 @@ const char* java_type_name(java_type_t type) {
} }
// Native // Native
// Writes namespaces for the cpp and header files, returning the number of namespaces written. // Writes namespaces for the cpp and header files, returning the number of
// namespaces written.
void write_namespace(FILE* out, const string& cppNamespaces) { void write_namespace(FILE* out, const string& cppNamespaces) {
vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ","); vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
for (string cppNamespace : cppNamespaceVec) { for (string cppNamespace : cppNamespaceVec) {
@@ -115,35 +116,31 @@ void write_closing_namespace(FILE* out, const string& cppNamespaces) {
} }
} }
static void write_cpp_usage( static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
FILE* out, const string& method_name, const string& atom_code_name, const AtomDecl& atom, const AtomDecl& attributionDecl) {
const AtomDecl& atom, const AtomDecl &attributionDecl) { fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(),
atom_code_name.c_str());
for (vector<AtomField>::const_iterator field = atom.fields.begin(); for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
field != atom.fields.end(); field++) { field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) { for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) { if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", const std::vector<%s>& %s", fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
cpp_type_name(chainField.javaType), chainField.name.c_str());
chainField.name.c_str());
} else { } else {
fprintf(out, ", const %s* %s, size_t %s_length", fprintf(out, ", const %s* %s, size_t %s_length",
cpp_type_name(chainField.javaType), cpp_type_name(chainField.javaType), chainField.name.c_str(),
chainField.name.c_str(), chainField.name.c_str()); chainField.name.c_str());
} }
} }
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", const std::map<int, int32_t>& %s_int" fprintf(out,
", const std::map<int, int64_t>& %s_long" ", const std::map<int, int32_t>& %s_int"
", const std::map<int, char const*>& %s_str" ", const std::map<int, int64_t>& %s_long"
", const std::map<int, float>& %s_float", ", const std::map<int, char const*>& %s_str"
field->name.c_str(), ", const std::map<int, float>& %s_float",
field->name.c_str(), field->name.c_str(), field->name.c_str(), field->name.c_str(),
field->name.c_str(), field->name.c_str());
field->name.c_str());
} else { } else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
} }
@@ -162,8 +159,8 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
size_t i = 0; size_t i = 0;
// Print atom constants // Print atom constants
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
string constant = make_constant_name(atom->name); string constant = make_constant_name(atom->name);
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, " /**\n"); fprintf(out, " /**\n");
@@ -173,7 +170,7 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code); auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) { if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second, write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
attributionDecl); attributionDecl);
} }
fprintf(out, " */\n"); fprintf(out, " */\n");
char const* const comma = (i == atoms.decls.size() - 1) ? "" : ","; char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
@@ -186,30 +183,30 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
} }
void write_native_method_signature(FILE* out, const string& methodName, void write_native_method_signature(FILE* out, const string& methodName,
const vector<java_type_t>& signature, const AtomDecl& attributionDecl, const vector<java_type_t>& signature,
const string& closer) { const AtomDecl& attributionDecl, const string& closer) {
fprintf(out, "%s(int32_t code", methodName.c_str()); fprintf(out, "%s(int32_t code", methodName.c_str());
int argIndex = 1; int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) { for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) { if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", const std::vector<%s>& %s", fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
cpp_type_name(chainField.javaType), chainField.name.c_str());
chainField.name.c_str());
} else { } else {
fprintf(out, ", const %s* %s, size_t %s_length", fprintf(out, ", const %s* %s, size_t %s_length",
cpp_type_name(chainField.javaType), cpp_type_name(chainField.javaType), chainField.name.c_str(),
chainField.name.c_str(), chainField.name.c_str()); chainField.name.c_str());
} }
} }
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", const std::map<int, int32_t>& arg%d_1, " fprintf(out,
"const std::map<int, int64_t>& arg%d_2, " ", const std::map<int, int32_t>& arg%d_1, "
"const std::map<int, char const*>& arg%d_3, " "const std::map<int, int64_t>& arg%d_2, "
"const std::map<int, float>& arg%d_4", "const std::map<int, char const*>& arg%d_3, "
argIndex, argIndex, argIndex, argIndex); "const std::map<int, float>& arg%d_4",
argIndex, argIndex, argIndex, argIndex);
} else { } else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
} }
@@ -219,27 +216,27 @@ void write_native_method_signature(FILE* out, const string& methodName,
} }
void write_native_method_call(FILE* out, const string& methodName, void write_native_method_call(FILE* out, const string& methodName,
const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex) { const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
int argIndex) {
fprintf(out, "%s(code", methodName.c_str()); fprintf(out, "%s(code", methodName.c_str());
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) { for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) { if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", %s", fprintf(out, ", %s", chainField.name.c_str());
} else {
fprintf(out, ", %s, %s_length", chainField.name.c_str(),
chainField.name.c_str()); chainField.name.c_str());
} else { }
fprintf(out, ", %s, %s_length", }
chainField.name.c_str(), chainField.name.c_str()); } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
} fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, argIndex, argIndex,
} argIndex);
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) { } else {
fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, fprintf(out, ", arg%d", argIndex);
argIndex, argIndex, argIndex); }
} else { argIndex++;
fprintf(out, ", arg%d", argIndex);
}
argIndex++;
} }
fprintf(out, ");\n"); fprintf(out, ");\n");
} }
@@ -252,8 +249,8 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms) {
build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map); build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
// Print constants for the atom codes. // Print constants for the atom codes.
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
string constant = make_constant_name(atom->name); string constant = make_constant_name(atom->name);
fprintf(out, "\n"); fprintf(out, "\n");
fprintf(out, " /**\n"); fprintf(out, " /**\n");
@@ -271,20 +268,19 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms) {
void write_java_enum_values(FILE* out, const Atoms& atoms) { void write_java_enum_values(FILE* out, const Atoms& atoms) {
fprintf(out, " // Constants for enum values.\n\n"); fprintf(out, " // Constants for enum values.\n\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
atom != atoms.decls.end(); atom++) { atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin(); for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) { field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ENUM) { if (field->javaType == JAVA_TYPE_ENUM) {
fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
field->name.c_str()); field->name.c_str());
for (map<int, string>::const_iterator value = field->enumValues.begin(); for (map<int, string>::const_iterator value = field->enumValues.begin();
value != field->enumValues.end(); value++) { value != field->enumValues.end(); value++) {
fprintf(out, " public static final int %s__%s__%s = %d;\n", fprintf(out, " public static final int %s__%s__%s = %d;\n",
make_constant_name(atom->message).c_str(), make_constant_name(atom->message).c_str(),
make_constant_name(field->name).c_str(), make_constant_name(field->name).c_str(),
make_constant_name(value->second).c_str(), make_constant_name(value->second).c_str(), value->first);
value->first);
} }
fprintf(out, "\n"); fprintf(out, "\n");
} }
@@ -293,11 +289,11 @@ void write_java_enum_values(FILE* out, const Atoms& atoms) {
} }
void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
const AtomDecl& atom) { const AtomDecl& atom) {
fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(),
method_name.c_str(), atom_code_name.c_str()); atom_code_name.c_str());
for (vector<AtomField>::const_iterator field = atom.fields.begin(); for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
field != atom.fields.end(); field++) { field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", android.os.WorkSource workSource"); fprintf(out, ", android.os.WorkSource workSource");
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) { } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
@@ -312,16 +308,15 @@ void write_java_usage(FILE* out, const string& method_name, const string& atom_c
} }
int write_java_non_chained_methods( int write_java_non_chained_methods(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
for (auto signatureInfoMapIt = signatureInfoMap.begin(); for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature. // Print method signature.
fprintf(out, " public static void write_non_chained(int code"); fprintf(out, " public static void write_non_chained(int code");
vector<java_type_t> signature = signatureInfoMapIt->first; vector<java_type_t> signature = signatureInfoMapIt->first;
int argIndex = 1; int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(stderr, "Non chained signatures should not have attribution chains.\n"); fprintf(stderr, "Non chained signatures should not have attribution chains.\n");
return 1; return 1;
@@ -337,8 +332,8 @@ int write_java_non_chained_methods(
fprintf(out, " write(code"); fprintf(out, " write(code");
argIndex = 1; argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
// First two args are uid and tag of attribution chain. // First two args are uid and tag of attribution chain.
if (argIndex == 1) { if (argIndex == 1) {
fprintf(out, ", new int[] {arg%d}", argIndex); fprintf(out, ", new int[] {arg%d}", argIndex);
@@ -357,23 +352,24 @@ int write_java_non_chained_methods(
} }
int write_java_work_source_methods( int write_java_work_source_methods(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
fprintf(out, " // WorkSource methods.\n"); fprintf(out, " // WorkSource methods.\n");
for (auto signatureInfoMapIt = signatureInfoMap.begin(); for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) { signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first; vector<java_type_t> signature = signatureInfoMapIt->first;
// Determine if there is Attribution in this signature. // Determine if there is Attribution in this signature.
int attributionArg = -1; int attributionArg = -1;
int argIndexMax = 0; int argIndexMax = 0;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
argIndexMax++; argIndexMax++;
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
if (attributionArg > -1) { if (attributionArg > -1) {
fprintf(stderr, "An atom contains multiple AttributionNode fields.\n"); fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n"); fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n"); fprintf(out,
"\n// Invalid for WorkSource: more than one attribution "
"chain.\n");
return 1; return 1;
} }
attributionArg = argIndexMax; attributionArg = argIndexMax;
@@ -387,8 +383,8 @@ int write_java_work_source_methods(
// Method header (signature) // Method header (signature)
fprintf(out, " public static void write(int code"); fprintf(out, " public static void write(int code");
int argIndex = 1; int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg != signature.end(); arg++) { arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", android.os.WorkSource ws"); fprintf(out, ", android.os.WorkSource ws");
} else { } else {
@@ -398,36 +394,40 @@ int write_java_work_source_methods(
} }
fprintf(out, ") {\n"); fprintf(out, ") {\n");
// write_non_chained() component. TODO: Remove when flat uids are no longer needed. // write_non_chained() component. TODO: Remove when flat uids are no longer
// needed.
fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n"); fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
fprintf(out, " write_non_chained(code"); fprintf(out, " write_non_chained(code");
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
if (argIndex == attributionArg) { if (argIndex == attributionArg) {
fprintf(out, ", ws.getUid(i), ws.getPackageName(i)"); fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
} else { } else {
fprintf(out, ", arg%d", argIndex); fprintf(out, ", arg%d", argIndex);
} }
} }
fprintf(out, ");\n"); fprintf(out, ");\n");
fprintf(out, " }\n"); // close for-loop fprintf(out, " }\n"); // close for-loop
// write() component. // write() component.
fprintf(out, " java.util.List<android.os.WorkSource.WorkChain> workChains = " fprintf(out,
" java.util.List<android.os.WorkSource.WorkChain> workChains = "
"ws.getWorkChains();\n"); "ws.getWorkChains();\n");
fprintf(out, " if (workChains != null) {\n"); fprintf(out, " if (workChains != null) {\n");
fprintf(out, " for (android.os.WorkSource.WorkChain wc : workChains) {\n"); fprintf(out,
" for (android.os.WorkSource.WorkChain wc : workChains) "
"{\n");
fprintf(out, " write(code"); fprintf(out, " write(code");
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) { for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
if (argIndex == attributionArg) { if (argIndex == attributionArg) {
fprintf(out, ", wc.getUids(), wc.getTags()"); fprintf(out, ", wc.getUids(), wc.getTags()");
} else { } else {
fprintf(out, ", arg%d", argIndex); fprintf(out, ", arg%d", argIndex);
} }
} }
fprintf(out, ");\n"); fprintf(out, ");\n");
fprintf(out, " }\n"); // close for-loop fprintf(out, " }\n"); // close for-loop
fprintf(out, " }\n"); // close if fprintf(out, " }\n"); // close if
fprintf(out, " }\n"); // close method fprintf(out, " }\n"); // close method
} }
return 0; return 0;
} }

View File

@@ -16,14 +16,14 @@
#pragma once #pragma once
#include "Collation.h" #include <stdio.h>
#include <string.h>
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <stdio.h> #include "Collation.h"
#include <string.h>
namespace android { namespace android {
namespace stats_log_api_gen { namespace stats_log_api_gen {
@@ -52,11 +52,12 @@ void write_closing_namespace(FILE* out, const string& cppNamespaces);
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl); void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
void write_native_method_signature(FILE* out, const string& methodName, void write_native_method_signature(FILE* out, const string& methodName,
const vector<java_type_t>& signature, const AtomDecl& attributionDecl, const vector<java_type_t>& signature,
const string& closer); const AtomDecl& attributionDecl, const string& closer);
void write_native_method_call(FILE* out, const string& methodName, void write_native_method_call(FILE* out, const string& methodName,
const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex = 1); const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
int argIndex = 1);
// Common Java helpers. // Common Java helpers.
void write_java_atom_codes(FILE* out, const Atoms& atoms); void write_java_atom_codes(FILE* out, const Atoms& atoms);
@@ -64,14 +65,13 @@ void write_java_atom_codes(FILE* out, const Atoms& atoms);
void write_java_enum_values(FILE* out, const Atoms& atoms); void write_java_enum_values(FILE* out, const Atoms& atoms);
void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name, void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
const AtomDecl& atom); const AtomDecl& atom);
int write_java_non_chained_methods(FILE* out, const map<vector<java_type_t>, int write_java_non_chained_methods(
FieldNumberToAnnotations>& signatureInfoMap); FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
int write_java_work_source_methods( int write_java_work_source_methods(
FILE* out, FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
} // namespace stats_log_api_gen } // namespace stats_log_api_gen
} // namespace android } // namespace android