summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/statsd/src/atoms.proto31
-rw-r--r--tools/stats_log_api_gen/Android.bp1
-rw-r--r--tools/stats_log_api_gen/Collation.cpp270
-rw-r--r--tools/stats_log_api_gen/Collation.h31
-rw-r--r--tools/stats_log_api_gen/main.cpp307
-rw-r--r--tools/stats_log_api_gen/test.proto44
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp53
7 files changed, 478 insertions, 259 deletions
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 716fee6bb1fb..617919d7b69c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -97,19 +97,29 @@ message Atom {
CpuTimePerUidFreqPulled cpu_time_per_uid_freq_pulled = 1010;
WifiActivityEnergyInfoPulled wifi_activity_energy_info_pulled = 1011;
ModemActivityInfoPulled modem_activity_info_pulled = 1012;
+ AttributionChainDummyAtom attribution_chain_dummy_atom = 10000;
}
}
/**
- * A WorkSource represents the chained attribution of applications that
+ * An attribution represents an application or module that is part of process where a particular bit
+ * of work is done.
+ */
+message Attribution {
+ // The uid for an application or module.
+ optional int32 uid = 1;
+ // The string tag for the attribution node.
+ optional string tag = 2;
+}
+
+/**
+ * An attribution chain represents the chained attributions of applications or modules that
* resulted in a particular bit of work being done.
+ * The ordering of the attributions is that of calls, that is uid = [A, B, C] if A calls B that
+ * calls C.
*/
-message WorkSource {
- // The uid for a given element in the attribution chain.
- repeated int32 uid = 1;
- // The (optional) string tag for an element in the attribution chain. If the
- // element has no tag, it is encoded as an empty string.
- repeated string tag = 2;
+message AttributionChain {
+ repeated Attribution attribution = 1;
}
/*
@@ -127,7 +137,7 @@ message WorkSource {
* - The CamelCase name of the message type should match the
* underscore_separated name as defined in Atom.
* - If an atom represents work that can be attributed to an app, there can
- * be exactly one WorkSource field. It must be field number 1.
+ * be exactly one AttributionChain field. It must be field number 1.
* - A field that is a uid should be a string field, tagged with the [xxx]
* annotation. The generated code on android will be represented by UIDs,
* and those UIDs will be translated in xxx to those strings.
@@ -138,6 +148,11 @@ message WorkSource {
* *****************************************************************************
*/
+message AttributionChainDummyAtom {
+ optional AttributionChain attribution_chain = 1;
+ optional int32 value = 2;
+}
+
/**
* Logs when the screen state changes.
*
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 468864b49d3f..e301eb140fc9 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -97,6 +97,7 @@ cc_library_shared {
cflags: [
"-Wall",
"-Werror",
+ "-fexceptions",
],
export_generated_headers: ["statslog.h"],
shared_libs: [
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index f76196dd2a19..a25784debf12 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -111,8 +111,9 @@ java_type(const FieldDescriptor* field)
return JAVA_TYPE_UNKNOWN;
case FieldDescriptor::TYPE_MESSAGE:
// TODO: not the final package name
- if (field->message_type()->full_name() == "android.os.statsd.WorkSource") {
- return JAVA_TYPE_WORK_SOURCE;
+ if (field->message_type()->full_name() ==
+ "android.os.statsd.AttributionChain") {
+ return JAVA_TYPE_ATTRIBUTION_CHAIN;
} else {
return JAVA_TYPE_OBJECT;
}
@@ -136,138 +137,153 @@ java_type(const FieldDescriptor* field)
}
/**
+ * 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;
+
+ 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) {
+ // Allow attribution chain, but only at position 1.
+ print_error(field, "Message type not allowed for field: %s\n",
+ field->name().c_str());
+ errorCount++;
+ continue;
+ } else if (javaType == JAVA_TYPE_BYTE_ARRAY) {
+ print_error(field, "Raw bytes type not allowed for field: %s\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);
+
+ AtomField atField(field->name(), javaType);
+ if (javaType == JAVA_TYPE_ENUM) {
+ // All enums are treated as ints when it comes to function signatures.
+ signature->push_back(JAVA_TYPE_INT);
+ const EnumDescriptor *enumDescriptor = field->enum_type();
+ for (int i = 0; i < enumDescriptor->value_count(); i++) {
+ atField.enumValues[enumDescriptor->value(i)->number()] =
+ enumDescriptor->value(i)->name().c_str();
+ }
+ } else {
+ signature->push_back(javaType);
+ }
+ atomDecl->fields.push_back(atField);
+ }
+
+ return errorCount;
+}
+
+/**
* Gather the info about the atoms.
*/
-int
-collate_atoms(const Descriptor* descriptor, Atoms* atoms)
-{
- int errorCount = 0;
- const bool dbg = false;
-
- for (int i=0; i<descriptor->field_count(); i++) {
- const FieldDescriptor* atomField = descriptor->field(i);
-
- if (dbg) {
- printf(" %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;
- }
-
- const Descriptor* atom = atomField->message_type();
-
- // 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;
-
- 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) {
- // Allow WorkSources, but only at position 1.
- print_error(field, "Message type not allowed for field: %s\n",
- field->name().c_str());
- errorCount++;
- continue;
- } else if (javaType == JAVA_TYPE_BYTE_ARRAY) {
- print_error(field, "Raw bytes type not allowed for field: %s\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
- }
-
- // Check that if there's a WorkSource, 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_WORK_SOURCE) {
- print_error(field, "WorkSource fields must have field id 1, in message: '%s'\n",
- atom->name().c_str());
- errorCount++;
- }
- }
- }
-
- AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
-
- // Build the type signature and the atom data.
- vector<java_type_t> signature;
- 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);
-
- AtomField atField(field->name(), javaType);
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- signature.push_back(JAVA_TYPE_INT);
- const EnumDescriptor* enumDescriptor = field->enum_type();
- for (int i = 0; i < enumDescriptor->value_count(); i++) {
- atField.enumValues[enumDescriptor->value(i)->number()] =
- enumDescriptor->value(i)->name().c_str();
- }
- } else {
- signature.push_back(javaType);
- }
- atomDecl.fields.push_back(atField);
- }
+int collate_atoms(const Descriptor *descriptor, Atoms *atoms) {
+ int errorCount = 0;
+ const bool dbg = false;
- atoms->signatures.insert(signature);
- atoms->decls.insert(atomDecl);
- }
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ const FieldDescriptor *atomField = descriptor->field(i);
if (dbg) {
- printf("signatures = [\n");
- for (set<vector<java_type_t>>::const_iterator it = atoms->signatures.begin();
- it != atoms->signatures.end(); it++) {
- printf(" ");
- for (vector<java_type_t>::const_iterator jt = it->begin(); jt != it->end(); jt++) {
- printf(" %d", (int)*jt);
- }
- printf("\n");
- }
- printf("]\n");
+ printf(" %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;
+ }
+
+ const Descriptor *atom = atomField->message_type();
+ AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
+ vector<java_type_t> signature;
+ errorCount += collate_atom(atom, &atomDecl, &signature);
+ atoms->signatures.insert(signature);
+ atoms->decls.insert(atomDecl);
+ }
+
+ if (dbg) {
+ printf("signatures = [\n");
+ for (set<vector<java_type_t>>::const_iterator it =
+ atoms->signatures.begin();
+ it != atoms->signatures.end(); it++) {
+ printf(" ");
+ for (vector<java_type_t>::const_iterator jt = it->begin();
+ jt != it->end(); jt++) {
+ printf(" %d", (int)*jt);
+ }
+ printf("\n");
}
+ printf("]\n");
+ }
- return errorCount;
+ return errorCount;
}
} // namespace stats_log_api_gen
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 2f840d7f4469..cd0625c3a61d 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -37,22 +37,21 @@ using google::protobuf::Descriptor;
* The types for atom parameters.
*/
typedef enum {
- JAVA_TYPE_UNKNOWN = 0,
-
- JAVA_TYPE_WORK_SOURCE = 1,
- JAVA_TYPE_BOOLEAN = 2,
- JAVA_TYPE_INT = 3,
- JAVA_TYPE_LONG = 4,
- JAVA_TYPE_FLOAT = 5,
- JAVA_TYPE_DOUBLE = 6,
- JAVA_TYPE_STRING = 7,
- JAVA_TYPE_ENUM = 8,
-
- JAVA_TYPE_OBJECT = -1,
- JAVA_TYPE_BYTE_ARRAY = -2,
+ JAVA_TYPE_UNKNOWN = 0,
+
+ JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
+ JAVA_TYPE_BOOLEAN = 2,
+ JAVA_TYPE_INT = 3,
+ JAVA_TYPE_LONG = 4,
+ JAVA_TYPE_FLOAT = 5,
+ JAVA_TYPE_DOUBLE = 6,
+ JAVA_TYPE_STRING = 7,
+ JAVA_TYPE_ENUM = 8,
+
+ JAVA_TYPE_OBJECT = -1,
+ JAVA_TYPE_BYTE_ARRAY = -2,
} java_type_t;
-
/**
* The name and type for an atom field.
*/
@@ -100,9 +99,11 @@ struct Atoms {
* Gather the information about the atoms. Returns the number of errors.
*/
int collate_atoms(const Descriptor* descriptor, Atoms* atoms);
+int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
+ vector<java_type_t> *signature);
} // namespace stats_log_api_gen
} // namespace android
-#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
+#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H \ No newline at end of file
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 423d0285e96f..8183a3fbe15d 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -24,8 +24,6 @@ int maxPushedAtomId = 2;
using android::os::statsd::Atom;
-// TODO: Support WorkSources
-
/**
* Turn lower and camel case into upper case with underscores.
*/
@@ -97,13 +95,13 @@ java_type_name(java_type_t type)
}
}
-static int
-write_stats_log_cpp(FILE* out, const Atoms& atoms)
-{
+static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
+ const AtomDecl &attributionDecl) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
+ fprintf(out, "#include <exception>\n");
fprintf(out, "#include <log/log_event_list.h>\n");
fprintf(out, "#include <log/log.h>\n");
fprintf(out, "#include <statslog.h>\n");
@@ -117,15 +115,29 @@ write_stats_log_cpp(FILE* out, const Atoms& atoms)
// Print write methods
fprintf(out, "\n");
for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
- signature != atoms.signatures.end(); signature++) {
+ signature != atoms.signatures.end(); signature++) {
int argIndex;
fprintf(out, "void\n");
fprintf(out, "stats_write(int32_t code");
argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+ arg != signature->end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", const std::vector<%s>& %s",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str());
+ } else {
+ fprintf(out, ", const %s* %s, size_t %s_length",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str(), chainField.name.c_str());
+ }
+ }
+ } else {
+ fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+ }
argIndex++;
}
fprintf(out, ")\n");
@@ -133,15 +145,40 @@ write_stats_log_cpp(FILE* out, const Atoms& atoms)
fprintf(out, "{\n");
argIndex = 1;
fprintf(out, " android_log_event_list event(kStatsEventTag);\n");
- fprintf(out, " event << code;\n");
+ fprintf(out, " event << code;\n\n");
for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
- if (*arg == JAVA_TYPE_STRING) {
- fprintf(out, " if (arg%d == NULL) {\n", argIndex);
- fprintf(out, " arg%d = \"\";\n", argIndex);
+ arg != signature->end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (const auto &chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, " if (%s_length != %s.size()) {\n",
+ attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
+ fprintf(out, " throw std::invalid_argument(\"attribution fields with"
+ " diff length: %s vs %s\");\n",
+ attributionDecl.fields.front().name.c_str(),
+ chainField.name.c_str());
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+ }
+ }
+ fprintf(out, "\n event.begin();\n");
+ fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
+ attributionDecl.fields.front().name.c_str());
+ fprintf(out, " event.begin();\n");
+ for (const auto &chainField : attributionDecl.fields) {
+ fprintf(out, " event << %s[i];\n", chainField.name.c_str());
+ }
+ fprintf(out, " event.end();\n");
fprintf(out, " }\n");
+ fprintf(out, " event.end();\n\n");
+ } else {
+ if (*arg == JAVA_TYPE_STRING) {
+ fprintf(out, " if (arg%d == NULL) {\n", argIndex);
+ fprintf(out, " arg%d = \"\";\n", argIndex);
+ fprintf(out, " }\n");
+ }
+ fprintf(out, " event << arg%d;\n", argIndex);
}
- fprintf(out, " event << arg%d;\n", argIndex);
argIndex++;
}
@@ -160,7 +197,7 @@ write_stats_log_cpp(FILE* out, const Atoms& atoms)
static int
-write_stats_log_header(FILE* out, const Atoms& atoms)
+write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
{
// Print prelude
fprintf(out, "// This file is autogenerated\n");
@@ -168,6 +205,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
fprintf(out, "#pragma once\n");
fprintf(out, "\n");
fprintf(out, "#include <stdint.h>\n");
+ fprintf(out, "#include <vector>\n");
fprintf(out, "\n");
fprintf(out, "namespace android {\n");
@@ -185,7 +223,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
size_t i = 0;
// Print constants
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ atom != atoms.decls.end(); atom++) {
string constant = make_constant_name(atom->name);
fprintf(out, "\n");
fprintf(out, " /**\n");
@@ -193,7 +231,21 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
fprintf(out, " * Usage: stats_write(StatsLog.%s", constant.c_str());
for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) {
- fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
+ if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", const std::vector<%s>& %s",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str());
+ } else {
+ fprintf(out, ", const %s* %s, size_t %s_length",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str(), chainField.name.c_str());
+ }
+ }
+ } else {
+ fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
+ }
}
fprintf(out, ");\n");
fprintf(out, " */\n");
@@ -208,8 +260,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
fprintf(out, "};\n");
fprintf(out, "\n");
- fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
- maxPushedAtomId);
+ fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", maxPushedAtomId);
// Print write methods
fprintf(out, "//\n");
@@ -220,8 +271,21 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
fprintf(out, "void stats_write(int32_t code ");
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+ arg != signature->end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", const std::vector<%s>& %s",
+ cpp_type_name(chainField.javaType), chainField.name.c_str());
+ } else {
+ fprintf(out, ", const %s* %s, size_t %s_length",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str(), chainField.name.c_str());
+ }
+ }
+ } else {
+ fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+ }
argIndex++;
}
fprintf(out, ");\n");
@@ -235,7 +299,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms)
}
static int
-write_stats_log_java(FILE* out, const Atoms& atoms)
+write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
{
// Print prelude
fprintf(out, "// This file is autogenerated\n");
@@ -259,8 +323,15 @@ write_stats_log_java(FILE* out, const Atoms& atoms)
fprintf(out, " * %s %s\n", atom->message.c_str(), atom->name.c_str());
fprintf(out, " * Usage: StatsLog.write(StatsLog.%s", constant.c_str());
for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s[] %s",
+ java_type_name(chainField.javaType), chainField.name.c_str());
+ }
+ } else {
+ fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
+ }
}
fprintf(out, ");\n");
fprintf(out, " */\n");
@@ -271,33 +342,41 @@ write_stats_log_java(FILE* out, const Atoms& atoms)
// Print constants for the enum values.
fprintf(out, " // Constants for enum values.\n\n");
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
+ atom != atoms.decls.end(); atom++) {
for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ENUM) {
- fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
- for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
- fprintf(out, " public static final int %s__%s__%s = %d;\n",
- make_constant_name(atom->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(),
- value->first);
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ENUM) {
+ fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
+ field->name.c_str());
+ for (map<int, string>::const_iterator value = field->enumValues.begin();
+ value != field->enumValues.end(); value++) {
+ fprintf(out, " public static final int %s__%s__%s = %d;\n",
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(),
+ value->first);
+ }
+ fprintf(out, "\n");
}
- fprintf(out, "\n");
- }
}
}
// Print write methods
fprintf(out, " // Write methods\n");
for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
- signature != atoms.signatures.end(); signature++) {
+ signature != atoms.signatures.end(); signature++) {
fprintf(out, " public static native void write(int code");
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+ arg != signature->end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s[] %s",
+ java_type_name(chainField.javaType), chainField.name.c_str());
+ }
+ } else {
+ fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+ }
argIndex++;
}
fprintf(out, ");\n");
@@ -330,12 +409,25 @@ jni_type_name(java_type_t type)
}
}
+static const char*
+jni_array_type_name(java_type_t type)
+{
+ switch (type) {
+ case JAVA_TYPE_INT:
+ return "jintArray";
+ case JAVA_TYPE_STRING:
+ return "jobjectArray";
+ default:
+ return "UNKNOWN";
+ }
+}
+
static string
jni_function_name(const vector<java_type_t>& signature)
{
string result("StatsLog_write");
for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
+ arg != signature.end(); arg++) {
switch (*arg) {
case JAVA_TYPE_BOOLEAN:
result += "_boolean";
@@ -356,6 +448,9 @@ jni_function_name(const vector<java_type_t>& signature)
case JAVA_TYPE_STRING:
result += "_String";
break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN:
+ result += "_AttributionChain";
+ break;
default:
result += "_UNKNOWN";
break;
@@ -387,19 +482,26 @@ java_type_signature(java_type_t type)
}
static string
-jni_function_signature(const vector<java_type_t>& signature)
+jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &attributionDecl)
{
string result("(I");
for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- result += java_type_signature(*arg);
+ arg != signature.end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ result += "[";
+ result += java_type_signature(chainField.javaType);
+ }
+ } else {
+ result += java_type_signature(*arg);
+ }
}
result += ")V";
return result;
}
static int
-write_stats_log_jni(FILE* out, const Atoms& atoms)
+write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
{
// Print prelude
fprintf(out, "// This file is autogenerated\n");
@@ -408,6 +510,8 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
fprintf(out, "#include <statslog.h>\n");
fprintf(out, "\n");
fprintf(out, "#include <nativehelper/JNIHelp.h>\n");
+ fprintf(out, "#include <nativehelper/ScopedUtfChars.h>\n");
+ fprintf(out, "#include <utils/Vector.h>\n");
fprintf(out, "#include \"core_jni_helpers.h\"\n");
fprintf(out, "#include \"jni.h\"\n");
fprintf(out, "\n");
@@ -419,7 +523,7 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
// Print write methods
for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
- signature != atoms.signatures.end(); signature++) {
+ signature != atoms.signatures.end(); signature++) {
int argIndex;
fprintf(out, "static void\n");
@@ -428,7 +532,14 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
- fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
+ chainField.name.c_str());
+ }
+ } else {
+ fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
+ }
argIndex++;
}
fprintf(out, ")\n");
@@ -437,10 +548,11 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
// Prepare strings
argIndex = 1;
- bool hadString = false;
+ bool hadStringOrChain = false;
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
if (*arg == JAVA_TYPE_STRING) {
+ hadStringOrChain = true;
fprintf(out, " const char* str%d;\n", argIndex);
fprintf(out, " if (arg%d != NULL) {\n", argIndex);
fprintf(out, " str%d = env->GetStringUTFChars(arg%d, NULL);\n",
@@ -448,13 +560,52 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
fprintf(out, " } else {\n");
fprintf(out, " str%d = NULL;\n", argIndex);
fprintf(out, " }\n");
- hadString = true;
+ } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ hadStringOrChain = true;
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, " size_t %s_length = env->GetArrayLength(%s);\n",
+ chainField.name.c_str(), chainField.name.c_str());
+ if (chainField.name != attributionDecl.fields.front().name) {
+ fprintf(out, " if (%s_length != %s_length) {\n",
+ chainField.name.c_str(),
+ attributionDecl.fields.front().name.c_str());
+ fprintf(out, " jniThrowException(env, "
+ "\"java/lang/IllegalArgumentException\", "
+ "\"invalid attribution field(%s) length.\");\n",
+ chainField.name.c_str());
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+ }
+ if (chainField.javaType == JAVA_TYPE_INT) {
+ fprintf(out, " jint* %s_array = env->GetIntArrayElements(%s, NULL);\n",
+ chainField.name.c_str(), chainField.name.c_str());
+ } else if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, " std::vector<%s> %s_vec;\n",
+ cpp_type_name(chainField.javaType), chainField.name.c_str());
+ fprintf(out, " std::vector<ScopedUtfChars*> scoped_%s_vec;\n",
+ chainField.name.c_str());
+ fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
+ chainField.name.c_str());
+ fprintf(out, " jstring jstr = "
+ "(jstring)env->GetObjectArrayElement(%s, i);\n",
+ chainField.name.c_str());
+ fprintf(out, " ScopedUtfChars* scoped_%s = "
+ "new ScopedUtfChars(env, jstr);\n",
+ chainField.name.c_str());
+ fprintf(out, " %s_vec.push_back(scoped_%s->c_str());\n",
+ chainField.name.c_str(), chainField.name.c_str());
+ fprintf(out, " scoped_%s_vec.push_back(scoped_%s);\n",
+ chainField.name.c_str(), chainField.name.c_str());
+ fprintf(out, " }\n");
+ }
+ fprintf(out, "\n");
+ }
}
argIndex++;
}
-
- // Emit this to quiet the unused parameter warning if there were no strings.
- if (!hadString) {
+ // Emit this to quiet the unused parameter warning if there were no strings or attribution
+ // chains.
+ if (!hadStringOrChain) {
fprintf(out, " (void)env;\n");
}
@@ -463,11 +614,24 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
fprintf(out, " android::util::stats_write(code");
for (vector<java_type_t>::const_iterator arg = signature->begin();
arg != signature->end(); arg++) {
- const char* argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
- fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_INT) {
+ fprintf(out, ", (const %s*)%s_array, %s_length",
+ cpp_type_name(chainField.javaType),
+ chainField.name.c_str(), chainField.name.c_str());
+ } else if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, ", %s_vec", chainField.name.c_str());
+ }
+ }
+ } else {
+ const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
+ fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
+ }
argIndex++;
}
fprintf(out, ");\n");
+ fprintf(out, "\n");
// Clean up strings
argIndex = 1;
@@ -478,6 +642,18 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
argIndex, argIndex);
fprintf(out, " }\n");
+ } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ if (chainField.javaType == JAVA_TYPE_INT) {
+ fprintf(out, " env->ReleaseIntArrayElements(%s, %s_array, 0);\n",
+ chainField.name.c_str(), chainField.name.c_str());
+ } else if (chainField.javaType == JAVA_TYPE_STRING) {
+ fprintf(out, " for (size_t i = 0; i < %s_length; ++i) {\n",
+ chainField.name.c_str());
+ fprintf(out, " delete scoped_%s_vec[i];\n", chainField.name.c_str());
+ fprintf(out, " }\n");
+ }
+ }
}
argIndex++;
}
@@ -494,8 +670,8 @@ write_stats_log_jni(FILE* out, const Atoms& atoms)
for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
signature != atoms.signatures.end(); signature++) {
fprintf(out, " { \"write\", \"%s\", (void*)%s },\n",
- jni_function_signature(*signature).c_str(),
- jni_function_name(*signature).c_str());
+ jni_function_signature(*signature, attributionDecl).c_str(),
+ jni_function_name(*signature).c_str());
}
fprintf(out, "};\n");
fprintf(out, "\n");
@@ -591,6 +767,11 @@ run(int argc, char const*const* argv)
return 1;
}
+ AtomDecl attributionDecl;
+ vector<java_type_t> attributionSignature;
+ collate_atom(android::os::statsd::Attribution::descriptor(),
+ &attributionDecl, &attributionSignature);
+
// Write the .cpp file
if (cppFilename.size() != 0) {
FILE* out = fopen(cppFilename.c_str(), "w");
@@ -598,7 +779,8 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
return 1;
}
- errorCount = android::stats_log_api_gen::write_stats_log_cpp(out, atoms);
+ errorCount = android::stats_log_api_gen::write_stats_log_cpp(
+ out, atoms, attributionDecl);
fclose(out);
}
@@ -609,7 +791,8 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
return 1;
}
- errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms);
+ errorCount = android::stats_log_api_gen::write_stats_log_header(
+ out, atoms, attributionDecl);
fclose(out);
}
@@ -620,7 +803,8 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
return 1;
}
- errorCount = android::stats_log_api_gen::write_stats_log_java(out, atoms);
+ errorCount = android::stats_log_api_gen::write_stats_log_java(
+ out, atoms, attributionDecl);
fclose(out);
}
@@ -631,7 +815,8 @@ run(int argc, char const*const* argv)
fprintf(stderr, "Unable to open file for write: %s\n", jniFilename.c_str());
return 1;
}
- errorCount = android::stats_log_api_gen::write_stats_log_jni(out, atoms);
+ errorCount = android::stats_log_api_gen::write_stats_log_jni(
+ out, atoms, attributionDecl);
fclose(out);
}
@@ -650,4 +835,4 @@ main(int argc, char const*const* argv)
GOOGLE_PROTOBUF_VERIFY_VERSION;
return android::stats_log_api_gen::run(argc, argv);
-}
+} \ No newline at end of file
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 66861588a008..84b22cdaf522 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -39,22 +39,22 @@ enum AnEnum {
}
message AllTypesAtom {
- optional android.os.statsd.WorkSource attribution = 1;
- optional double double_field = 2;
- optional float float_field = 3;
- optional int64 int64_field = 4;
- optional uint64 uint64_field = 5;
- optional int32 int32_field = 6;
- optional fixed64 fixed64_field = 7;
- optional fixed32 fixed32_field = 8;
- optional bool bool_field = 9;
- optional string string_field = 10;
- optional uint32 uint32_field = 11;
- optional AnEnum enum_field = 12;
- optional sfixed32 sfixed32_field = 13;
- optional sfixed64 sfixed64_field = 14;
- optional sint32 sint32_field = 15;
- optional sint64 sint64_field = 16;
+ optional android.os.statsd.AttributionChain attribution_chain = 1;
+ optional double double_field = 2;
+ optional float float_field = 3;
+ optional int64 int64_field = 4;
+ optional uint64 uint64_field = 5;
+ optional int32 int32_field = 6;
+ optional fixed64 fixed64_field = 7;
+ optional fixed32 fixed32_field = 8;
+ optional bool bool_field = 9;
+ optional string string_field = 10;
+ optional uint32 uint32_field = 11;
+ optional AnEnum enum_field = 12;
+ optional sfixed32 sfixed32_field = 13;
+ optional sfixed64 sfixed64_field = 14;
+ optional sint32 sint32_field = 15;
+ optional sint64 sint64_field = 16;
}
message Event {
@@ -99,14 +99,12 @@ message BadSkippedFieldMultiple {
}
}
-message BadWorkSourcePositionAtom {
- optional int32 field1 = 1;
- optional android.os.statsd.WorkSource attribution = 2;
+message BadAttributionChainPositionAtom {
+ optional int32 field1 = 1;
+ optional android.os.statsd.AttributionChain attribution = 2;
}
-message BadWorkSourcePosition {
- oneof event {
- BadWorkSourcePositionAtom bad = 1;
- }
+message BadAttributionChainPosition {
+ oneof event { BadAttributionChainPositionAtom bad = 1; }
}
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 073f2cfce6a8..b2b7298d86c7 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -64,7 +64,7 @@ set_contains_vector(const set<vector<java_type_t>>& s, int count, ...)
} \
} 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) \
do { \
for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
@@ -95,24 +95,25 @@ TEST(CollationTest, CollateStats) {
EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
// AllTypesAtom
- EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures,
- JAVA_TYPE_WORK_SOURCE, // WorkSource
- JAVA_TYPE_DOUBLE, // double
- JAVA_TYPE_FLOAT, // float
- JAVA_TYPE_LONG, // int64
- JAVA_TYPE_LONG, // uint64
- JAVA_TYPE_INT, // int32
- JAVA_TYPE_LONG, // fixed64
- JAVA_TYPE_INT, // fixed32
- JAVA_TYPE_BOOLEAN, // bool
- JAVA_TYPE_STRING, // string
- JAVA_TYPE_INT, // uint32
- JAVA_TYPE_INT, // AnEnum
- JAVA_TYPE_INT, // sfixed32
- JAVA_TYPE_LONG, // sfixed64
- JAVA_TYPE_INT, // sint32
- JAVA_TYPE_LONG // sint64
- );
+ EXPECT_SET_CONTAINS_SIGNATURE(
+ atoms.signatures,
+ JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
+ JAVA_TYPE_DOUBLE, // double
+ JAVA_TYPE_FLOAT, // float
+ JAVA_TYPE_LONG, // int64
+ JAVA_TYPE_LONG, // uint64
+ JAVA_TYPE_INT, // int32
+ JAVA_TYPE_LONG, // fixed64
+ JAVA_TYPE_INT, // fixed32
+ JAVA_TYPE_BOOLEAN, // bool
+ JAVA_TYPE_STRING, // string
+ JAVA_TYPE_INT, // uint32
+ JAVA_TYPE_INT, // AnEnum
+ JAVA_TYPE_INT, // sfixed32
+ JAVA_TYPE_LONG, // sfixed64
+ JAVA_TYPE_INT, // sint32
+ JAVA_TYPE_LONG // sint64
+ );
set<AtomDecl>::const_iterator atom = atoms.decls.begin();
EXPECT_EQ(1, atom->code);
@@ -187,14 +188,16 @@ TEST(CollationTest, FailOnSkippedFieldsMultiple) {
}
/**
- * Test that atoms that have a WorkSource not in the first position are rejected.
+ * Test that atoms that have an attribution chain not in the first position are
+ * rejected.
*/
-TEST(CollationTest, FailBadWorkSourcePosition) {
- Atoms atoms;
- int errorCount = collate_atoms(BadWorkSourcePosition::descriptor(), &atoms);
+TEST(CollationTest, FailBadAttributionChainPosition) {
+ Atoms atoms;
+ int errorCount =
+ collate_atoms(BadAttributionChainPosition::descriptor(), &atoms);
- EXPECT_EQ(1, errorCount);
+ EXPECT_EQ(1, errorCount);
}
} // namespace stats_log_api_gen
-} // namespace android
+} // namespace android \ No newline at end of file