Merge changes from topic "statsd-allow-bytes-type"
* changes: Add byte size of the bytes fields to statslog c++ APIs. Skip writing message field in an atom if it's empty Adding tests and move launcher.proto Add launcher.proto to atoms.proto Allow atoms to log fields in bytes format.
This commit is contained in:
@@ -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];
|
||||
}
|
||||
@@ -26,6 +26,7 @@ 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";
|
||||
@@ -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.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs that a setting was updated.
|
||||
* Logged from:
|
||||
|
||||
@@ -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 +=
|
||||
|
||||
@@ -25,15 +25,16 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
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<Matcher>& fieldMatchers,
|
||||
// }
|
||||
//
|
||||
//
|
||||
void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& dims, size_t* index,
|
||||
int depth, int prefix, ProtoOutputStream* protoOutput) {
|
||||
void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& 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,33 @@ void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& 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<int, std::vector<int>>::const_iterator itr;
|
||||
if (depth == 0 && (itr = AtomsInfo::kBytesFieldAtoms.find(tagId)) !=
|
||||
AtomsInfo::kBytesFieldAtoms.end()) {
|
||||
const std::vector<int>& bytesFields = itr->second;
|
||||
for (int bytesField : bytesFields) {
|
||||
if (bytesField == fieldNum) {
|
||||
// This is a bytes field
|
||||
isBytesField = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isBytesField) {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -337,7 +363,7 @@ void writeFieldValueTreeToStreamHelper(const std::vector<FieldValue>& 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 +380,7 @@ void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/logd/LogEvent.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <log/log_event_list.h>
|
||||
#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,94 @@ 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<uint8_t> 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);
|
||||
}
|
||||
|
||||
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<uint8_t> 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
|
||||
|
||||
86
core/proto/android/stats/launcher/launcher.proto
Normal file
86
core/proto/android/stats/launcher/launcher.proto
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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<int, const FieldDescriptor *>::const_iterator it = fields.begin();
|
||||
it != fields.end(); it++) {
|
||||
const FieldDescriptor *field = it->second;
|
||||
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
|
||||
os::statsd::LogMode::MODE_BYTES;
|
||||
|
||||
java_type_t javaType = java_type(field);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -86,6 +86,8 @@ struct AtomDecl {
|
||||
|
||||
int uidField = 0;
|
||||
|
||||
vector<int> binaryFields;
|
||||
|
||||
AtomDecl();
|
||||
AtomDecl(const AtomDecl& that);
|
||||
AtomDecl(int code, const string& name, const string& message);
|
||||
|
||||
@@ -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<int, StateAtomFieldOptions> "
|
||||
"AtomsInfo::kStateAtomsFieldOptions = "
|
||||
"getStateAtomFieldOptions();\n");
|
||||
|
||||
fprintf(out,
|
||||
"static std::map<int, std::vector<int>> "
|
||||
"getBinaryFieldAtoms() {\n");
|
||||
fprintf(out, " std::map<int, std::vector<int>> options;\n");
|
||||
for (set<AtomDecl>::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<int>(%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<int, std::vector<int>> "
|
||||
"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");
|
||||
@@ -235,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);
|
||||
}
|
||||
@@ -277,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);
|
||||
@@ -317,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);
|
||||
}
|
||||
@@ -343,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);
|
||||
}
|
||||
@@ -491,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());
|
||||
}
|
||||
@@ -518,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);
|
||||
}
|
||||
@@ -600,6 +650,9 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio
|
||||
fprintf(out,
|
||||
" const static std::map<int, StateAtomFieldOptions> "
|
||||
"kStateAtomsFieldOptions;\n");
|
||||
fprintf(out,
|
||||
" const static std::map<int, std::vector<int>> "
|
||||
"kBytesFieldAtoms;");
|
||||
fprintf(out, "};\n");
|
||||
|
||||
fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
|
||||
@@ -632,6 +685,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 +876,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 +925,9 @@ jni_function_name(const string& method_name, const vector<java_type_t>& signatur
|
||||
case JAVA_TYPE_ATTRIBUTION_CHAIN:
|
||||
result += "_AttributionChain";
|
||||
break;
|
||||
case JAVA_TYPE_BYTE_ARRAY:
|
||||
result += "_bytes";
|
||||
break;
|
||||
default:
|
||||
result += "_UNKNOWN";
|
||||
break;
|
||||
@@ -893,6 +953,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 +1022,32 @@ 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, " int str%d_length = 0;\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",
|
||||
argIndex, argIndex);
|
||||
fprintf(out,
|
||||
" str%d_length = env->GetArrayLength(arg%d);\n",
|
||||
argIndex, argIndex);
|
||||
fprintf(out,
|
||||
" str%d = "
|
||||
"reinterpret_cast<char*>(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,8 +1114,15 @@ 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);
|
||||
|
||||
if (*arg == JAVA_TYPE_BYTE_ARRAY) {
|
||||
fprintf(out, ", %s%d_length", argName, argIndex);
|
||||
}
|
||||
}
|
||||
argIndex++;
|
||||
}
|
||||
@@ -1043,6 +1138,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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user