diff options
| -rw-r--r-- | cmds/statsd/src/atoms.proto | 31 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/Android.bp | 1 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/Collation.cpp | 270 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/Collation.h | 31 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/main.cpp | 307 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/test.proto | 44 | ||||
| -rw-r--r-- | tools/stats_log_api_gen/test_collation.cpp | 53 |
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 |