From 8b71c74894462fc68f2ebe551b82615d0cd67184 Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Wed, 24 Oct 2018 12:15:56 -0700 Subject: Allow atoms to log fields in bytes format. There are an increasing number of requests to log data in complex format to statsd, while the data is not expected to be parsed or aggregated by statsd and only to be uploaded as events. Instead of making an exception for each of these cases in a hard coded way, this CL add a feature to annotate these field in atoms.proto and the stats-log-api-gen tool will produce byte array interfaces for them. Note that log_msg does not have byte array type, and only has string type, when statsd receives the log, these fields are in string type. Only when the atom is written to proto, we will check if this field should be bytes field and write it to protobuf in message format. Change-Id: If53dd95c5826710c76d7fe982bf951a435dfc738 Merged-In: If53dd95c5826710c76d7fe982bf951a435dfc738 Fix: 118386797 Bug: 120635548 Test: unit test & manual test (cherry picked from commit bbdd67d19f4912fbec00220b22e44c68eff5ab3f) --- cmds/statsd/src/atom_field_options.proto | 12 +++++ cmds/statsd/src/stats_log_util.cpp | 40 ++++++++++++---- tools/stats_log_api_gen/Collation.cpp | 25 +++++++++- tools/stats_log_api_gen/Collation.h | 2 + tools/stats_log_api_gen/main.cpp | 76 +++++++++++++++++++++++++++++- tools/stats_log_api_gen/test.proto | 22 +++++++++ tools/stats_log_api_gen/test_collation.cpp | 14 ++++++ 7 files changed, 179 insertions(+), 12 deletions(-) diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto index a2a03b14c073..7dfe7d6ecb7e 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -64,10 +64,22 @@ message StateAtomFieldOption { optional StateField option = 1 [default = STATE_FIELD_UNSET]; } +// Used to generate StatsLog.write APIs. +enum LogMode { + MODE_UNSET = 0; + // Log fields as their actual types e.g., all primary data types. + // Or fields that are hardcoded in stats_log_api_gen tool e.g., AttributionNode + MODE_AUTOMATIC = 1; + // Log fields in their proto binary format. These fields will not be parsed in statsd + MODE_BYTES = 2; +} + extend google.protobuf.FieldOptions { // Flags to decorate an atom that presents a state change. optional StateAtomFieldOption stateFieldOption = 50000; // Flags to decorate the uid fields in an atom. optional bool is_uid = 50001 [default = false]; + + optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC]; } \ No newline at end of file diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index a0ab3e46e719..444e5b7c3dbb 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -25,15 +25,16 @@ #include #include +using android::util::AtomsInfo; using android::util::FIELD_COUNT_REPEATED; using android::util::FIELD_TYPE_BOOL; +using android::util::FIELD_TYPE_FIXED64; using android::util::FIELD_TYPE_FLOAT; using android::util::FIELD_TYPE_INT32; using android::util::FIELD_TYPE_INT64; -using android::util::FIELD_TYPE_UINT64; -using android::util::FIELD_TYPE_FIXED64; using android::util::FIELD_TYPE_MESSAGE; using android::util::FIELD_TYPE_STRING; +using android::util::FIELD_TYPE_UINT64; using android::util::ProtoOutputStream; namespace android { @@ -294,8 +295,9 @@ void writeDimensionPathToProto(const std::vector& fieldMatchers, // } // // -void writeFieldValueTreeToStreamHelper(const std::vector& dims, size_t* index, - int depth, int prefix, ProtoOutputStream* protoOutput) { +void writeFieldValueTreeToStreamHelper(int tagId, const std::vector& dims, + size_t* index, int depth, int prefix, + ProtoOutputStream* protoOutput) { size_t count = dims.size(); while (*index < count) { const auto& dim = dims[*index]; @@ -319,9 +321,31 @@ void writeFieldValueTreeToStreamHelper(const std::vector& dims, size case FLOAT: protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value); break; - case STRING: - protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value); + case STRING: { + bool isBytesField = false; + // Bytes field is logged via string format in log_msg format. So here we check + // if this string field is a byte field. + std::map>::const_iterator itr; + if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) != + AtomsInfo::kBytesFieldAtoms.end()) { + const std::vector& bytesFields = itr->second; + for (int bytesField : bytesFields) { + if (bytesField == fieldNum) { + // This is a bytes field + isBytesField = true; + break; + } + } + } + if (isBytesField) { + protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum, + (const char*)dim.mValue.str_value.c_str(), + dim.mValue.str_value.length()); + } else { + protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value); + } break; + } default: break; } @@ -337,7 +361,7 @@ void writeFieldValueTreeToStreamHelper(const std::vector& dims, size } // Directly jump to the leaf value because the repeated position field is implied // by the position of the sub msg in the parent field. - writeFieldValueTreeToStreamHelper(dims, index, valueDepth, + writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth, dim.mField.getPrefix(valueDepth), protoOutput); if (msg_token != 0) { protoOutput->end(msg_token); @@ -354,7 +378,7 @@ void writeFieldValueTreeToStream(int tagId, const std::vector& value uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId); size_t index = 0; - writeFieldValueTreeToStreamHelper(values, &index, 0, 0, protoOutput); + writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput); protoOutput->end(atomToken); } diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index ebdcdfdd6c50..61174d99198b 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -47,7 +47,8 @@ AtomDecl::AtomDecl(const AtomDecl& that) fields(that.fields), primaryFields(that.primaryFields), exclusiveField(that.exclusiveField), - uidField(that.uidField) {} + uidField(that.uidField), + binaryFields(that.binaryFields) {} AtomDecl::AtomDecl(int c, const string& n, const string& m) :code(c), @@ -116,6 +117,9 @@ java_type(const FieldDescriptor* field) if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") { return JAVA_TYPE_ATTRIBUTION_CHAIN; + } else if (field->options().GetExtension(os::statsd::log_mode) == + os::statsd::LogMode::MODE_BYTES) { + return JAVA_TYPE_BYTE_ARRAY; } else { return JAVA_TYPE_OBJECT; } @@ -185,6 +189,8 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, for (map::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); @@ -198,12 +204,19 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, field->name().c_str()); errorCount++; continue; - } else if (javaType == JAVA_TYPE_BYTE_ARRAY) { + } 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; + } } // Check that if there's an attribution chain, it's at position 1. @@ -228,12 +241,16 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, 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. signature->push_back(JAVA_TYPE_INT); collate_enums(*field->enum_type(), &atField); + } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) { + signature->push_back(JAVA_TYPE_BYTE_ARRAY); } else { signature->push_back(javaType); } @@ -275,6 +292,10 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, errorCount++; } } + // Binary field validity is already checked above. + if (isBinaryField) { + atomDecl->binaryFields.push_back(it->first); + } } return errorCount; diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index 5d2c30292c9c..a8b270caefaf 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -86,6 +86,8 @@ struct AtomDecl { int uidField = 0; + vector binaryFields; + AtomDecl(); AtomDecl(const AtomDecl& that); AtomDecl(int code, const string& name, const string& message); diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index e519909aa026..597b0556ee63 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -68,6 +68,8 @@ cpp_type_name(java_type_t type) return "double"; case JAVA_TYPE_STRING: return "char const*"; + case JAVA_TYPE_BYTE_ARRAY: + return "char const*"; default: return "UNKNOWN"; } @@ -90,6 +92,8 @@ java_type_name(java_type_t type) return "double"; case JAVA_TYPE_STRING: return "java.lang.String"; + case JAVA_TYPE_BYTE_ARRAY: + return "byte[]"; default: return "UNKNOWN"; } @@ -200,13 +204,40 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, } fprintf(out, " return options;\n"); - fprintf(out, " }\n"); + fprintf(out, "}\n"); fprintf(out, "const std::map " "AtomsInfo::kStateAtomsFieldOptions = " "getStateAtomFieldOptions();\n"); + fprintf(out, + "static std::map> " + "getBinaryFieldAtoms() {\n"); + fprintf(out, " std::map> options;\n"); + for (set::const_iterator atom = atoms.decls.begin(); + atom != atoms.decls.end(); atom++) { + if (atom->binaryFields.size() == 0) { + continue; + } + fprintf(out, + "\n // Adding binary fields for atom " + "(%d)%s\n", + atom->code, atom->name.c_str()); + + for (const auto& field : atom->binaryFields) { + fprintf(out, " options[static_cast(%s)].push_back(%d);\n", + make_constant_name(atom->name).c_str(), field); + } + } + + fprintf(out, " return options;\n"); + fprintf(out, "}\n"); + + fprintf(out, + "const std::map> " + "AtomsInfo::kBytesFieldAtoms = " + "getBinaryFieldAtoms();\n"); fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); @@ -600,6 +631,9 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, " const static std::map " "kStateAtomsFieldOptions;\n"); + fprintf(out, + " const static std::map> " + "kBytesFieldAtoms;"); fprintf(out, "};\n"); fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", @@ -632,6 +666,8 @@ static void write_java_usage(FILE* out, const string& method_name, const string& field != atom.fields.end(); field++) { if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) { fprintf(out, ", android.os.WorkSource workSource"); + } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", byte[] %s", field->name.c_str()); } else { fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str()); } @@ -821,6 +857,8 @@ jni_type_name(java_type_t type) return "jdouble"; case JAVA_TYPE_STRING: return "jstring"; + case JAVA_TYPE_BYTE_ARRAY: + return "jbyteArray"; default: return "UNKNOWN"; } @@ -868,6 +906,9 @@ jni_function_name(const string& method_name, const vector& signatur case JAVA_TYPE_ATTRIBUTION_CHAIN: result += "_AttributionChain"; break; + case JAVA_TYPE_BYTE_ARRAY: + result += "_bytes"; + break; default: result += "_UNKNOWN"; break; @@ -893,6 +934,8 @@ java_type_signature(java_type_t type) return "D"; case JAVA_TYPE_STRING: return "Ljava/lang/String;"; + case JAVA_TYPE_BYTE_ARRAY: + return "[B"; default: return "UNKNOWN"; } @@ -960,6 +1003,25 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp fprintf(out, " } else {\n"); fprintf(out, " str%d = NULL;\n", argIndex); fprintf(out, " }\n"); + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + hadStringOrChain = true; + fprintf(out, " jbyte* jbyte_array%d;\n", argIndex); + fprintf(out, " const char* str%d;\n", argIndex); + fprintf(out, " if (arg%d != NULL) {\n", argIndex); + fprintf(out, + " jbyte_array%d = " + "env->GetByteArrayElements(arg%d, NULL);\n", + argIndex, argIndex); + fprintf(out, + " str%d = " + "reinterpret_cast(env->GetByteArrayElements(arg%" + "d, NULL));\n", + argIndex, argIndex); + fprintf(out, " } else {\n"); + fprintf(out, " jbyte_array%d = NULL;\n", argIndex); + fprintf(out, " str%d = NULL;\n", argIndex); + fprintf(out, " }\n"); + } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { hadStringOrChain = true; for (auto chainField : attributionDecl.fields) { @@ -1026,7 +1088,10 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp } } } else { - const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg"; + const char* argName = (*arg == JAVA_TYPE_STRING || + *arg == JAVA_TYPE_BYTE_ARRAY) + ? "str" + : "arg"; fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex); } argIndex++; @@ -1043,6 +1108,13 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n", argIndex, argIndex); fprintf(out, " }\n"); + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, " if (str%d != NULL) { \n", argIndex); + fprintf(out, + " env->ReleaseByteArrayElements(arg%d, " + "jbyte_array%d, 0);\n", + argIndex, argIndex); + fprintf(out, " }\n"); } else if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_INT) { diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto index 264a865e3b39..188b765e241e 100644 --- a/tools/stats_log_api_gen/test.proto +++ b/tools/stats_log_api_gen/test.proto @@ -109,6 +109,28 @@ message BadAttributionNodePosition { oneof event { BadAttributionNodePositionAtom bad = 1; } } +message GoodEventWithBinaryFieldAtom { + oneof event { GoodBinaryFieldAtom field1 = 1; } +} + +message ComplexField { + optional string str = 1; +} + +message GoodBinaryFieldAtom { + optional int32 field1 = 1; + optional ComplexField bf = 2 [(android.os.statsd.log_mode) = MODE_BYTES]; +} + +message BadEventWithBinaryFieldAtom { + oneof event { BadBinaryFieldAtom field1 = 1; } +} + +message BadBinaryFieldAtom { + optional int32 field1 = 1; + optional ComplexField bf = 2; +} + message BadStateAtoms { oneof event { BadStateAtom1 bad1 = 1; diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp index 1936d9667948..ad3bffacd442 100644 --- a/tools/stats_log_api_gen/test_collation.cpp +++ b/tools/stats_log_api_gen/test_collation.cpp @@ -212,5 +212,19 @@ TEST(CollationTest, PassOnGoodStateAtomOptions) { EXPECT_EQ(0, errorCount); } +TEST(CollationTest, PassOnGoodBinaryFieldAtom) { + Atoms atoms; + int errorCount = + collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), &atoms); + EXPECT_EQ(0, errorCount); +} + +TEST(CollationTest, FailOnBadBinaryFieldAtom) { + Atoms atoms; + int errorCount = + collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), &atoms); + EXPECT_TRUE(errorCount > 0); +} + } // namespace stats_log_api_gen } // namespace android \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From cc651c118e5f56ff8215c59f3a4cbb53ff01e522 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Wed, 17 Oct 2018 13:35:32 -0700 Subject: Add launcher.proto to atoms.proto Test: blank Bug: 113043444 Bug: 120635548 Change-Id: I7e0e72cdf68dcf195188dbab8fe2567fcbd5964e Merged-In: I7e0e72cdf68dcf195188dbab8fe2567fcbd5964e (cherry picked from commit c6d6b77ddc805d6e8f70ed16f0c73177840791e7) --- cmds/statsd/src/atoms.proto | 12 +++- core/proto/android/app/launcher/launcher.proto | 86 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 core/proto/android/app/launcher/launcher.proto diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 281f900d9cb9..049f16edb653 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -22,6 +22,7 @@ option java_outer_classname = "AtomsProto"; import "frameworks/base/cmds/statsd/src/atom_field_options.proto"; import "frameworks/base/core/proto/android/app/enums.proto"; +import "frameworks/base/core/proto/android/app/launcher/launcher.proto"; import "frameworks/base/core/proto/android/app/job/enums.proto"; import "frameworks/base/core/proto/android/bluetooth/enums.proto"; import "frameworks/base/core/proto/android/os/enums.proto"; @@ -59,7 +60,8 @@ message Atom { LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 11; MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12; WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13; - // 14 - 19 are available + // 14 - 18 are available + LauncherUIChanged launcher_event = 19; BatterySaverModeStateChanged battery_saver_mode_state_changed = 20; DeviceIdleModeStateChanged device_idle_mode_state_changed = 21; DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22; @@ -1166,6 +1168,14 @@ message PhoneStateChanged { optional State state = 1; } +message LauncherUIChanged { + optional android.app.launcher.LauncherAction action = 1; + optional android.app.launcher.LauncherState src_state = 2; + optional android.app.launcher.LauncherState dst_state = 3; + optional android.app.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES]; + optional bool is_swipe_up_enabled = 5; +} + /** * Logs that a setting was updated. * Logged from: diff --git a/core/proto/android/app/launcher/launcher.proto b/core/proto/android/app/launcher/launcher.proto new file mode 100644 index 000000000000..6451eb4b08b3 --- /dev/null +++ b/core/proto/android/app/launcher/launcher.proto @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package android.app.launcher; +option java_multiple_files = true; + +enum LauncherAction { + DEFAULT_ACTION = 0; + LAUNCH_APP = 1; + LAUNCH_TASK = 2; + DISMISS_TASK = 3; + LONGPRESS = 4; + DRAGDROP = 5; + SWIPE_UP = 6; + SWIPE_DOWN = 7; + SWIPE_LEFT = 8; + SWIPE_RIGHT = 9; +} + +enum LauncherState { + BACKGROUND = 0; + HOME = 1; + OVERVIEW = 2; + ALLAPPS = 3; +} + +message LauncherTarget { + enum Type { + NONE = 0; + ITEM_TYPE = 1; + CONTROL_TYPE = 2; + CONTAINER_TYPE = 3; + } + enum Item { + DEFAULT_ITEM = 0; + APP_ICON = 1; + SHORTCUT = 2; + WIDGET = 3; + FOLDER_ICON = 4; + DEEPSHORTCUT = 5; + SEARCHBOX = 6; + EDITTEXT = 7; + NOTIFICATION = 8; + TASK = 9; + } + enum Container { + DEFAULT_CONTAINER = 0; + HOTSEAT = 1; + FOLDER = 2; + PREDICTION = 3; + SEARCHRESULT = 4; + } + enum Control { + DEFAULT_CONTROL = 0; + MENU = 1; + UNINSTALL = 2; + REMOVE = 3; + } + optional Type type = 1; + optional Item item = 2; + optional Container container = 3; + optional Control control = 4; + optional string launch_component = 5; + optional int32 page_id = 6; + optional int32 grid_x = 7; + optional int32 grid_y = 8; +} + +message LauncherExtension { + repeated LauncherTarget src_target = 1; + repeated LauncherTarget dst_target = 2; +} -- cgit v1.2.3-59-g8ed1b From 046b51295ea28500333794fb93b6ce96ad71c6af Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Wed, 24 Oct 2018 14:09:20 -0700 Subject: Adding tests and move launcher.proto Test: statsd_test Bug: 120635548 Change-Id: I0655f70098d78f8f6dc9381921c4a687d2195bd4 Merged-In: I0655f70098d78f8f6dc9381921c4a687d2195bd4 (cherry picked from commit 8c4338614513f59e53c2d7a164a05d309a470e81) --- cmds/statsd/src/atoms.proto | 10 +-- cmds/statsd/tests/LogEvent_test.cpp | 58 +++++++++++++++- core/proto/android/app/launcher/launcher.proto | 86 ------------------------ core/proto/android/stats/launcher/launcher.proto | 86 ++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 92 deletions(-) delete mode 100644 core/proto/android/app/launcher/launcher.proto create mode 100644 core/proto/android/stats/launcher/launcher.proto diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 049f16edb653..d9fa0f13f5bf 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -22,11 +22,11 @@ option java_outer_classname = "AtomsProto"; import "frameworks/base/cmds/statsd/src/atom_field_options.proto"; import "frameworks/base/core/proto/android/app/enums.proto"; -import "frameworks/base/core/proto/android/app/launcher/launcher.proto"; import "frameworks/base/core/proto/android/app/job/enums.proto"; import "frameworks/base/core/proto/android/bluetooth/enums.proto"; import "frameworks/base/core/proto/android/os/enums.proto"; import "frameworks/base/core/proto/android/server/enums.proto"; +import "frameworks/base/core/proto/android/stats/launcher/launcher.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; @@ -1169,10 +1169,10 @@ message PhoneStateChanged { } message LauncherUIChanged { - optional android.app.launcher.LauncherAction action = 1; - optional android.app.launcher.LauncherState src_state = 2; - optional android.app.launcher.LauncherState dst_state = 3; - optional android.app.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES]; + optional android.stats.launcher.LauncherAction action = 1; + optional android.stats.launcher.LauncherState src_state = 2; + optional android.stats.launcher.LauncherState dst_state = 3; + optional android.stats.launcher.LauncherExtension extension = 4 [(log_mode) = MODE_BYTES]; optional bool is_swipe_up_enabled = 5; } diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 2fcde29fbbdb..7896c6078eea 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -12,9 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/logd/LogEvent.h" #include #include -#include "src/logd/LogEvent.h" +#include "frameworks/base/cmds/statsd/src/atoms.pb.h" +#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h" #ifdef __ANDROID__ @@ -22,6 +24,9 @@ namespace android { namespace os { namespace statsd { +using std::string; +using util::ProtoOutputStream; + TEST(LogEventTest, TestLogParsing) { LogEvent event1(1, 2000); @@ -159,6 +164,57 @@ TEST(LogEventTest, TestLogParsing2) { } +TEST(LogEventTest, TestBinaryFieldAtom) { + Atom launcherAtom; + auto launcher_event = launcherAtom.mutable_launcher_event(); + launcher_event->set_action(stats::launcher::LauncherAction::LONGPRESS); + launcher_event->set_src_state(stats::launcher::LauncherState::OVERVIEW); + launcher_event->set_dst_state(stats::launcher::LauncherState::ALLAPPS); + + auto extension = launcher_event->mutable_extension(); + + auto src_target = extension->add_src_target(); + src_target->set_type(stats::launcher::LauncherTarget_Type_ITEM_TYPE); + src_target->set_item(stats::launcher::LauncherTarget_Item_FOLDER_ICON); + + auto dst_target = extension->add_dst_target(); + dst_target->set_type(stats::launcher::LauncherTarget_Type_ITEM_TYPE); + dst_target->set_item(stats::launcher::LauncherTarget_Item_WIDGET); + + string extension_str; + extension->SerializeToString(&extension_str); + + LogEvent event1(Atom::kLauncherEventFieldNumber, 1000); + + event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS); + event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW); + event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS); + event1.write(extension_str); + event1.init(); + + ProtoOutputStream proto; + event1.ToProto(proto); + + std::vector outData; + outData.resize(proto.size()); + size_t pos = 0; + auto iter = proto.data(); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&(outData[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); + } + + std::string result_str(outData.begin(), outData.end()); + std::string orig_str; + launcherAtom.SerializeToString(&orig_str); + + EXPECT_EQ(orig_str, result_str); +} + + + } // namespace statsd } // namespace os } // namespace android diff --git a/core/proto/android/app/launcher/launcher.proto b/core/proto/android/app/launcher/launcher.proto deleted file mode 100644 index 6451eb4b08b3..000000000000 --- a/core/proto/android/app/launcher/launcher.proto +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto2"; -package android.app.launcher; -option java_multiple_files = true; - -enum LauncherAction { - DEFAULT_ACTION = 0; - LAUNCH_APP = 1; - LAUNCH_TASK = 2; - DISMISS_TASK = 3; - LONGPRESS = 4; - DRAGDROP = 5; - SWIPE_UP = 6; - SWIPE_DOWN = 7; - SWIPE_LEFT = 8; - SWIPE_RIGHT = 9; -} - -enum LauncherState { - BACKGROUND = 0; - HOME = 1; - OVERVIEW = 2; - ALLAPPS = 3; -} - -message LauncherTarget { - enum Type { - NONE = 0; - ITEM_TYPE = 1; - CONTROL_TYPE = 2; - CONTAINER_TYPE = 3; - } - enum Item { - DEFAULT_ITEM = 0; - APP_ICON = 1; - SHORTCUT = 2; - WIDGET = 3; - FOLDER_ICON = 4; - DEEPSHORTCUT = 5; - SEARCHBOX = 6; - EDITTEXT = 7; - NOTIFICATION = 8; - TASK = 9; - } - enum Container { - DEFAULT_CONTAINER = 0; - HOTSEAT = 1; - FOLDER = 2; - PREDICTION = 3; - SEARCHRESULT = 4; - } - enum Control { - DEFAULT_CONTROL = 0; - MENU = 1; - UNINSTALL = 2; - REMOVE = 3; - } - optional Type type = 1; - optional Item item = 2; - optional Container container = 3; - optional Control control = 4; - optional string launch_component = 5; - optional int32 page_id = 6; - optional int32 grid_x = 7; - optional int32 grid_y = 8; -} - -message LauncherExtension { - repeated LauncherTarget src_target = 1; - repeated LauncherTarget dst_target = 2; -} diff --git a/core/proto/android/stats/launcher/launcher.proto b/core/proto/android/stats/launcher/launcher.proto new file mode 100644 index 000000000000..dbd0e038c40c --- /dev/null +++ b/core/proto/android/stats/launcher/launcher.proto @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package android.stats.launcher; +option java_multiple_files = true; + +enum LauncherAction { + DEFAULT_ACTION = 0; + LAUNCH_APP = 1; + LAUNCH_TASK = 2; + DISMISS_TASK = 3; + LONGPRESS = 4; + DRAGDROP = 5; + SWIPE_UP = 6; + SWIPE_DOWN = 7; + SWIPE_LEFT = 8; + SWIPE_RIGHT = 9; +} + +enum LauncherState { + BACKGROUND = 0; + HOME = 1; + OVERVIEW = 2; + ALLAPPS = 3; +} + +message LauncherTarget { + enum Type { + NONE = 0; + ITEM_TYPE = 1; + CONTROL_TYPE = 2; + CONTAINER_TYPE = 3; + } + enum Item { + DEFAULT_ITEM = 0; + APP_ICON = 1; + SHORTCUT = 2; + WIDGET = 3; + FOLDER_ICON = 4; + DEEPSHORTCUT = 5; + SEARCHBOX = 6; + EDITTEXT = 7; + NOTIFICATION = 8; + TASK = 9; + } + enum Container { + DEFAULT_CONTAINER = 0; + HOTSEAT = 1; + FOLDER = 2; + PREDICTION = 3; + SEARCHRESULT = 4; + } + enum Control { + DEFAULT_CONTROL = 0; + MENU = 1; + UNINSTALL = 2; + REMOVE = 3; + } + optional Type type = 1; + optional Item item = 2; + optional Container container = 3; + optional Control control = 4; + optional string launch_component = 5; + optional int32 page_id = 6; + optional int32 grid_x = 7; + optional int32 grid_y = 8; +} + +message LauncherExtension { + repeated LauncherTarget src_target = 1; + repeated LauncherTarget dst_target = 2; +} -- cgit v1.2.3-59-g8ed1b From 2822b4f42f49650b194f6561454aeb48f4f3d9d1 Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Thu, 29 Nov 2018 09:39:45 -0800 Subject: Skip writing message field in an atom if it's empty Test: unit test added Bug: 120635548 Change-Id: I825b1ce526944a20fe65705508ad180ece37492c Merged-In: I825b1ce526944a20fe65705508ad180ece37492c (cherry picked from commit 8e6f9983009eadf32d05ad65e38906d3985bc9ba) --- cmds/statsd/src/logd/LogEvent.cpp | 2 +- cmds/statsd/src/stats_log_util.cpp | 8 +++++--- cmds/statsd/tests/LogEvent_test.cpp | 37 +++++++++++++++++++++++++++++++++++++ tools/stats_log_api_gen/main.cpp | 5 ++++- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 4e4f146d27ac..5d6d02b4948b 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -379,7 +379,7 @@ float LogEvent::GetFloat(size_t key, status_t* err) const { string LogEvent::ToString() const { string result; - result += StringPrintf("{ %lld %lld (%d)", (long long)mLogdTimestampNs, + result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs, (long long)mElapsedTimestampNs, mTagId); for (const auto& value : mValues) { result += diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp index 444e5b7c3dbb..11ce71705fc1 100644 --- a/cmds/statsd/src/stats_log_util.cpp +++ b/cmds/statsd/src/stats_log_util.cpp @@ -338,9 +338,11 @@ void writeFieldValueTreeToStreamHelper(int tagId, const std::vector& } } if (isBytesField) { - protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum, - (const char*)dim.mValue.str_value.c_str(), - dim.mValue.str_value.length()); + if (dim.mValue.str_value.length() > 0) { + protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum, + (const char*)dim.mValue.str_value.c_str(), + dim.mValue.str_value.length()); + } } else { protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value); } diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp index 7896c6078eea..b29de5385cf4 100644 --- a/cmds/statsd/tests/LogEvent_test.cpp +++ b/cmds/statsd/tests/LogEvent_test.cpp @@ -213,7 +213,44 @@ TEST(LogEventTest, TestBinaryFieldAtom) { EXPECT_EQ(orig_str, result_str); } +TEST(LogEventTest, TestBinaryFieldAtom_empty) { + Atom launcherAtom; + auto launcher_event = launcherAtom.mutable_launcher_event(); + launcher_event->set_action(stats::launcher::LauncherAction::LONGPRESS); + launcher_event->set_src_state(stats::launcher::LauncherState::OVERVIEW); + launcher_event->set_dst_state(stats::launcher::LauncherState::ALLAPPS); + + // empty string. + string extension_str; + + LogEvent event1(Atom::kLauncherEventFieldNumber, 1000); + + event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS); + event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW); + event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS); + event1.write(extension_str); + event1.init(); + + ProtoOutputStream proto; + event1.ToProto(proto); + std::vector outData; + outData.resize(proto.size()); + size_t pos = 0; + auto iter = proto.data(); + while (iter.readBuffer() != NULL) { + size_t toRead = iter.currentToRead(); + std::memcpy(&(outData[pos]), iter.readBuffer(), toRead); + pos += toRead; + iter.rp()->move(toRead); + } + + std::string result_str(outData.begin(), outData.end()); + std::string orig_str; + launcherAtom.SerializeToString(&orig_str); + + EXPECT_EQ(orig_str, result_str); +} } // namespace statsd } // namespace os diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 597b0556ee63..f7e0039dcb4d 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -1007,7 +1007,10 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp hadStringOrChain = true; fprintf(out, " jbyte* jbyte_array%d;\n", argIndex); fprintf(out, " const char* str%d;\n", argIndex); - fprintf(out, " if (arg%d != NULL) {\n", argIndex); + fprintf(out, + " if (arg%d != NULL && env->GetArrayLength(arg%d) > " + "0) {\n", + argIndex, argIndex); fprintf(out, " jbyte_array%d = " "env->GetByteArrayElements(arg%d, NULL);\n", -- cgit v1.2.3-59-g8ed1b From d66ecfccf6f5a1be8f934776dfe72e5bf9c779ec Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Thu, 6 Dec 2018 10:34:25 -0800 Subject: Add byte size of the bytes fields to statslog c++ APIs. The proto binary data can contain '\0's and in the native layer, the current liblog api would convert that into string and thus the data is truncated. This CL adds a "size_t bytes_field_len" after the bytes fields so that we can correctly pass the data from JAVA to native. Java StatsLog.write() APIs remain the same Bug: 120635548 Test: test_drive with atom 103 Change-Id: I34f1c4ddd6a4ec5f3604b0c67a47a5399e3c6ddd Merged-In: I34f1c4ddd6a4ec5f3604b0c67a47a5399e3c6ddd (cherry picked from commit 1fe9f594984b47144b958f0ac423eeffc56b62ea) --- tools/stats_log_api_gen/main.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index f7e0039dcb4d..485fc46387e4 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -266,6 +266,9 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, chainField.name.c_str(), chainField.name.c_str()); } } + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", %s arg%d, size_t arg%d_length", + cpp_type_name(*arg), argIndex, argIndex); } else { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); } @@ -308,6 +311,10 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " event.end();\n"); fprintf(out, " }\n"); fprintf(out, " event.end();\n\n"); + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, + " event.AppendCharArray(arg%d, arg%d_length);\n", + argIndex, argIndex); } else { if (*arg == JAVA_TYPE_STRING) { fprintf(out, " if (arg%d == NULL) {\n", argIndex); @@ -348,6 +355,9 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, chainField.name.c_str(), chainField.name.c_str()); } } + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", %s arg%d, size_t arg%d_length", + cpp_type_name(*arg), argIndex, argIndex); } else { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); } @@ -374,6 +384,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, chainField.name.c_str(), chainField.name.c_str()); } } + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", arg%d, arg%d_length", argIndex, argIndex); } else { fprintf(out, ", arg%d", argIndex); } @@ -522,6 +534,10 @@ static void write_cpp_usage( chainField.name.c_str(), chainField.name.c_str()); } } + } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", %s %s, size_t %s_length", + cpp_type_name(field->javaType), field->name.c_str(), + field->name.c_str()); } else { fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str()); } @@ -549,6 +565,9 @@ static void write_cpp_method_header( chainField.name.c_str(), chainField.name.c_str()); } } + } else if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", %s arg%d, size_t arg%d_length", + cpp_type_name(*arg), argIndex, argIndex); } else { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); } @@ -1007,6 +1026,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp hadStringOrChain = true; fprintf(out, " jbyte* jbyte_array%d;\n", argIndex); fprintf(out, " const char* str%d;\n", argIndex); + fprintf(out, " int str%d_length = 0;\n", argIndex); fprintf(out, " if (arg%d != NULL && env->GetArrayLength(arg%d) > " "0) {\n", @@ -1015,6 +1035,9 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp " jbyte_array%d = " "env->GetByteArrayElements(arg%d, NULL);\n", argIndex, argIndex); + fprintf(out, + " str%d_length = env->GetArrayLength(arg%d);\n", + argIndex, argIndex); fprintf(out, " str%d = " "reinterpret_cast(env->GetByteArrayElements(arg%" @@ -1096,6 +1119,10 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp ? "str" : "arg"; fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex); + + if (*arg == JAVA_TYPE_BYTE_ARRAY) { + fprintf(out, ", %s%d_length", argName, argIndex); + } } argIndex++; } -- cgit v1.2.3-59-g8ed1b