Migrate to frameworks/proto_logging/stats
BUG: 175318992 Test: TH Merged-In: Id85494f7f40a0201061e74fbf3f08f70a632a62c Change-Id: I8bee7a0a6acecc1274d5acc0adb44c5dde8862e4
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
BasedOnStyle: Google
|
|
||||||
AllowShortIfStatementsOnASingleLine: true
|
|
||||||
AllowShortFunctionsOnASingleLine: false
|
|
||||||
AllowShortLoopsOnASingleLine: true
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
ColumnLimit: 100
|
|
||||||
CommentPragmas: NOLINT:.*
|
|
||||||
ContinuationIndentWidth: 8
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
IndentWidth: 4
|
|
||||||
PointerAlignment: Left
|
|
||||||
TabWidth: 4
|
|
||||||
AccessModifierOffset: -4
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^"Log\.h"'
|
|
||||||
Priority: -1
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (C) 2017 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.
|
|
||||||
//
|
|
||||||
|
|
||||||
// ==========================================================
|
|
||||||
// Build the host executable: stats-log-api-gen
|
|
||||||
// ==========================================================
|
|
||||||
cc_binary_host {
|
|
||||||
name: "stats-log-api-gen",
|
|
||||||
srcs: [
|
|
||||||
"Collation.cpp",
|
|
||||||
"java_writer.cpp",
|
|
||||||
"java_writer_q.cpp",
|
|
||||||
"main.cpp",
|
|
||||||
"native_writer.cpp",
|
|
||||||
"utils.cpp",
|
|
||||||
],
|
|
||||||
cflags: [
|
|
||||||
"-Wall",
|
|
||||||
"-Werror",
|
|
||||||
],
|
|
||||||
|
|
||||||
shared_libs: [
|
|
||||||
"libstats_proto_host",
|
|
||||||
"libprotobuf-cpp-full",
|
|
||||||
"libbase",
|
|
||||||
],
|
|
||||||
|
|
||||||
proto: {
|
|
||||||
type: "full",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================
|
|
||||||
// Build the host test executable: stats-log-api-gen
|
|
||||||
// ==========================================================
|
|
||||||
cc_test_host {
|
|
||||||
name: "stats-log-api-gen-test",
|
|
||||||
cflags: [
|
|
||||||
"-Wall",
|
|
||||||
"-Wextra",
|
|
||||||
"-Werror",
|
|
||||||
"-g",
|
|
||||||
"-DUNIT_TEST",
|
|
||||||
],
|
|
||||||
srcs: [
|
|
||||||
"Collation.cpp",
|
|
||||||
"test_collation.cpp",
|
|
||||||
"test.proto",
|
|
||||||
],
|
|
||||||
|
|
||||||
static_libs: [
|
|
||||||
"libgmock_host",
|
|
||||||
],
|
|
||||||
|
|
||||||
shared_libs: [
|
|
||||||
"libstats_proto_host",
|
|
||||||
"libprotobuf-cpp-full",
|
|
||||||
],
|
|
||||||
|
|
||||||
proto: {
|
|
||||||
type: "full",
|
|
||||||
include_dirs: [
|
|
||||||
"external/protobuf/src",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================
|
|
||||||
// Native library
|
|
||||||
// ==========================================================
|
|
||||||
genrule {
|
|
||||||
name: "statslog.h",
|
|
||||||
tools: ["stats-log-api-gen"],
|
|
||||||
cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog.h",
|
|
||||||
out: [
|
|
||||||
"statslog.h",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
genrule {
|
|
||||||
name: "statslog.cpp",
|
|
||||||
tools: ["stats-log-api-gen"],
|
|
||||||
cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog.cpp",
|
|
||||||
out: [
|
|
||||||
"statslog.cpp",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
cc_library {
|
|
||||||
name: "libstatslog",
|
|
||||||
host_supported: true,
|
|
||||||
generated_sources: [
|
|
||||||
"statslog.cpp",
|
|
||||||
],
|
|
||||||
generated_headers: [
|
|
||||||
"statslog.h"
|
|
||||||
],
|
|
||||||
cflags: [
|
|
||||||
"-Wall",
|
|
||||||
"-Werror",
|
|
||||||
],
|
|
||||||
export_generated_headers: [
|
|
||||||
"statslog.h"
|
|
||||||
],
|
|
||||||
shared_libs: [
|
|
||||||
"liblog",
|
|
||||||
"libcutils",
|
|
||||||
],
|
|
||||||
target: {
|
|
||||||
android: {
|
|
||||||
shared_libs: ["libstatssocket"],
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
static_libs: ["libstatssocket"],
|
|
||||||
},
|
|
||||||
darwin: {
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,576 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "frameworks/proto_logging/stats/atoms.pb.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using google::protobuf::EnumDescriptor;
|
|
||||||
using google::protobuf::FieldDescriptor;
|
|
||||||
using google::protobuf::FileDescriptor;
|
|
||||||
using google::protobuf::SourceLocation;
|
|
||||||
using std::make_shared;
|
|
||||||
using std::map;
|
|
||||||
|
|
||||||
const bool dbg = false;
|
|
||||||
|
|
||||||
//
|
|
||||||
// AtomDecl class
|
|
||||||
//
|
|
||||||
|
|
||||||
AtomDecl::AtomDecl() : code(0), name() {
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomDecl::AtomDecl(const AtomDecl& that)
|
|
||||||
: code(that.code),
|
|
||||||
name(that.name),
|
|
||||||
message(that.message),
|
|
||||||
fields(that.fields),
|
|
||||||
fieldNumberToAnnotations(that.fieldNumberToAnnotations),
|
|
||||||
primaryFields(that.primaryFields),
|
|
||||||
exclusiveField(that.exclusiveField),
|
|
||||||
defaultState(that.defaultState),
|
|
||||||
triggerStateReset(that.triggerStateReset),
|
|
||||||
nested(that.nested),
|
|
||||||
uidField(that.uidField) {
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomDecl::AtomDecl(int c, const string& n, const string& m) : code(c), name(n), message(m) {
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomDecl::~AtomDecl() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print an error message for a FieldDescriptor, including the file name and
|
|
||||||
* line number.
|
|
||||||
*/
|
|
||||||
static void print_error(const FieldDescriptor* field, const char* format, ...) {
|
|
||||||
const Descriptor* message = field->containing_type();
|
|
||||||
const FileDescriptor* file = message->file();
|
|
||||||
|
|
||||||
SourceLocation loc;
|
|
||||||
if (field->GetSourceLocation(&loc)) {
|
|
||||||
// TODO: this will work if we can figure out how to pass
|
|
||||||
// --include_source_info to protoc
|
|
||||||
fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "%s: ", file->name().c_str());
|
|
||||||
}
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
vfprintf(stderr, format, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a protobuf type into a java type.
|
|
||||||
*/
|
|
||||||
static java_type_t java_type(const FieldDescriptor* field) {
|
|
||||||
int protoType = field->type();
|
|
||||||
switch (protoType) {
|
|
||||||
case FieldDescriptor::TYPE_DOUBLE:
|
|
||||||
return JAVA_TYPE_DOUBLE;
|
|
||||||
case FieldDescriptor::TYPE_FLOAT:
|
|
||||||
return JAVA_TYPE_FLOAT;
|
|
||||||
case FieldDescriptor::TYPE_INT64:
|
|
||||||
return JAVA_TYPE_LONG;
|
|
||||||
case FieldDescriptor::TYPE_UINT64:
|
|
||||||
return JAVA_TYPE_LONG;
|
|
||||||
case FieldDescriptor::TYPE_INT32:
|
|
||||||
return JAVA_TYPE_INT;
|
|
||||||
case FieldDescriptor::TYPE_FIXED64:
|
|
||||||
return JAVA_TYPE_LONG;
|
|
||||||
case FieldDescriptor::TYPE_FIXED32:
|
|
||||||
return JAVA_TYPE_INT;
|
|
||||||
case FieldDescriptor::TYPE_BOOL:
|
|
||||||
return JAVA_TYPE_BOOLEAN;
|
|
||||||
case FieldDescriptor::TYPE_STRING:
|
|
||||||
return JAVA_TYPE_STRING;
|
|
||||||
case FieldDescriptor::TYPE_GROUP:
|
|
||||||
return JAVA_TYPE_UNKNOWN;
|
|
||||||
case FieldDescriptor::TYPE_MESSAGE:
|
|
||||||
// TODO: not the final package name
|
|
||||||
if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
|
|
||||||
return JAVA_TYPE_ATTRIBUTION_CHAIN;
|
|
||||||
} else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
|
|
||||||
return JAVA_TYPE_KEY_VALUE_PAIR;
|
|
||||||
} else if (field->options().GetExtension(os::statsd::log_mode) ==
|
|
||||||
os::statsd::LogMode::MODE_BYTES) {
|
|
||||||
return JAVA_TYPE_BYTE_ARRAY;
|
|
||||||
} else {
|
|
||||||
return JAVA_TYPE_OBJECT;
|
|
||||||
}
|
|
||||||
case FieldDescriptor::TYPE_BYTES:
|
|
||||||
return JAVA_TYPE_BYTE_ARRAY;
|
|
||||||
case FieldDescriptor::TYPE_UINT32:
|
|
||||||
return JAVA_TYPE_INT;
|
|
||||||
case FieldDescriptor::TYPE_ENUM:
|
|
||||||
return JAVA_TYPE_ENUM;
|
|
||||||
case FieldDescriptor::TYPE_SFIXED32:
|
|
||||||
return JAVA_TYPE_INT;
|
|
||||||
case FieldDescriptor::TYPE_SFIXED64:
|
|
||||||
return JAVA_TYPE_LONG;
|
|
||||||
case FieldDescriptor::TYPE_SINT32:
|
|
||||||
return JAVA_TYPE_INT;
|
|
||||||
case FieldDescriptor::TYPE_SINT64:
|
|
||||||
return JAVA_TYPE_LONG;
|
|
||||||
default:
|
|
||||||
return JAVA_TYPE_UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather the enums info.
|
|
||||||
*/
|
|
||||||
void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
|
|
||||||
for (int i = 0; i < enumDescriptor.value_count(); i++) {
|
|
||||||
atomField->enumValues[enumDescriptor.value(i)->number()] =
|
|
||||||
enumDescriptor.value(i)->name().c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
|
|
||||||
const AnnotationId annotationId,
|
|
||||||
const AnnotationType annotationType,
|
|
||||||
const AnnotationValue annotationValue) {
|
|
||||||
if (dbg) {
|
|
||||||
printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
|
|
||||||
fieldNumber, annotationId, annotationType);
|
|
||||||
}
|
|
||||||
atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
|
|
||||||
make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
|
|
||||||
const int fieldNumber, const java_type_t& javaType) {
|
|
||||||
int errorCount = 0;
|
|
||||||
|
|
||||||
if (field->options().HasExtension(os::statsd::state_field_option)) {
|
|
||||||
const os::statsd::StateAtomFieldOption& stateFieldOption =
|
|
||||||
field->options().GetExtension(os::statsd::state_field_option);
|
|
||||||
const bool primaryField = stateFieldOption.primary_field();
|
|
||||||
const bool exclusiveState = stateFieldOption.exclusive_state();
|
|
||||||
const bool primaryFieldFirstUid = stateFieldOption.primary_field_first_uid();
|
|
||||||
|
|
||||||
// Check the field is only one of primaryField, exclusiveState, or primaryFieldFirstUid.
|
|
||||||
if (primaryField + primaryFieldFirstUid + exclusiveState > 1) {
|
|
||||||
print_error(field,
|
|
||||||
"Field can be max 1 of primary_field, exclusive_state, "
|
|
||||||
"or primary_field_first_uid: '%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (primaryField) {
|
|
||||||
if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
|
|
||||||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
|
|
||||||
print_error(field, "Invalid primary state field: '%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
} else {
|
|
||||||
atomDecl->primaryFields.push_back(fieldNumber);
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_PRIMARY_FIELD,
|
|
||||||
ANNOTATION_TYPE_BOOL, AnnotationValue(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (primaryFieldFirstUid) {
|
|
||||||
if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
print_error(field,
|
|
||||||
"PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
|
|
||||||
"'%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
} else {
|
|
||||||
atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber,
|
|
||||||
ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, ANNOTATION_TYPE_BOOL,
|
|
||||||
AnnotationValue(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exclusiveState) {
|
|
||||||
if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
|
|
||||||
javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
|
|
||||||
print_error(field, "Invalid exclusive state field: '%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atomDecl->exclusiveField != 0) {
|
|
||||||
print_error(field,
|
|
||||||
"Cannot have more than one exclusive state field in an "
|
|
||||||
"atom: '%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
} else {
|
|
||||||
atomDecl->exclusiveField = fieldNumber;
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_EXCLUSIVE_STATE,
|
|
||||||
ANNOTATION_TYPE_BOOL, AnnotationValue(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateFieldOption.has_default_state_value()) {
|
|
||||||
const int defaultState = stateFieldOption.default_state_value();
|
|
||||||
atomDecl->defaultState = defaultState;
|
|
||||||
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
|
|
||||||
ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateFieldOption.has_trigger_state_reset_value()) {
|
|
||||||
const int triggerStateReset = stateFieldOption.trigger_state_reset_value();
|
|
||||||
|
|
||||||
atomDecl->triggerStateReset = triggerStateReset;
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_TRIGGER_STATE_RESET,
|
|
||||||
ANNOTATION_TYPE_INT, AnnotationValue(triggerStateReset));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stateFieldOption.has_nested()) {
|
|
||||||
const bool nested = stateFieldOption.nested();
|
|
||||||
atomDecl->nested = nested;
|
|
||||||
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
|
|
||||||
ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field->options().GetExtension(os::statsd::is_uid) == true) {
|
|
||||||
if (javaType != JAVA_TYPE_INT) {
|
|
||||||
print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atomDecl->uidField == 0) {
|
|
||||||
atomDecl->uidField = fieldNumber;
|
|
||||||
|
|
||||||
addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
|
|
||||||
ANNOTATION_TYPE_BOOL, AnnotationValue(true));
|
|
||||||
} else {
|
|
||||||
print_error(field,
|
|
||||||
"Cannot have more than one field in an atom with is_uid "
|
|
||||||
"annotation: '%s'\n",
|
|
||||||
atomDecl->message.c_str());
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather the info about an atom proto.
|
|
||||||
*/
|
|
||||||
int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) {
|
|
||||||
int errorCount = 0;
|
|
||||||
|
|
||||||
// Build a sorted list of the fields. Descriptor has them in source file
|
|
||||||
// order.
|
|
||||||
map<int, const FieldDescriptor*> fields;
|
|
||||||
for (int j = 0; j < atom->field_count(); j++) {
|
|
||||||
const FieldDescriptor* field = atom->field(j);
|
|
||||||
fields[field->number()] = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the parameters start at 1 and go up sequentially.
|
|
||||||
int expectedNumber = 1;
|
|
||||||
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
|
|
||||||
it++) {
|
|
||||||
const int number = it->first;
|
|
||||||
const FieldDescriptor* field = it->second;
|
|
||||||
if (number != expectedNumber) {
|
|
||||||
print_error(field,
|
|
||||||
"Fields must be numbered consecutively starting at 1:"
|
|
||||||
" '%s' is %d but should be %d\n",
|
|
||||||
field->name().c_str(), number, expectedNumber);
|
|
||||||
errorCount++;
|
|
||||||
expectedNumber = number;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
expectedNumber++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that only allowed types are present. Remove any invalid ones.
|
|
||||||
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
|
|
||||||
it++) {
|
|
||||||
const FieldDescriptor* field = it->second;
|
|
||||||
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
|
|
||||||
os::statsd::LogMode::MODE_BYTES;
|
|
||||||
|
|
||||||
java_type_t javaType = java_type(field);
|
|
||||||
|
|
||||||
if (javaType == JAVA_TYPE_UNKNOWN) {
|
|
||||||
print_error(field, "Unknown type for field: %s\n", field->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
} else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) {
|
|
||||||
// Allow attribution chain, but only at position 1.
|
|
||||||
print_error(field, "Message type not allowed for field in pushed atoms: %s\n",
|
|
||||||
field->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
} else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
|
|
||||||
print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
|
|
||||||
print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Doubles are not supported yet.
|
|
||||||
if (javaType == JAVA_TYPE_DOUBLE) {
|
|
||||||
print_error(field,
|
|
||||||
"Doubles are not supported in atoms. Please change field %s "
|
|
||||||
"to float\n",
|
|
||||||
field->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field->is_repeated() &&
|
|
||||||
!(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
|
|
||||||
print_error(field,
|
|
||||||
"Repeated fields are not supported in atoms. Please make "
|
|
||||||
"field %s not "
|
|
||||||
"repeated.\n",
|
|
||||||
field->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that if there's an attribution chain, it's at position 1.
|
|
||||||
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
|
|
||||||
it++) {
|
|
||||||
int number = it->first;
|
|
||||||
if (number != 1) {
|
|
||||||
const FieldDescriptor* field = it->second;
|
|
||||||
java_type_t javaType = java_type(field);
|
|
||||||
if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
print_error(field,
|
|
||||||
"AttributionChain fields must have field id 1, in message: '%s'\n",
|
|
||||||
atom->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the type signature and the atom data.
|
|
||||||
for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
|
|
||||||
it++) {
|
|
||||||
const FieldDescriptor* field = it->second;
|
|
||||||
java_type_t javaType = java_type(field);
|
|
||||||
bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
|
|
||||||
os::statsd::LogMode::MODE_BYTES;
|
|
||||||
|
|
||||||
AtomField atField(field->name(), javaType);
|
|
||||||
|
|
||||||
if (javaType == JAVA_TYPE_ENUM) {
|
|
||||||
// All enums are treated as ints when it comes to function signatures.
|
|
||||||
collate_enums(*field->enum_type(), &atField);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate signature for pushed atoms
|
|
||||||
if (atomDecl->code < PULL_ATOM_START_ID) {
|
|
||||||
if (javaType == JAVA_TYPE_ENUM) {
|
|
||||||
// All enums are treated as ints when it comes to function signatures.
|
|
||||||
signature->push_back(JAVA_TYPE_INT);
|
|
||||||
} else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
|
|
||||||
signature->push_back(JAVA_TYPE_BYTE_ARRAY);
|
|
||||||
} else {
|
|
||||||
signature->push_back(javaType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
atomDecl->fields.push_back(atField);
|
|
||||||
|
|
||||||
errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function flattens the fields of the AttributionNode proto in an Atom
|
|
||||||
// proto and generates the corresponding atom decl and signature.
|
|
||||||
bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
|
|
||||||
vector<java_type_t>* signature) {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomDecl attributionDecl;
|
|
||||||
vector<java_type_t> attributionSignature;
|
|
||||||
collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
|
|
||||||
&attributionSignature);
|
|
||||||
|
|
||||||
// Build the type signature and the atom data.
|
|
||||||
bool has_attribution_node = false;
|
|
||||||
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_ATTRIBUTION_CHAIN) {
|
|
||||||
atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
|
|
||||||
attributionDecl.fields.end());
|
|
||||||
signature->insert(signature->end(), attributionSignature.begin(),
|
|
||||||
attributionSignature.end());
|
|
||||||
has_attribution_node = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
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 {
|
|
||||||
signature->push_back(javaType);
|
|
||||||
}
|
|
||||||
atomDecl->fields.push_back(atField);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return has_attribution_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl>& atomDecl,
|
|
||||||
FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet) {
|
|
||||||
for (FieldNumberToAnnotations::const_iterator it = atomDecl->fieldNumberToAnnotations.begin();
|
|
||||||
it != atomDecl->fieldNumberToAnnotations.end(); it++) {
|
|
||||||
const int fieldNumber = it->first;
|
|
||||||
(*fieldNumberToAtomDeclSet)[fieldNumber].insert(atomDecl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather the info about the atoms.
|
|
||||||
*/
|
|
||||||
int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
|
|
||||||
int errorCount = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
|
||||||
const FieldDescriptor* atomField = descriptor->field(i);
|
|
||||||
|
|
||||||
if (moduleName != DEFAULT_MODULE_NAME) {
|
|
||||||
const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < moduleCount; ++j) {
|
|
||||||
const string atomModuleName =
|
|
||||||
atomField->options().GetExtension(os::statsd::module, j);
|
|
||||||
if (atomModuleName == moduleName) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This atom is not in the module we're interested in; skip it.
|
|
||||||
if (moduleCount == j) {
|
|
||||||
if (dbg) {
|
|
||||||
printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
shared_ptr<AtomDecl> atomDecl =
|
|
||||||
make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name());
|
|
||||||
|
|
||||||
if (atomDecl->code < PULL_ATOM_START_ID &&
|
|
||||||
atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
|
|
||||||
addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
|
|
||||||
ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
|
|
||||||
AnnotationValue(true));
|
|
||||||
if (dbg) {
|
|
||||||
printf("%s can have timestamp truncated\n", atomField->name().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<java_type_t> signature;
|
|
||||||
errorCount += collate_atom(atom, atomDecl.get(), &signature);
|
|
||||||
if (atomDecl->primaryFields.size() != 0 && atomDecl->exclusiveField == 0) {
|
|
||||||
print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
|
|
||||||
atomField->name().c_str());
|
|
||||||
errorCount++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = atoms->signatureInfoMap[signature];
|
|
||||||
populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet);
|
|
||||||
|
|
||||||
atoms->decls.insert(atomDecl);
|
|
||||||
|
|
||||||
shared_ptr<AtomDecl> nonChainedAtomDecl =
|
|
||||||
make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name());
|
|
||||||
vector<java_type_t> nonChainedSignature;
|
|
||||||
if (get_non_chained_node(atom, nonChainedAtomDecl.get(), &nonChainedSignature)) {
|
|
||||||
FieldNumberToAtomDeclSet& nonChainedFieldNumberToAtomDeclSet =
|
|
||||||
atoms->nonChainedSignatureInfoMap[nonChainedSignature];
|
|
||||||
populateFieldNumberToAtomDeclSet(nonChainedAtomDecl,
|
|
||||||
&nonChainedFieldNumberToAtomDeclSet);
|
|
||||||
|
|
||||||
atoms->non_chained_decls.insert(nonChainedAtomDecl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dbg) {
|
|
||||||
printf("signatures = [\n");
|
|
||||||
for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin();
|
|
||||||
it != atoms->signatureInfoMap.end(); it++) {
|
|
||||||
printf(" ");
|
|
||||||
for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
|
|
||||||
jt++) {
|
|
||||||
printf(" %d", (int)*jt);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
printf("]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H
|
|
||||||
#define ANDROID_STATS_LOG_API_GEN_COLLATION_H
|
|
||||||
|
|
||||||
#include <google/protobuf/descriptor.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "frameworks/proto_logging/stats/atom_field_options.pb.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using google::protobuf::Descriptor;
|
|
||||||
using google::protobuf::FieldDescriptor;
|
|
||||||
using std::map;
|
|
||||||
using std::set;
|
|
||||||
using std::shared_ptr;
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
const int PULL_ATOM_START_ID = 10000;
|
|
||||||
|
|
||||||
const int FIRST_UID_IN_CHAIN_ID = 0;
|
|
||||||
|
|
||||||
enum AnnotationId : uint8_t {
|
|
||||||
ANNOTATION_ID_IS_UID = 1,
|
|
||||||
ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2,
|
|
||||||
ANNOTATION_ID_PRIMARY_FIELD = 3,
|
|
||||||
ANNOTATION_ID_EXCLUSIVE_STATE = 4,
|
|
||||||
ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID = 5,
|
|
||||||
ANNOTATION_ID_DEFAULT_STATE = 6,
|
|
||||||
ANNOTATION_ID_TRIGGER_STATE_RESET = 7,
|
|
||||||
ANNOTATION_ID_STATE_NESTED = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const int ATOM_ID_FIELD_NUMBER = -1;
|
|
||||||
|
|
||||||
const string DEFAULT_MODULE_NAME = "DEFAULT";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The types for atom parameters.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
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_KEY_VALUE_PAIR = 9,
|
|
||||||
|
|
||||||
JAVA_TYPE_OBJECT = -1,
|
|
||||||
JAVA_TYPE_BYTE_ARRAY = -2,
|
|
||||||
} java_type_t;
|
|
||||||
|
|
||||||
enum AnnotationType {
|
|
||||||
ANNOTATION_TYPE_UNKNOWN = 0,
|
|
||||||
ANNOTATION_TYPE_INT = 1,
|
|
||||||
ANNOTATION_TYPE_BOOL = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
union AnnotationValue {
|
|
||||||
int intValue;
|
|
||||||
bool boolValue;
|
|
||||||
|
|
||||||
AnnotationValue(const int value) : intValue(value) {
|
|
||||||
}
|
|
||||||
AnnotationValue(const bool value) : boolValue(value) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Annotation {
|
|
||||||
const AnnotationId annotationId;
|
|
||||||
const int atomId;
|
|
||||||
AnnotationType type;
|
|
||||||
AnnotationValue value;
|
|
||||||
|
|
||||||
inline Annotation(AnnotationId annotationId, int atomId, AnnotationType type,
|
|
||||||
AnnotationValue value)
|
|
||||||
: annotationId(annotationId), atomId(atomId), type(type), value(value) {
|
|
||||||
}
|
|
||||||
inline ~Annotation() {
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator<(const Annotation& that) const {
|
|
||||||
return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SharedComparator {
|
|
||||||
template <typename T>
|
|
||||||
inline bool operator()(const shared_ptr<T>& lhs, const shared_ptr<T>& rhs) const {
|
|
||||||
return (*lhs) < (*rhs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using AnnotationSet = set<shared_ptr<Annotation>, SharedComparator>;
|
|
||||||
|
|
||||||
using FieldNumberToAnnotations = map<int, AnnotationSet>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name and type for an atom field.
|
|
||||||
*/
|
|
||||||
struct AtomField {
|
|
||||||
string name;
|
|
||||||
java_type_t javaType;
|
|
||||||
|
|
||||||
// If the field is of type enum, the following map contains the list of enum
|
|
||||||
// values.
|
|
||||||
map<int /* numeric value */, string /* value name */> enumValues;
|
|
||||||
|
|
||||||
inline AtomField() : name(), javaType(JAVA_TYPE_UNKNOWN) {
|
|
||||||
}
|
|
||||||
inline AtomField(const AtomField& that)
|
|
||||||
: name(that.name), javaType(that.javaType), enumValues(that.enumValues) {
|
|
||||||
}
|
|
||||||
|
|
||||||
inline AtomField(string n, java_type_t jt) : name(n), javaType(jt) {
|
|
||||||
}
|
|
||||||
inline ~AtomField() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name and code for an atom.
|
|
||||||
*/
|
|
||||||
struct AtomDecl {
|
|
||||||
int code;
|
|
||||||
string name;
|
|
||||||
|
|
||||||
string message;
|
|
||||||
vector<AtomField> fields;
|
|
||||||
|
|
||||||
FieldNumberToAnnotations fieldNumberToAnnotations;
|
|
||||||
|
|
||||||
vector<int> primaryFields;
|
|
||||||
int exclusiveField = 0;
|
|
||||||
int defaultState = INT_MAX;
|
|
||||||
int triggerStateReset = INT_MAX;
|
|
||||||
bool nested = true;
|
|
||||||
|
|
||||||
int uidField = 0;
|
|
||||||
|
|
||||||
AtomDecl();
|
|
||||||
AtomDecl(const AtomDecl& that);
|
|
||||||
AtomDecl(int code, const string& name, const string& message);
|
|
||||||
~AtomDecl();
|
|
||||||
|
|
||||||
inline bool operator<(const AtomDecl& that) const {
|
|
||||||
return (code == that.code) ? (name < that.name) : (code < that.code);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using AtomDeclSet = set<shared_ptr<AtomDecl>, SharedComparator>;
|
|
||||||
|
|
||||||
// Maps a field number to a set of atoms that have annotation(s) for their field with that field
|
|
||||||
// number.
|
|
||||||
using FieldNumberToAtomDeclSet = map<int, AtomDeclSet>;
|
|
||||||
|
|
||||||
using SignatureInfoMap = map<vector<java_type_t>, FieldNumberToAtomDeclSet>;
|
|
||||||
|
|
||||||
struct Atoms {
|
|
||||||
SignatureInfoMap signatureInfoMap;
|
|
||||||
AtomDeclSet decls;
|
|
||||||
AtomDeclSet non_chained_decls;
|
|
||||||
SignatureInfoMap nonChainedSignatureInfoMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gather the information about the atoms. Returns the number of errors.
|
|
||||||
*/
|
|
||||||
int collate_atoms(const Descriptor* descriptor, const string& moduleName, 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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
yro@google.com
|
|
||||||
@@ -1,336 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "java_writer.h"
|
|
||||||
|
|
||||||
#include "java_writer_q.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
static int write_java_q_logger_class(FILE* out, const SignatureInfoMap& signatureInfoMap,
|
|
||||||
const AtomDecl& attributionDecl) {
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n");
|
|
||||||
fprintf(out, " private static class QLogger {\n");
|
|
||||||
|
|
||||||
write_java_q_logging_constants(out, " ");
|
|
||||||
|
|
||||||
// Print Q write methods.
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, " // Write methods.\n");
|
|
||||||
write_java_methods_q_schema(out, signatureInfoMap, attributionDecl, " ");
|
|
||||||
|
|
||||||
fprintf(out, " }\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_java_annotation_constants(FILE* out) {
|
|
||||||
fprintf(out, " // Annotation constants.\n");
|
|
||||||
|
|
||||||
for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
|
|
||||||
fprintf(out, " public static final byte %s = %hhu;\n", name.c_str(), id);
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_annotations(FILE* out, int argIndex,
|
|
||||||
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet) {
|
|
||||||
FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
|
|
||||||
fieldNumberToAtomDeclSet.find(argIndex);
|
|
||||||
if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
|
|
||||||
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
|
|
||||||
const string atomConstant = make_constant_name(atomDecl->name);
|
|
||||||
fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
|
|
||||||
const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
|
|
||||||
int resetState = -1;
|
|
||||||
int defaultState = -1;
|
|
||||||
for (const shared_ptr<Annotation>& annotation : annotations) {
|
|
||||||
const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
|
|
||||||
switch (annotation->type) {
|
|
||||||
case ANNOTATION_TYPE_INT:
|
|
||||||
if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
|
|
||||||
resetState = annotation->value.intValue;
|
|
||||||
} else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
|
|
||||||
defaultState = annotation->value.intValue;
|
|
||||||
} else {
|
|
||||||
fprintf(out, " builder.addIntAnnotation(%s, %d);\n",
|
|
||||||
annotationConstant.c_str(), annotation->value.intValue);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ANNOTATION_TYPE_BOOL:
|
|
||||||
fprintf(out, " builder.addBooleanAnnotation(%s, %s);\n",
|
|
||||||
annotationConstant.c_str(),
|
|
||||||
annotation->value.boolValue ? "true" : "false");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (defaultState != -1 && resetState != -1) {
|
|
||||||
const string& annotationConstant =
|
|
||||||
ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
|
|
||||||
fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
|
|
||||||
fprintf(out, " builder.addIntAnnotation(%s, %d);\n",
|
|
||||||
annotationConstant.c_str(), defaultState);
|
|
||||||
fprintf(out, " }\n");
|
|
||||||
}
|
|
||||||
fprintf(out, " }\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
|
|
||||||
const AtomDecl& attributionDecl, const bool supportQ) {
|
|
||||||
for (auto signatureInfoMapIt = signatureInfoMap.begin();
|
|
||||||
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
|
|
||||||
// Print method signature.
|
|
||||||
fprintf(out, " public static void write(int code");
|
|
||||||
const vector<java_type_t>& signature = signatureInfoMapIt->first;
|
|
||||||
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
|
|
||||||
int argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); 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 if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(out, ", android.util.SparseArray<Object> valueMap");
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ") {\n");
|
|
||||||
|
|
||||||
// Print method body.
|
|
||||||
string indent("");
|
|
||||||
if (supportQ) {
|
|
||||||
fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n");
|
|
||||||
indent = " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start StatsEvent.Builder.
|
|
||||||
fprintf(out,
|
|
||||||
"%s final StatsEvent.Builder builder = "
|
|
||||||
"StatsEvent.newBuilder();\n",
|
|
||||||
indent.c_str());
|
|
||||||
|
|
||||||
// Write atom code.
|
|
||||||
fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
|
|
||||||
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
|
|
||||||
|
|
||||||
// Write the args.
|
|
||||||
argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
switch (*arg) {
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_INT:
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
fprintf(out,
|
|
||||||
"%s builder.writeByteArray(null == arg%d ? new byte[0] : "
|
|
||||||
"arg%d);\n",
|
|
||||||
indent.c_str(), argIndex, argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
|
|
||||||
fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
|
|
||||||
fprintf(out, "%s null == %s ? new int[0] : %s,\n",
|
|
||||||
indent.c_str(), uidName, uidName);
|
|
||||||
fprintf(out, "%s null == %s ? new String[0] : %s);\n",
|
|
||||||
indent.c_str(), tagName, tagName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JAVA_TYPE_KEY_VALUE_PAIR:
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s intMap = new "
|
|
||||||
"android.util.SparseIntArray();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s intMap.put(key, (Integer) value);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s } else if (value instanceof Long) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s longMap = new "
|
|
||||||
"android.util.SparseLongArray();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s longMap.put(key, (Long) value);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s } else if (value instanceof String) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s stringMap = new "
|
|
||||||
"android.util.SparseArray<>();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s stringMap.put(key, (String) value);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s } else if (value instanceof Float) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s floatMap = new "
|
|
||||||
"android.util.SparseArray<>();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s floatMap.put(key, (Float) value);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s builder.writeKeyValuePairs("
|
|
||||||
"intMap, longMap, stringMap, floatMap);\n",
|
|
||||||
indent.c_str());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Unsupported types: OBJECT, DOUBLE.
|
|
||||||
fprintf(stderr, "Encountered unsupported type.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
write_annotations(out, argIndex, fieldNumberToAtomDeclSet);
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str());
|
|
||||||
fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
|
|
||||||
|
|
||||||
// Add support for writing using Q schema if this is not the default module.
|
|
||||||
if (supportQ) {
|
|
||||||
fprintf(out, " } else {\n");
|
|
||||||
fprintf(out, " QLogger.write(code");
|
|
||||||
argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin();
|
|
||||||
arg != signature.end(); arg++) {
|
|
||||||
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
fprintf(out, ", %s, %s", uidName, tagName);
|
|
||||||
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
// Module logging does not yet support key value pair.
|
|
||||||
fprintf(stderr, "Module logging does not yet support key value pair.\n");
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", arg%d", argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ");\n");
|
|
||||||
fprintf(out, " }\n"); // if
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, " }\n"); // method
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
|
|
||||||
const string& javaClass, const string& javaPackage, const bool supportQ,
|
|
||||||
const bool supportWorkSource) {
|
|
||||||
// Print prelude
|
|
||||||
fprintf(out, "// This file is autogenerated\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "package %s;\n", javaPackage.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
if (supportQ) {
|
|
||||||
fprintf(out, "import android.os.Build;\n");
|
|
||||||
fprintf(out, "import android.os.SystemClock;\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "import android.util.StatsEvent;\n");
|
|
||||||
fprintf(out, "import android.util.StatsLog;\n");
|
|
||||||
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "/**\n");
|
|
||||||
fprintf(out, " * Utility class for logging statistics events.\n");
|
|
||||||
fprintf(out, " */\n");
|
|
||||||
fprintf(out, "public class %s {\n", javaClass.c_str());
|
|
||||||
|
|
||||||
write_java_atom_codes(out, atoms);
|
|
||||||
write_java_enum_values(out, atoms);
|
|
||||||
write_java_annotation_constants(out);
|
|
||||||
|
|
||||||
int errors = 0;
|
|
||||||
|
|
||||||
// Print write methods.
|
|
||||||
fprintf(out, " // Write methods\n");
|
|
||||||
errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
|
|
||||||
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
|
|
||||||
if (supportWorkSource) {
|
|
||||||
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportQ) {
|
|
||||||
errors += write_java_q_logger_class(out, atoms.signatureInfoMap, attributionDecl);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "}\n");
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
|
|
||||||
const string& javaClass, const string& javaPackage, const bool supportQ,
|
|
||||||
const bool supportWorkSource);
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,601 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "java_writer_q.h"
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
void write_java_q_logging_constants(FILE* out, const string& indent) {
|
|
||||||
fprintf(out, "%s// Payload limits.\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%sprivate static final int MAX_EVENT_PAYLOAD = "
|
|
||||||
"LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
|
|
||||||
indent.c_str());
|
|
||||||
|
|
||||||
// Value types. Must match with EventLog.java and log.h.
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "%s// Value types.\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final byte INT_TYPE = 0;\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final byte LONG_TYPE = 1;\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final byte STRING_TYPE = 2;\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final byte LIST_TYPE = 3;\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Size of each value type.
|
|
||||||
// Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for
|
|
||||||
// the value.
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "%s// Size of each value type.\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str());
|
|
||||||
// Longs take 9 bytes, 1 for the type and 8 for the value.
|
|
||||||
fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str());
|
|
||||||
// Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the
|
|
||||||
// length.
|
|
||||||
fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
|
|
||||||
const AtomDecl& attributionDecl, const string& indent) {
|
|
||||||
int requiredHelpers = 0;
|
|
||||||
for (auto signatureInfoMapIt = signatureInfoMap.begin();
|
|
||||||
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
|
|
||||||
// Print method signature.
|
|
||||||
vector<java_type_t> signature = signatureInfoMapIt->first;
|
|
||||||
fprintf(out, "%spublic static void write(int code", indent.c_str());
|
|
||||||
int argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); 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 if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(out, ", android.util.SparseArray<Object> valueMap");
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ") {\n");
|
|
||||||
|
|
||||||
// Calculate the size of the buffer.
|
|
||||||
fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + "
|
|
||||||
"INT_TYPE_SIZE;\n",
|
|
||||||
indent.c_str());
|
|
||||||
argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
switch (*arg) {
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
case JAVA_TYPE_INT:
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
// Longs take 9 bytes, 1 for the type and 8 for the value.
|
|
||||||
fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
// Strings take 5 metadata bytes + length of byte encoded string.
|
|
||||||
fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
|
|
||||||
fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex);
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s byte[] arg%dBytes = "
|
|
||||||
"arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
|
|
||||||
indent.c_str(), argIndex, argIndex);
|
|
||||||
fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
|
|
||||||
indent.c_str(), argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
// Byte arrays take 5 metadata bytes + length of byte array.
|
|
||||||
fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
|
|
||||||
fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex);
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
|
|
||||||
indent.c_str(), argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
// Null checks on the params.
|
|
||||||
fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName);
|
|
||||||
fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName,
|
|
||||||
java_type_name(attributionDecl.fields.front().javaType));
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName);
|
|
||||||
fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName,
|
|
||||||
java_type_name(attributionDecl.fields.back().javaType));
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
|
|
||||||
// First check that the lengths of the uid and tag arrays are the
|
|
||||||
// same.
|
|
||||||
fprintf(out, "%s if (%s.length != %s.length) {\n", indent.c_str(), uidName,
|
|
||||||
tagName);
|
|
||||||
fprintf(out, "%s return;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(),
|
|
||||||
tagName);
|
|
||||||
fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
|
|
||||||
indent.c_str(), argIndex, tagName, tagName);
|
|
||||||
fprintf(out,
|
|
||||||
"%s int str%dlen = "
|
|
||||||
"str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8)."
|
|
||||||
"length;\n",
|
|
||||||
indent.c_str(), argIndex, argIndex);
|
|
||||||
fprintf(out,
|
|
||||||
"%s attrSize += "
|
|
||||||
"LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + "
|
|
||||||
"str%dlen;\n",
|
|
||||||
indent.c_str(), argIndex);
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s needed += attrSize;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JAVA_TYPE_KEY_VALUE_PAIR: {
|
|
||||||
fprintf(out, "%s // Calculate bytes needed by Key Value Pairs.\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s intMap = new android.util.SparseIntArray();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s intMap.put(key, (Integer) value);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s } else if (value instanceof Long) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s longMap = new "
|
|
||||||
"android.util.SparseLongArray();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s longMap.put(key, (Long) value);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s } else if (value instanceof String) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s final String str = (value == null) ? \"\" : "
|
|
||||||
"(String) value;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s final int len = "
|
|
||||||
"str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s keyValuePairSize += LIST_TYPE_OVERHEAD + "
|
|
||||||
"INT_TYPE_SIZE\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s + STRING_TYPE_OVERHEAD + len;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s stringMap = new "
|
|
||||||
"android.util.SparseArray<>();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s stringMap.put(key, str);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s } else if (value instanceof Float) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s floatMap = new "
|
|
||||||
"android.util.SparseArray<>();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s floatMap.put(key, (Float) value);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Unsupported types: OBJECT, DOUBLE.
|
|
||||||
fprintf(stderr, "Module logging does not yet support Object and Double.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we have the size that is needed. Check for overflow and return if
|
|
||||||
// needed.
|
|
||||||
fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s return;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
|
|
||||||
// Create new buffer, and associated data types.
|
|
||||||
fprintf(out, "%s byte[] buff = new byte[needed];\n", indent.c_str());
|
|
||||||
fprintf(out, "%s int pos = 0;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Initialize the buffer with list data type.
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = %zu;\n", indent.c_str(), signature.size() + 2);
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write timestamp.
|
|
||||||
fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write atom code.
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, code);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write the args.
|
|
||||||
argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
switch (*arg) {
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_INT:
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
|
|
||||||
fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n",
|
|
||||||
indent.c_str(), argIndex);
|
|
||||||
fprintf(out,
|
|
||||||
"%s System.arraycopy("
|
|
||||||
"arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
|
|
||||||
"arg%dBytes.length);\n",
|
|
||||||
indent.c_str(), argIndex, argIndex);
|
|
||||||
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
|
|
||||||
indent.c_str(), argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", indent.c_str(),
|
|
||||||
argIndex);
|
|
||||||
fprintf(out,
|
|
||||||
"%s System.arraycopy("
|
|
||||||
"arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
|
|
||||||
indent.c_str(), argIndex, argIndex);
|
|
||||||
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
|
|
||||||
indent.c_str(), argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
|
|
||||||
requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
|
|
||||||
fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n",
|
|
||||||
indent.c_str(), uidName, tagName);
|
|
||||||
fprintf(out, "%s pos += attrSize;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JAVA_TYPE_KEY_VALUE_PAIR:
|
|
||||||
requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
|
|
||||||
requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
|
|
||||||
fprintf(out,
|
|
||||||
"%s writeKeyValuePairs(buff, pos, (byte) count, intMap, "
|
|
||||||
"longMap, "
|
|
||||||
"stringMap, floatMap);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Unsupported types: OBJECT, DOUBLE.
|
|
||||||
fprintf(stderr, "Object and Double are not supported in module logging");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "%s StatsLog.writeRaw(buff, pos);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s}\n", indent.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
write_java_helpers_for_q_schema_methods(out, attributionDecl, requiredHelpers, indent);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
|
|
||||||
const int requiredHelpers, const string& indent) {
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str());
|
|
||||||
fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s return;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s}\n", indent.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
|
|
||||||
fprintf(out, "%sprivate static void copyLong(byte[] buff, int pos, long val) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 4] = (byte) (val >> 32);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 5] = (byte) (val >> 40);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 6] = (byte) (val >> 48);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 7] = (byte) (val >> 56);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s return;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s}\n", indent.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
|
|
||||||
if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) {
|
|
||||||
fprintf(out, "%sprivate static void copyFloat(byte[] buff, int pos, float val) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos, Float.floatToIntBits(val));\n", indent.c_str());
|
|
||||||
fprintf(out, "%s return;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s}\n", indent.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
|
|
||||||
fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
|
|
||||||
indent.c_str());
|
|
||||||
for (auto chainField : attributionDecl.fields) {
|
|
||||||
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
|
|
||||||
}
|
|
||||||
fprintf(out, ") {\n");
|
|
||||||
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
|
|
||||||
// Write the first list begin.
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) (%s.length);\n", indent.c_str(), tagName);
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Iterate through the attribution chain and write the nodes.
|
|
||||||
fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName);
|
|
||||||
// Write the list begin.
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = %lu;\n", indent.c_str(),
|
|
||||||
attributionDecl.fields.size());
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write the uid.
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, %s[i]);\n", indent.c_str(), uidName);
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write the tag.
|
|
||||||
fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", indent.c_str(),
|
|
||||||
tagName, tagName, tagName);
|
|
||||||
fprintf(out,
|
|
||||||
"%s byte[] %sByte = "
|
|
||||||
"%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
|
|
||||||
indent.c_str(), tagName, tagName);
|
|
||||||
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName);
|
|
||||||
fprintf(out,
|
|
||||||
"%s System.arraycopy("
|
|
||||||
"%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
|
|
||||||
indent.c_str(), tagName, tagName);
|
|
||||||
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", indent.c_str(),
|
|
||||||
tagName);
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s}\n", indent.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) {
|
|
||||||
fprintf(out,
|
|
||||||
"%sprivate static void writeKeyValuePairs(byte[] buff, int pos, "
|
|
||||||
"byte numPairs,\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final android.util.SparseArray<String> stringMap,\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s final android.util.SparseArray<Float> floatMap) {\n",
|
|
||||||
indent.c_str());
|
|
||||||
|
|
||||||
// Start list of lists.
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) numPairs;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write integers.
|
|
||||||
fprintf(out, "%s final int intMapSize = null == intMap ? 0 : intMap.size();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < intMapSize; i++) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int key = intMap.keyAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int value = intMap.valueAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, value);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write longs.
|
|
||||||
fprintf(out, "%s final int longMapSize = null == longMap ? 0 : longMap.size();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < longMapSize; i++) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int key = longMap.keyAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final long value = longMap.valueAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyLong(buff, pos + 1, value);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write Strings.
|
|
||||||
fprintf(out,
|
|
||||||
"%s final int stringMapSize = null == stringMap ? 0 : "
|
|
||||||
"stringMap.size();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int key = stringMap.keyAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final String value = stringMap.valueAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s final byte[] valueBytes = "
|
|
||||||
"value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str());
|
|
||||||
fprintf(out,
|
|
||||||
"%s System.arraycopy("
|
|
||||||
"valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
|
|
||||||
"valueBytes.length);\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
|
|
||||||
// Write floats.
|
|
||||||
fprintf(out,
|
|
||||||
"%s final int floatMapSize = null == floatMap ? 0 : "
|
|
||||||
"floatMap.size();\n",
|
|
||||||
indent.c_str());
|
|
||||||
fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final int key = floatMap.keyAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s final float value = floatMap.valueAt(i);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s copyFloat(buff, pos + 1, value);\n", indent.c_str());
|
|
||||||
fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
|
|
||||||
fprintf(out, "%s }\n", indent.c_str());
|
|
||||||
fprintf(out, "%s}\n", indent.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is called in main.cpp to generate StatsLog for modules that's
|
|
||||||
// compatible with Q at compile-time.
|
|
||||||
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
|
|
||||||
const AtomDecl& attributionDecl, const string& javaClass,
|
|
||||||
const string& javaPackage, const bool supportWorkSource) {
|
|
||||||
// Print prelude
|
|
||||||
fprintf(out, "// This file is autogenerated\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "package %s;\n", javaPackage.c_str());
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "import android.util.StatsLog;\n");
|
|
||||||
fprintf(out, "import android.os.SystemClock;\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "/**\n");
|
|
||||||
fprintf(out, " * Utility class for logging statistics events.\n");
|
|
||||||
fprintf(out, " */\n");
|
|
||||||
fprintf(out, "public class %s {\n", javaClass.c_str());
|
|
||||||
|
|
||||||
write_java_q_logging_constants(out, " ");
|
|
||||||
|
|
||||||
write_java_atom_codes(out, atoms);
|
|
||||||
|
|
||||||
write_java_enum_values(out, atoms);
|
|
||||||
|
|
||||||
int errors = 0;
|
|
||||||
// Print write methods
|
|
||||||
fprintf(out, " // Write methods\n");
|
|
||||||
errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, " ");
|
|
||||||
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
|
|
||||||
if (supportWorkSource) {
|
|
||||||
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "}\n");
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
void write_java_q_logging_constants(FILE* out, const string& indent);
|
|
||||||
|
|
||||||
int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
|
|
||||||
const AtomDecl& attributionDecl, const string& indent);
|
|
||||||
|
|
||||||
void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
|
|
||||||
const int requiredHelpers, const string& indent);
|
|
||||||
|
|
||||||
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
|
|
||||||
const AtomDecl& attributionDecl, const string& javaClass,
|
|
||||||
const string& javaPackage, const bool supportWorkSource);
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
#include "frameworks/proto_logging/stats/atoms.pb.h"
|
|
||||||
#include "java_writer.h"
|
|
||||||
#include "java_writer_q.h"
|
|
||||||
#include "native_writer.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
using namespace google::protobuf;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using android::os::statsd::Atom;
|
|
||||||
|
|
||||||
static void print_usage() {
|
|
||||||
fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
fprintf(stderr, "OPTIONS\n");
|
|
||||||
fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n");
|
|
||||||
fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n");
|
|
||||||
fprintf(stderr, " --help this message\n");
|
|
||||||
fprintf(stderr, " --java FILENAME the java file to output\n");
|
|
||||||
fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
" --namespace COMMA,SEP,NAMESPACE required for cpp/header with "
|
|
||||||
"module\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
" comma separated namespace of "
|
|
||||||
"the files\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
" --importHeader NAME required for cpp/jni to say which header to "
|
|
||||||
"import "
|
|
||||||
"for write helpers\n");
|
|
||||||
fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n");
|
|
||||||
fprintf(stderr, " required for java with module\n");
|
|
||||||
fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
|
|
||||||
fprintf(stderr, " Optional for Java with module.\n");
|
|
||||||
fprintf(stderr, " Default is \"StatsLogInternal\"\n");
|
|
||||||
fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
" --worksource Include support for logging WorkSource "
|
|
||||||
"objects.\n");
|
|
||||||
fprintf(stderr,
|
|
||||||
" --compileQ Include compile-time support for Android Q "
|
|
||||||
"(Java only).\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do the argument parsing and execute the tasks.
|
|
||||||
*/
|
|
||||||
static int run(int argc, char const* const* argv) {
|
|
||||||
string cppFilename;
|
|
||||||
string headerFilename;
|
|
||||||
string javaFilename;
|
|
||||||
string javaPackage;
|
|
||||||
string javaClass;
|
|
||||||
|
|
||||||
string moduleName = DEFAULT_MODULE_NAME;
|
|
||||||
string cppNamespace = DEFAULT_CPP_NAMESPACE;
|
|
||||||
string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
|
|
||||||
bool supportQ = false;
|
|
||||||
bool supportWorkSource = false;
|
|
||||||
bool compileQ = false;
|
|
||||||
|
|
||||||
int index = 1;
|
|
||||||
while (index < argc) {
|
|
||||||
if (0 == strcmp("--help", argv[index])) {
|
|
||||||
print_usage();
|
|
||||||
return 0;
|
|
||||||
} else if (0 == strcmp("--cpp", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cppFilename = argv[index];
|
|
||||||
} else if (0 == strcmp("--header", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
headerFilename = argv[index];
|
|
||||||
} else if (0 == strcmp("--java", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
javaFilename = argv[index];
|
|
||||||
} else if (0 == strcmp("--module", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
moduleName = argv[index];
|
|
||||||
} else if (0 == strcmp("--namespace", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cppNamespace = argv[index];
|
|
||||||
} else if (0 == strcmp("--importHeader", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cppHeaderImport = argv[index];
|
|
||||||
} else if (0 == strcmp("--javaPackage", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
javaPackage = argv[index];
|
|
||||||
} else if (0 == strcmp("--javaClass", argv[index])) {
|
|
||||||
index++;
|
|
||||||
if (index >= argc) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
javaClass = argv[index];
|
|
||||||
} else if (0 == strcmp("--supportQ", argv[index])) {
|
|
||||||
supportQ = true;
|
|
||||||
} else if (0 == strcmp("--worksource", argv[index])) {
|
|
||||||
supportWorkSource = true;
|
|
||||||
} else if (0 == strcmp("--compileQ", argv[index])) {
|
|
||||||
compileQ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) {
|
|
||||||
// Support for Q schema is not needed for default module.
|
|
||||||
fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportQ && compileQ) {
|
|
||||||
// Runtime Q support is redundant if compile-time Q support is required.
|
|
||||||
fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collate the parameters
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(Atom::descriptor(), moduleName, &atoms);
|
|
||||||
if (errorCount != 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomDecl attributionDecl;
|
|
||||||
vector<java_type_t> attributionSignature;
|
|
||||||
collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
|
|
||||||
&attributionSignature);
|
|
||||||
|
|
||||||
// Write the .cpp file
|
|
||||||
if (cppFilename.size() != 0) {
|
|
||||||
FILE* out = fopen(cppFilename.c_str(), "w");
|
|
||||||
if (out == NULL) {
|
|
||||||
fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// If this is for a specific module, the namespace must also be provided.
|
|
||||||
if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
|
|
||||||
fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// If this is for a specific module, the header file to import must also be
|
|
||||||
// provided.
|
|
||||||
if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
|
|
||||||
fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
errorCount = android::stats_log_api_gen::write_stats_log_cpp(
|
|
||||||
out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
|
|
||||||
fclose(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the .h file
|
|
||||||
if (headerFilename.size() != 0) {
|
|
||||||
FILE* out = fopen(headerFilename.c_str(), "w");
|
|
||||||
if (out == NULL) {
|
|
||||||
fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// If this is for a specific module, the namespace must also be provided.
|
|
||||||
if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
|
|
||||||
fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
|
|
||||||
}
|
|
||||||
errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl,
|
|
||||||
cppNamespace);
|
|
||||||
fclose(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the .java file
|
|
||||||
if (javaFilename.size() != 0) {
|
|
||||||
if (javaClass.size() == 0) {
|
|
||||||
fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (javaPackage.size() == 0) {
|
|
||||||
fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleName.size() == 0) {
|
|
||||||
fprintf(stderr, "Must supply --module if supplying a Java filename");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* out = fopen(javaFilename.c_str(), "w");
|
|
||||||
if (out == NULL) {
|
|
||||||
fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compileQ) {
|
|
||||||
errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
|
|
||||||
out, atoms, attributionDecl, javaClass, javaPackage, supportWorkSource);
|
|
||||||
} else {
|
|
||||||
errorCount = android::stats_log_api_gen::write_stats_log_java(
|
|
||||||
out, atoms, attributionDecl, javaClass, javaPackage, supportQ,
|
|
||||||
supportWorkSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main.
|
|
||||||
*/
|
|
||||||
int main(int argc, char const* const* argv) {
|
|
||||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
|
||||||
|
|
||||||
return android::stats_log_api_gen::run(argc, argv);
|
|
||||||
}
|
|
||||||
@@ -1,355 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "native_writer.h"
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
static void write_native_annotation_constants(FILE* out) {
|
|
||||||
fprintf(out, "// Annotation constants.\n");
|
|
||||||
|
|
||||||
for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
|
|
||||||
fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_annotations(FILE* out, int argIndex,
|
|
||||||
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
|
|
||||||
const string& methodPrefix, const string& methodSuffix) {
|
|
||||||
FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
|
|
||||||
fieldNumberToAtomDeclSet.find(argIndex);
|
|
||||||
if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
|
|
||||||
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
|
|
||||||
const string atomConstant = make_constant_name(atomDecl->name);
|
|
||||||
fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
|
|
||||||
const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
|
|
||||||
int resetState = -1;
|
|
||||||
int defaultState = -1;
|
|
||||||
for (const shared_ptr<Annotation>& annotation : annotations) {
|
|
||||||
const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
|
|
||||||
switch (annotation->type) {
|
|
||||||
case ANNOTATION_TYPE_INT:
|
|
||||||
if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
|
|
||||||
resetState = annotation->value.intValue;
|
|
||||||
} else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
|
|
||||||
defaultState = annotation->value.intValue;
|
|
||||||
} else {
|
|
||||||
fprintf(out, " %saddInt32Annotation(%s%s, %d);\n",
|
|
||||||
methodPrefix.c_str(), methodSuffix.c_str(),
|
|
||||||
annotationConstant.c_str(), annotation->value.intValue);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ANNOTATION_TYPE_BOOL:
|
|
||||||
// TODO(b/151786433): Write annotation constant name instead of
|
|
||||||
// annotation id literal.
|
|
||||||
fprintf(out, " %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
|
|
||||||
methodSuffix.c_str(), annotationConstant.c_str(),
|
|
||||||
annotation->value.boolValue ? "true" : "false");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (defaultState != -1 && resetState != -1) {
|
|
||||||
const string& annotationConstant =
|
|
||||||
ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
|
|
||||||
fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
|
|
||||||
fprintf(out, " %saddInt32Annotation(%s%s, %d);\n", methodPrefix.c_str(),
|
|
||||||
methodSuffix.c_str(), annotationConstant.c_str(), defaultState);
|
|
||||||
fprintf(out, " }\n");
|
|
||||||
}
|
|
||||||
fprintf(out, " }\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
|
|
||||||
const AtomDecl& attributionDecl, const bool supportQ) {
|
|
||||||
fprintf(out, "\n");
|
|
||||||
for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
|
|
||||||
signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
|
|
||||||
vector<java_type_t> signature = signatureInfoMapIt->first;
|
|
||||||
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
|
|
||||||
// Key value pairs not supported in native.
|
|
||||||
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
|
|
||||||
|
|
||||||
int argIndex = 1;
|
|
||||||
if (supportQ) {
|
|
||||||
fprintf(out, " StatsEventCompat event;\n");
|
|
||||||
fprintf(out, " event.setAtomId(code);\n");
|
|
||||||
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "");
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin();
|
|
||||||
arg != signature.end(); arg++) {
|
|
||||||
switch (*arg) {
|
|
||||||
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n",
|
|
||||||
uidName, uidName, tagName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
|
|
||||||
argIndex, argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
fprintf(out, " event.writeBool(arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_INT: // Fall through.
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
fprintf(out, " event.writeFloat(arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
fprintf(out, " event.writeInt64(arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
fprintf(out, " event.writeString(arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS.
|
|
||||||
fprintf(stderr, "Encountered unsupported type.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "");
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, " return event.writeToSocket();\n");
|
|
||||||
} else {
|
|
||||||
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
|
|
||||||
fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
|
|
||||||
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
|
|
||||||
"event, ");
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin();
|
|
||||||
arg != signature.end(); arg++) {
|
|
||||||
switch (*arg) {
|
|
||||||
case JAVA_TYPE_ATTRIBUTION_CHAIN: {
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
fprintf(out,
|
|
||||||
" AStatsEvent_writeAttributionChain(event, "
|
|
||||||
"reinterpret_cast<const uint32_t*>(%s), %s.data(), "
|
|
||||||
"static_cast<uint8_t>(%s_length));\n",
|
|
||||||
uidName, tagName, uidName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
fprintf(out,
|
|
||||||
" AStatsEvent_writeByteArray(event, "
|
|
||||||
"reinterpret_cast<const uint8_t*>(arg%d.arg), "
|
|
||||||
"arg%d.arg_length);\n",
|
|
||||||
argIndex, argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_INT: // Fall through.
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
|
|
||||||
fprintf(stderr, "Encountered unsupported type.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
|
|
||||||
"event, ");
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, " const int ret = AStatsEvent_write(event);\n");
|
|
||||||
fprintf(out, " AStatsEvent_release(event);\n");
|
|
||||||
fprintf(out, " return ret;\n");
|
|
||||||
}
|
|
||||||
fprintf(out, "}\n\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
|
|
||||||
const AtomDecl& attributionDecl) {
|
|
||||||
fprintf(out, "\n");
|
|
||||||
for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
|
|
||||||
signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
|
|
||||||
vector<java_type_t> signature = signature_it->first;
|
|
||||||
// Key value pairs not supported in native.
|
|
||||||
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
write_native_method_signature(out, "int stats_write_non_chained", signature,
|
|
||||||
attributionDecl, " {");
|
|
||||||
|
|
||||||
vector<java_type_t> newSignature;
|
|
||||||
|
|
||||||
// First two args form the attribution node so size goes down by 1.
|
|
||||||
newSignature.reserve(signature.size() - 1);
|
|
||||||
|
|
||||||
// First arg is Attribution Chain.
|
|
||||||
newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
|
|
||||||
|
|
||||||
// Followed by the originial signature except the first 2 args.
|
|
||||||
newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
|
|
||||||
|
|
||||||
const char* uidName = attributionDecl.fields.front().name.c_str();
|
|
||||||
const char* tagName = attributionDecl.fields.back().name.c_str();
|
|
||||||
fprintf(out, " const int32_t* %s = &arg1;\n", uidName);
|
|
||||||
fprintf(out, " const size_t %s_length = 1;\n", uidName);
|
|
||||||
fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName);
|
|
||||||
fprintf(out, " return ");
|
|
||||||
write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
|
|
||||||
|
|
||||||
fprintf(out, "}\n\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_native_method_header(FILE* out, const string& methodName,
|
|
||||||
const SignatureInfoMap& signatureInfoMap,
|
|
||||||
const AtomDecl& attributionDecl) {
|
|
||||||
for (auto signatureInfoMapIt = signatureInfoMap.begin();
|
|
||||||
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
|
|
||||||
vector<java_type_t> signature = signatureInfoMapIt->first;
|
|
||||||
|
|
||||||
// Key value pairs not supported in native.
|
|
||||||
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
write_native_method_signature(out, methodName, signature, attributionDecl, ";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
|
|
||||||
const string& cppNamespace, const string& importHeader,
|
|
||||||
const bool supportQ) {
|
|
||||||
// Print prelude
|
|
||||||
fprintf(out, "// This file is autogenerated\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
|
|
||||||
fprintf(out, "#include <%s>\n", importHeader.c_str());
|
|
||||||
if (supportQ) {
|
|
||||||
fprintf(out, "#include <StatsEventCompat.h>\n");
|
|
||||||
} else {
|
|
||||||
fprintf(out, "#include <stats_event.h>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "\n");
|
|
||||||
write_namespace(out, cppNamespace);
|
|
||||||
|
|
||||||
write_native_stats_write_methods(out, atoms, attributionDecl, supportQ);
|
|
||||||
write_native_stats_write_non_chained_methods(out, atoms, attributionDecl);
|
|
||||||
|
|
||||||
// Print footer
|
|
||||||
fprintf(out, "\n");
|
|
||||||
write_closing_namespace(out, cppNamespace);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
|
|
||||||
const string& cppNamespace) {
|
|
||||||
// Print prelude
|
|
||||||
fprintf(out, "// This file is autogenerated\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "#pragma once\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "#include <stdint.h>\n");
|
|
||||||
fprintf(out, "#include <vector>\n");
|
|
||||||
fprintf(out, "#include <map>\n");
|
|
||||||
fprintf(out, "#include <set>\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
|
|
||||||
write_namespace(out, cppNamespace);
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "/*\n");
|
|
||||||
fprintf(out, " * API For logging statistics events.\n");
|
|
||||||
fprintf(out, " */\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
|
|
||||||
write_native_atom_constants(out, atoms, attributionDecl);
|
|
||||||
|
|
||||||
// Print constants for the enum values.
|
|
||||||
fprintf(out, "//\n");
|
|
||||||
fprintf(out, "// Constants for enum values\n");
|
|
||||||
fprintf(out, "//\n\n");
|
|
||||||
for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
|
|
||||||
atomIt++) {
|
|
||||||
for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
|
|
||||||
field != (*atomIt)->fields.end(); field++) {
|
|
||||||
if (field->javaType == JAVA_TYPE_ENUM) {
|
|
||||||
fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
|
|
||||||
field->name.c_str());
|
|
||||||
for (map<int, string>::const_iterator value = field->enumValues.begin();
|
|
||||||
value != field->enumValues.end(); value++) {
|
|
||||||
fprintf(out, "const int32_t %s__%s__%s = %d;\n",
|
|
||||||
make_constant_name((*atomIt)->message).c_str(),
|
|
||||||
make_constant_name(field->name).c_str(),
|
|
||||||
make_constant_name(value->second).c_str(), value->first);
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write_native_annotation_constants(out);
|
|
||||||
|
|
||||||
fprintf(out, "struct BytesField {\n");
|
|
||||||
fprintf(out,
|
|
||||||
" BytesField(char const* array, size_t len) : arg(array), "
|
|
||||||
"arg_length(len) {}\n");
|
|
||||||
fprintf(out, " char const* arg;\n");
|
|
||||||
fprintf(out, " size_t arg_length;\n");
|
|
||||||
fprintf(out, "};\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
|
|
||||||
// Print write methods
|
|
||||||
fprintf(out, "//\n");
|
|
||||||
fprintf(out, "// Write methods\n");
|
|
||||||
fprintf(out, "//\n");
|
|
||||||
write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl);
|
|
||||||
|
|
||||||
fprintf(out, "//\n");
|
|
||||||
fprintf(out, "// Write flattened methods\n");
|
|
||||||
fprintf(out, "//\n");
|
|
||||||
write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
|
|
||||||
attributionDecl);
|
|
||||||
|
|
||||||
fprintf(out, "\n");
|
|
||||||
write_closing_namespace(out, cppNamespace);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
|
|
||||||
const string& cppNamespace, const string& importHeader,
|
|
||||||
const bool supportQ);
|
|
||||||
|
|
||||||
int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
|
|
||||||
const string& cppNamespace);
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 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";
|
|
||||||
|
|
||||||
import "frameworks/proto_logging/stats/atoms.proto";
|
|
||||||
import "frameworks/proto_logging/stats/atom_field_options.proto";
|
|
||||||
|
|
||||||
package android.stats_log_api_gen;
|
|
||||||
|
|
||||||
message IntAtom {
|
|
||||||
optional int32 field1 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message AnotherIntAtom {
|
|
||||||
optional int32 field1 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message OutOfOrderAtom {
|
|
||||||
optional int32 field2 = 2;
|
|
||||||
optional int32 field1 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnEnum {
|
|
||||||
VALUE0 = 0;
|
|
||||||
VALUE1 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message AllTypesAtom {
|
|
||||||
repeated android.os.statsd.AttributionNode attribution_chain = 1;
|
|
||||||
optional float float_field = 2;
|
|
||||||
optional int64 int64_field = 3;
|
|
||||||
optional uint64 uint64_field = 4;
|
|
||||||
optional int32 int32_field = 5;
|
|
||||||
optional fixed64 fixed64_field = 6;
|
|
||||||
optional fixed32 fixed32_field = 7;
|
|
||||||
optional bool bool_field = 8;
|
|
||||||
optional string string_field = 9;
|
|
||||||
optional uint32 uint32_field = 10;
|
|
||||||
optional AnEnum enum_field = 11;
|
|
||||||
optional sfixed32 sfixed32_field = 12;
|
|
||||||
optional sfixed64 sfixed64_field = 13;
|
|
||||||
optional sint32 sint32_field = 14;
|
|
||||||
optional sint64 sint64_field = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Event {
|
|
||||||
oneof event {
|
|
||||||
OutOfOrderAtom out_of_order_atom = 2;
|
|
||||||
IntAtom int_atom = 1;
|
|
||||||
AnotherIntAtom another_int_atom = 3;
|
|
||||||
AllTypesAtom all_types_atom = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadTypesAtom {
|
|
||||||
optional IntAtom bad_int_atom = 1;
|
|
||||||
optional bytes bad_bytes = 2;
|
|
||||||
repeated int32 repeated_field = 3;
|
|
||||||
optional double double_field = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadTypesEvent {
|
|
||||||
oneof event {
|
|
||||||
BadTypesAtom bad_types_atom = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadSkippedFieldSingleAtom {
|
|
||||||
optional int32 field2 = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadSkippedFieldSingle {
|
|
||||||
oneof event {
|
|
||||||
BadSkippedFieldSingleAtom bad = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadSkippedFieldMultipleAtom {
|
|
||||||
optional int32 field1 = 1;
|
|
||||||
optional int32 field3 = 3;
|
|
||||||
optional int32 field5 = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadSkippedFieldMultiple {
|
|
||||||
oneof event {
|
|
||||||
BadSkippedFieldMultipleAtom bad = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message BadAttributionNodePositionAtom {
|
|
||||||
optional int32 field1 = 1;
|
|
||||||
repeated android.os.statsd.AttributionNode attribution = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
BadStateAtom2 bad2 = 2;
|
|
||||||
BadStateAtom3 bad3 = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message GoodStateAtoms {
|
|
||||||
oneof event {
|
|
||||||
GoodStateAtom1 good1 = 1;
|
|
||||||
GoodStateAtom2 good2 = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The atom has only primary field but no exclusive state field.
|
|
||||||
message BadStateAtom1 {
|
|
||||||
optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only primative types can be annotated.
|
|
||||||
message BadStateAtom2 {
|
|
||||||
repeated android.os.statsd.AttributionNode attribution = 1
|
|
||||||
[(android.os.statsd.state_field_option).primary_field = true];
|
|
||||||
optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Having 2 exclusive state field in the atom means the atom is badly designed.
|
|
||||||
// E.g., putting bluetooth state and wifi state in the same atom.
|
|
||||||
message BadStateAtom3 {
|
|
||||||
optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
|
|
||||||
optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
optional int32 state2 = 3 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
message GoodStateAtom1 {
|
|
||||||
optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
|
|
||||||
optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atoms can have exclusive state field, but no primary field. That means
|
|
||||||
// the state is globally exclusive (e.g., DisplayState).
|
|
||||||
message GoodStateAtom2 {
|
|
||||||
optional int32 uid = 1;
|
|
||||||
optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can have more than one primary fields. That means their combination is a
|
|
||||||
// primary key.
|
|
||||||
message GoodStateAtom3 {
|
|
||||||
optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
|
|
||||||
optional int32 tid = 2 [(android.os.statsd.state_field_option).primary_field = true];
|
|
||||||
optional int32 state = 3 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
message ModuleOneAtom {
|
|
||||||
optional int32 field = 1 [(android.os.statsd.is_uid) = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
message ModuleTwoAtom {
|
|
||||||
optional int32 field = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ModuleOneAndTwoAtom {
|
|
||||||
optional int32 field = 1 [(android.os.statsd.state_field_option).exclusive_state = true];
|
|
||||||
}
|
|
||||||
|
|
||||||
message NoModuleAtom {
|
|
||||||
optional string field = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ModuleAtoms {
|
|
||||||
oneof event {
|
|
||||||
ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
|
|
||||||
ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
|
|
||||||
ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
|
|
||||||
(android.os.statsd.module) = "module1", (android.os.statsd.module) = "module2"
|
|
||||||
];
|
|
||||||
NoModuleAtom no_module_atom = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,369 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using std::map;
|
|
||||||
using std::set;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return whether the map contains a vector of the elements provided.
|
|
||||||
*/
|
|
||||||
static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) {
|
|
||||||
va_list args;
|
|
||||||
vector<java_type_t> v;
|
|
||||||
|
|
||||||
va_start(args, count);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
v.push_back((java_type_t)va_arg(args, int));
|
|
||||||
}
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return s.find(v) != s.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expect that the provided map contains the elements provided.
|
|
||||||
*/
|
|
||||||
#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \
|
|
||||||
do { \
|
|
||||||
int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int); \
|
|
||||||
EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/** Expects that the provided atom has no enum values for any field. */
|
|
||||||
#define EXPECT_NO_ENUM_FIELD(atom) \
|
|
||||||
do { \
|
|
||||||
for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
|
|
||||||
field != atom->fields.end(); field++) { \
|
|
||||||
EXPECT_TRUE(field->enumValues.empty()); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/** 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(); \
|
|
||||||
field != atom->fields.end(); field++) { \
|
|
||||||
if (field->name == field_name) { \
|
|
||||||
EXPECT_EQ(field->enumValues, values); \
|
|
||||||
} else { \
|
|
||||||
EXPECT_TRUE(field->enumValues.empty()); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test a correct collation, with all the types.
|
|
||||||
*/
|
|
||||||
TEST(CollationTest, CollateStats) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(Event::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(0, errorCount);
|
|
||||||
EXPECT_EQ(3ul, atoms.signatureInfoMap.size());
|
|
||||||
|
|
||||||
// IntAtom, AnotherIntAtom
|
|
||||||
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
|
|
||||||
|
|
||||||
// OutOfOrderAtom
|
|
||||||
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
|
|
||||||
|
|
||||||
// AllTypesAtom
|
|
||||||
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap,
|
|
||||||
JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
|
|
||||||
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_EQ(4ul, atoms.decls.size());
|
|
||||||
|
|
||||||
AtomDeclSet::const_iterator atomIt = atoms.decls.begin();
|
|
||||||
EXPECT_EQ(1, (*atomIt)->code);
|
|
||||||
EXPECT_EQ("int_atom", (*atomIt)->name);
|
|
||||||
EXPECT_EQ("IntAtom", (*atomIt)->message);
|
|
||||||
EXPECT_NO_ENUM_FIELD((*atomIt));
|
|
||||||
atomIt++;
|
|
||||||
|
|
||||||
EXPECT_EQ(2, (*atomIt)->code);
|
|
||||||
EXPECT_EQ("out_of_order_atom", (*atomIt)->name);
|
|
||||||
EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message);
|
|
||||||
EXPECT_NO_ENUM_FIELD((*atomIt));
|
|
||||||
atomIt++;
|
|
||||||
|
|
||||||
EXPECT_EQ(3, (*atomIt)->code);
|
|
||||||
EXPECT_EQ("another_int_atom", (*atomIt)->name);
|
|
||||||
EXPECT_EQ("AnotherIntAtom", (*atomIt)->message);
|
|
||||||
EXPECT_NO_ENUM_FIELD((*atomIt));
|
|
||||||
atomIt++;
|
|
||||||
|
|
||||||
EXPECT_EQ(4, (*atomIt)->code);
|
|
||||||
EXPECT_EQ("all_types_atom", (*atomIt)->name);
|
|
||||||
EXPECT_EQ("AllTypesAtom", (*atomIt)->message);
|
|
||||||
map<int, string> enumValues;
|
|
||||||
enumValues[0] = "VALUE0";
|
|
||||||
enumValues[1] = "VALUE1";
|
|
||||||
EXPECT_HAS_ENUM_FIELD((*atomIt), "enum_field", enumValues);
|
|
||||||
atomIt++;
|
|
||||||
|
|
||||||
EXPECT_EQ(atoms.decls.end(), atomIt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that event class that contains stuff other than the atoms is rejected.
|
|
||||||
*/
|
|
||||||
TEST(CollationTest, NonMessageTypeFails) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(IntAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(1, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that atoms that have non-primitive types or repeated fields are
|
|
||||||
* rejected.
|
|
||||||
*/
|
|
||||||
TEST(CollationTest, FailOnBadTypes) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(BadTypesEvent::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(4, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that atoms that skip field numbers (in the first position) are rejected.
|
|
||||||
*/
|
|
||||||
TEST(CollationTest, FailOnSkippedFieldsSingle) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount =
|
|
||||||
collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(1, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that atoms that skip field numbers (not in the first position, and
|
|
||||||
* multiple times) are rejected.
|
|
||||||
*/
|
|
||||||
TEST(CollationTest, FailOnSkippedFieldsMultiple) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount =
|
|
||||||
collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(2, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that atoms that have an attribution chain not in the first position are
|
|
||||||
* rejected.
|
|
||||||
*/
|
|
||||||
TEST(CollationTest, FailBadAttributionNodePosition) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount =
|
|
||||||
collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(1, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, FailOnBadStateAtomOptions) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(BadStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
|
|
||||||
EXPECT_EQ(3, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, PassOnGoodStateAtomOptions) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(GoodStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
EXPECT_EQ(0, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, PassOnGoodBinaryFieldAtom) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount =
|
|
||||||
collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
EXPECT_EQ(0, errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, FailOnBadBinaryFieldAtom) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount =
|
|
||||||
collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
EXPECT_TRUE(errorCount > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, PassOnLogFromModuleAtom) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
EXPECT_EQ(errorCount, 0);
|
|
||||||
EXPECT_EQ(atoms.decls.size(), 4ul);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, RecognizeModuleAtom) {
|
|
||||||
Atoms atoms;
|
|
||||||
int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
|
|
||||||
EXPECT_EQ(errorCount, 0);
|
|
||||||
EXPECT_EQ(atoms.decls.size(), 4ul);
|
|
||||||
EXPECT_EQ(atoms.signatureInfoMap.size(), 2u);
|
|
||||||
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
|
|
||||||
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_STRING);
|
|
||||||
|
|
||||||
SignatureInfoMap::const_iterator signatureInfoMapIt;
|
|
||||||
const vector<java_type_t>* signature;
|
|
||||||
const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet;
|
|
||||||
FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt;
|
|
||||||
const AtomDeclSet* atomDeclSet;
|
|
||||||
AtomDeclSet::const_iterator atomDeclSetIt;
|
|
||||||
AtomDecl* atomDecl;
|
|
||||||
FieldNumberToAnnotations* fieldNumberToAnnotations;
|
|
||||||
FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt;
|
|
||||||
const AnnotationSet* annotationSet;
|
|
||||||
AnnotationSet::const_iterator annotationSetIt;
|
|
||||||
Annotation* annotation;
|
|
||||||
|
|
||||||
signatureInfoMapIt = atoms.signatureInfoMap.begin();
|
|
||||||
signature = &(signatureInfoMapIt->first);
|
|
||||||
fieldNumberToAtomDeclSet = &signatureInfoMapIt->second;
|
|
||||||
EXPECT_EQ(1ul, signature->size());
|
|
||||||
EXPECT_EQ(JAVA_TYPE_INT, signature->at(0));
|
|
||||||
EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size());
|
|
||||||
fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin();
|
|
||||||
EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first);
|
|
||||||
atomDeclSet = &fieldNumberToAtomDeclSetIt->second;
|
|
||||||
EXPECT_EQ(2ul, atomDeclSet->size());
|
|
||||||
atomDeclSetIt = atomDeclSet->begin();
|
|
||||||
atomDecl = atomDeclSetIt->get();
|
|
||||||
EXPECT_EQ(1, atomDecl->code);
|
|
||||||
fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
|
|
||||||
fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
|
|
||||||
EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
|
|
||||||
annotationSet = &fieldNumberToAnnotationsIt->second;
|
|
||||||
EXPECT_EQ(1ul, annotationSet->size());
|
|
||||||
annotationSetIt = annotationSet->begin();
|
|
||||||
annotation = annotationSetIt->get();
|
|
||||||
EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId);
|
|
||||||
EXPECT_EQ(1, annotation->atomId);
|
|
||||||
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
|
|
||||||
EXPECT_TRUE(annotation->value.boolValue);
|
|
||||||
|
|
||||||
atomDeclSetIt++;
|
|
||||||
atomDecl = atomDeclSetIt->get();
|
|
||||||
EXPECT_EQ(3, atomDecl->code);
|
|
||||||
fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
|
|
||||||
fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
|
|
||||||
EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
|
|
||||||
annotationSet = &fieldNumberToAnnotationsIt->second;
|
|
||||||
EXPECT_EQ(1ul, annotationSet->size());
|
|
||||||
annotationSetIt = annotationSet->begin();
|
|
||||||
annotation = annotationSetIt->get();
|
|
||||||
EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId);
|
|
||||||
EXPECT_EQ(3, annotation->atomId);
|
|
||||||
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
|
|
||||||
EXPECT_TRUE(annotation->value.boolValue);
|
|
||||||
|
|
||||||
signatureInfoMapIt++;
|
|
||||||
signature = &signatureInfoMapIt->first;
|
|
||||||
fieldNumberToAtomDeclSet = &signatureInfoMapIt->second;
|
|
||||||
EXPECT_EQ(1ul, signature->size());
|
|
||||||
EXPECT_EQ(JAVA_TYPE_STRING, signature->at(0));
|
|
||||||
EXPECT_EQ(0ul, fieldNumberToAtomDeclSet->size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CollationTest, RecognizeModule1Atom) {
|
|
||||||
Atoms atoms;
|
|
||||||
const string moduleName = "module1";
|
|
||||||
int errorCount = collate_atoms(ModuleAtoms::descriptor(), moduleName, &atoms);
|
|
||||||
EXPECT_EQ(errorCount, 0);
|
|
||||||
EXPECT_EQ(atoms.decls.size(), 2ul);
|
|
||||||
EXPECT_EQ(atoms.signatureInfoMap.size(), 1u);
|
|
||||||
EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
|
|
||||||
|
|
||||||
SignatureInfoMap::const_iterator signatureInfoMapIt;
|
|
||||||
const vector<java_type_t>* signature;
|
|
||||||
const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet;
|
|
||||||
FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt;
|
|
||||||
const AtomDeclSet* atomDeclSet;
|
|
||||||
AtomDeclSet::const_iterator atomDeclSetIt;
|
|
||||||
AtomDecl* atomDecl;
|
|
||||||
FieldNumberToAnnotations* fieldNumberToAnnotations;
|
|
||||||
FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt;
|
|
||||||
const AnnotationSet* annotationSet;
|
|
||||||
AnnotationSet::const_iterator annotationSetIt;
|
|
||||||
Annotation* annotation;
|
|
||||||
|
|
||||||
signatureInfoMapIt = atoms.signatureInfoMap.begin();
|
|
||||||
signature = &(signatureInfoMapIt->first);
|
|
||||||
fieldNumberToAtomDeclSet = &signatureInfoMapIt->second;
|
|
||||||
EXPECT_EQ(1ul, signature->size());
|
|
||||||
EXPECT_EQ(JAVA_TYPE_INT, signature->at(0));
|
|
||||||
EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size());
|
|
||||||
fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin();
|
|
||||||
EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first);
|
|
||||||
atomDeclSet = &fieldNumberToAtomDeclSetIt->second;
|
|
||||||
EXPECT_EQ(2ul, atomDeclSet->size());
|
|
||||||
atomDeclSetIt = atomDeclSet->begin();
|
|
||||||
atomDecl = atomDeclSetIt->get();
|
|
||||||
EXPECT_EQ(1, atomDecl->code);
|
|
||||||
fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
|
|
||||||
fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
|
|
||||||
EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
|
|
||||||
annotationSet = &fieldNumberToAnnotationsIt->second;
|
|
||||||
EXPECT_EQ(1ul, annotationSet->size());
|
|
||||||
annotationSetIt = annotationSet->begin();
|
|
||||||
annotation = annotationSetIt->get();
|
|
||||||
EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId);
|
|
||||||
EXPECT_EQ(1, annotation->atomId);
|
|
||||||
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
|
|
||||||
EXPECT_TRUE(annotation->value.boolValue);
|
|
||||||
|
|
||||||
atomDeclSetIt++;
|
|
||||||
atomDecl = atomDeclSetIt->get();
|
|
||||||
EXPECT_EQ(3, atomDecl->code);
|
|
||||||
fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
|
|
||||||
fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
|
|
||||||
EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
|
|
||||||
annotationSet = &fieldNumberToAnnotationsIt->second;
|
|
||||||
EXPECT_EQ(1ul, annotationSet->size());
|
|
||||||
annotationSetIt = annotationSet->begin();
|
|
||||||
annotation = annotationSetIt->get();
|
|
||||||
EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId);
|
|
||||||
EXPECT_EQ(3, annotation->atomId);
|
|
||||||
EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
|
|
||||||
EXPECT_TRUE(annotation->value.boolValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#include "android-base/strings.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
static void build_non_chained_decl_map(const Atoms& atoms,
|
|
||||||
std::map<int, AtomDeclSet::const_iterator>* decl_map) {
|
|
||||||
for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin();
|
|
||||||
atomIt != atoms.non_chained_decls.end(); atomIt++) {
|
|
||||||
decl_map->insert(std::make_pair((*atomIt)->code, atomIt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn lower and camel case into upper case with underscores.
|
|
||||||
*/
|
|
||||||
string make_constant_name(const string& str) {
|
|
||||||
string result;
|
|
||||||
const int N = str.size();
|
|
||||||
bool underscore_next = false;
|
|
||||||
for (int i = 0; i < N; i++) {
|
|
||||||
char c = str[i];
|
|
||||||
if (c >= 'A' && c <= 'Z') {
|
|
||||||
if (underscore_next) {
|
|
||||||
result += '_';
|
|
||||||
underscore_next = false;
|
|
||||||
}
|
|
||||||
} else if (c >= 'a' && c <= 'z') {
|
|
||||||
c = 'A' + c - 'a';
|
|
||||||
underscore_next = true;
|
|
||||||
} else if (c == '_') {
|
|
||||||
underscore_next = false;
|
|
||||||
}
|
|
||||||
result += c;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* cpp_type_name(java_type_t type) {
|
|
||||||
switch (type) {
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
return "bool";
|
|
||||||
case JAVA_TYPE_INT:
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
return "int32_t";
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
return "int64_t";
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
return "float";
|
|
||||||
case JAVA_TYPE_DOUBLE:
|
|
||||||
return "double";
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
return "char const*";
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
return "const BytesField&";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* java_type_name(java_type_t type) {
|
|
||||||
switch (type) {
|
|
||||||
case JAVA_TYPE_BOOLEAN:
|
|
||||||
return "boolean";
|
|
||||||
case JAVA_TYPE_INT:
|
|
||||||
case JAVA_TYPE_ENUM:
|
|
||||||
return "int";
|
|
||||||
case JAVA_TYPE_LONG:
|
|
||||||
return "long";
|
|
||||||
case JAVA_TYPE_FLOAT:
|
|
||||||
return "float";
|
|
||||||
case JAVA_TYPE_DOUBLE:
|
|
||||||
return "double";
|
|
||||||
case JAVA_TYPE_STRING:
|
|
||||||
return "java.lang.String";
|
|
||||||
case JAVA_TYPE_BYTE_ARRAY:
|
|
||||||
return "byte[]";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Native
|
|
||||||
// Writes namespaces for the cpp and header files, returning the number of
|
|
||||||
// namespaces written.
|
|
||||||
void write_namespace(FILE* out, const string& cppNamespaces) {
|
|
||||||
vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
|
|
||||||
for (string cppNamespace : cppNamespaceVec) {
|
|
||||||
fprintf(out, "namespace %s {\n", cppNamespace.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes namespace closing brackets for cpp and header files.
|
|
||||||
void write_closing_namespace(FILE* out, const string& cppNamespaces) {
|
|
||||||
vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
|
|
||||||
for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
|
|
||||||
fprintf(out, "} // namespace %s\n", it->c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
|
|
||||||
const shared_ptr<AtomDecl> atom, const AtomDecl& attributionDecl) {
|
|
||||||
fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
|
|
||||||
|
|
||||||
for (vector<AtomField>::const_iterator field = atom->fields.begin();
|
|
||||||
field != atom->fields.end(); field++) {
|
|
||||||
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 if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(out,
|
|
||||||
", const std::map<int, int32_t>& %s_int"
|
|
||||||
", const std::map<int, int64_t>& %s_long"
|
|
||||||
", const std::map<int, char const*>& %s_str"
|
|
||||||
", const std::map<int, float>& %s_float",
|
|
||||||
field->name.c_str(), field->name.c_str(), field->name.c_str(),
|
|
||||||
field->name.c_str());
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(out, ");\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl) {
|
|
||||||
fprintf(out, "/**\n");
|
|
||||||
fprintf(out, " * Constants for atom codes.\n");
|
|
||||||
fprintf(out, " */\n");
|
|
||||||
fprintf(out, "enum {\n");
|
|
||||||
|
|
||||||
std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
|
|
||||||
build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
// Print atom constants
|
|
||||||
for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
|
|
||||||
atomIt++) {
|
|
||||||
string constant = make_constant_name((*atomIt)->name);
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, " /**\n");
|
|
||||||
fprintf(out, " * %s %s\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
|
|
||||||
write_cpp_usage(out, "stats_write", constant, *atomIt, attributionDecl);
|
|
||||||
|
|
||||||
auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
|
|
||||||
if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
|
|
||||||
write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
|
|
||||||
attributionDecl);
|
|
||||||
}
|
|
||||||
fprintf(out, " */\n");
|
|
||||||
char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
|
|
||||||
fprintf(out, " %s = %d%s\n", constant.c_str(), (*atomIt)->code, comma);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "};\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_native_method_signature(FILE* out, const string& methodName,
|
|
||||||
const vector<java_type_t>& signature,
|
|
||||||
const AtomDecl& attributionDecl, const string& closer) {
|
|
||||||
fprintf(out, "%s(int32_t code", methodName.c_str());
|
|
||||||
int argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); 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 if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(out,
|
|
||||||
", const std::map<int, int32_t>& arg%d_1, "
|
|
||||||
"const std::map<int, int64_t>& arg%d_2, "
|
|
||||||
"const std::map<int, char const*>& arg%d_3, "
|
|
||||||
"const std::map<int, float>& arg%d_4",
|
|
||||||
argIndex, argIndex, argIndex, argIndex);
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ")%s\n", closer.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_native_method_call(FILE* out, const string& methodName,
|
|
||||||
const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
|
|
||||||
int argIndex) {
|
|
||||||
fprintf(out, "%s(code", methodName.c_str());
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
for (auto chainField : attributionDecl.fields) {
|
|
||||||
if (chainField.javaType == JAVA_TYPE_STRING) {
|
|
||||||
fprintf(out, ", %s", chainField.name.c_str());
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s, %s_length", chainField.name.c_str(),
|
|
||||||
chainField.name.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, argIndex, argIndex,
|
|
||||||
argIndex);
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", arg%d", argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ");\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Java
|
|
||||||
void write_java_atom_codes(FILE* out, const Atoms& atoms) {
|
|
||||||
fprintf(out, " // Constants for atom codes.\n");
|
|
||||||
|
|
||||||
std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
|
|
||||||
build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
|
|
||||||
|
|
||||||
// Print constants for the atom codes.
|
|
||||||
for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
|
|
||||||
atomIt++) {
|
|
||||||
string constant = make_constant_name((*atomIt)->name);
|
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, " /**\n");
|
|
||||||
fprintf(out, " * %s %s<br>\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
|
|
||||||
write_java_usage(out, "write", constant, **atomIt);
|
|
||||||
auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
|
|
||||||
if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
|
|
||||||
write_java_usage(out, "write_non_chained", constant, **(non_chained_decl->second));
|
|
||||||
}
|
|
||||||
fprintf(out, " */\n");
|
|
||||||
fprintf(out, " public static final int %s = %d;\n", constant.c_str(), (*atomIt)->code);
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_java_enum_values(FILE* out, const Atoms& atoms) {
|
|
||||||
fprintf(out, " // Constants for enum values.\n\n");
|
|
||||||
for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
|
|
||||||
atomIt++) {
|
|
||||||
for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
|
|
||||||
field != (*atomIt)->fields.end(); field++) {
|
|
||||||
if (field->javaType == JAVA_TYPE_ENUM) {
|
|
||||||
fprintf(out, " // Values for %s.%s\n", (*atomIt)->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((*atomIt)->message).c_str(),
|
|
||||||
make_constant_name(field->name).c_str(),
|
|
||||||
make_constant_name(value->second).c_str(), value->first);
|
|
||||||
}
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
|
|
||||||
const AtomDecl& atom) {
|
|
||||||
fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(),
|
|
||||||
atom_code_name.c_str());
|
|
||||||
for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
|
|
||||||
field++) {
|
|
||||||
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
fprintf(out, ", android.os.WorkSource workSource");
|
|
||||||
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(out, ", android.util.SparseArray<Object> value_map");
|
|
||||||
} 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(out, ");<br>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) {
|
|
||||||
for (auto signatureInfoMapIt = signatureInfoMap.begin();
|
|
||||||
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
|
|
||||||
// Print method signature.
|
|
||||||
fprintf(out, " public static void write_non_chained(int code");
|
|
||||||
vector<java_type_t> signature = signatureInfoMapIt->first;
|
|
||||||
int argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
fprintf(stderr, "Non chained signatures should not have attribution chains.\n");
|
|
||||||
return 1;
|
|
||||||
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
|
|
||||||
fprintf(stderr, "Module logging does not yet support key value pair.\n");
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ") {\n");
|
|
||||||
|
|
||||||
fprintf(out, " write(code");
|
|
||||||
argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
// First two args are uid and tag of attribution chain.
|
|
||||||
if (argIndex == 1) {
|
|
||||||
fprintf(out, ", new int[] {arg%d}", argIndex);
|
|
||||||
} else if (argIndex == 2) {
|
|
||||||
fprintf(out, ", new java.lang.String[] {arg%d}", argIndex);
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", arg%d", argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ");\n");
|
|
||||||
fprintf(out, " }\n");
|
|
||||||
fprintf(out, "\n");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) {
|
|
||||||
fprintf(out, " // WorkSource methods.\n");
|
|
||||||
for (auto signatureInfoMapIt = signatureInfoMap.begin();
|
|
||||||
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
|
|
||||||
vector<java_type_t> signature = signatureInfoMapIt->first;
|
|
||||||
// Determine if there is Attribution in this signature.
|
|
||||||
int attributionArg = -1;
|
|
||||||
int argIndexMax = 0;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
argIndexMax++;
|
|
||||||
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
if (attributionArg > -1) {
|
|
||||||
fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
|
|
||||||
fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
|
|
||||||
fprintf(out,
|
|
||||||
"\n// Invalid for WorkSource: more than one attribution "
|
|
||||||
"chain.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
attributionArg = argIndexMax;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (attributionArg < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(out, "\n");
|
|
||||||
// Method header (signature)
|
|
||||||
fprintf(out, " public static void write(int code");
|
|
||||||
int argIndex = 1;
|
|
||||||
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
|
|
||||||
arg++) {
|
|
||||||
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
|
|
||||||
fprintf(out, ", android.os.WorkSource ws");
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
|
|
||||||
}
|
|
||||||
argIndex++;
|
|
||||||
}
|
|
||||||
fprintf(out, ") {\n");
|
|
||||||
|
|
||||||
// write_non_chained() component. TODO: Remove when flat uids are no longer
|
|
||||||
// needed.
|
|
||||||
fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
|
|
||||||
fprintf(out, " write_non_chained(code");
|
|
||||||
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
|
|
||||||
if (argIndex == attributionArg) {
|
|
||||||
fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", arg%d", argIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(out, ");\n");
|
|
||||||
fprintf(out, " }\n"); // close for-loop
|
|
||||||
|
|
||||||
// write() component.
|
|
||||||
fprintf(out,
|
|
||||||
" java.util.List<android.os.WorkSource.WorkChain> workChains = "
|
|
||||||
"ws.getWorkChains();\n");
|
|
||||||
fprintf(out, " if (workChains != null) {\n");
|
|
||||||
fprintf(out,
|
|
||||||
" for (android.os.WorkSource.WorkChain wc : workChains) "
|
|
||||||
"{\n");
|
|
||||||
fprintf(out, " write(code");
|
|
||||||
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
|
|
||||||
if (argIndex == attributionArg) {
|
|
||||||
fprintf(out, ", wc.getUids(), wc.getTags()");
|
|
||||||
} else {
|
|
||||||
fprintf(out, ", arg%d", argIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(out, ");\n");
|
|
||||||
fprintf(out, " }\n"); // close for-loop
|
|
||||||
fprintf(out, " }\n"); // close if
|
|
||||||
fprintf(out, " }\n"); // close method
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2019, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Collation.h"
|
|
||||||
|
|
||||||
namespace android {
|
|
||||||
namespace stats_log_api_gen {
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
const string DEFAULT_CPP_NAMESPACE = "android,util";
|
|
||||||
const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
|
|
||||||
|
|
||||||
const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
|
|
||||||
const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
|
|
||||||
const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04;
|
|
||||||
|
|
||||||
const map<AnnotationId, string> ANNOTATION_ID_CONSTANTS = {
|
|
||||||
{ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
|
|
||||||
{ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
|
|
||||||
{ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
|
|
||||||
{ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
|
|
||||||
{ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
|
|
||||||
{ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
|
|
||||||
{ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
|
|
||||||
|
|
||||||
string make_constant_name(const string& str);
|
|
||||||
|
|
||||||
const char* cpp_type_name(java_type_t type);
|
|
||||||
|
|
||||||
const char* java_type_name(java_type_t type);
|
|
||||||
|
|
||||||
// Common Native helpers
|
|
||||||
void write_namespace(FILE* out, const string& cppNamespaces);
|
|
||||||
|
|
||||||
void write_closing_namespace(FILE* out, const string& cppNamespaces);
|
|
||||||
|
|
||||||
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
|
|
||||||
|
|
||||||
void write_native_method_signature(FILE* out, const string& methodName,
|
|
||||||
const vector<java_type_t>& signature,
|
|
||||||
const AtomDecl& attributionDecl, const string& closer);
|
|
||||||
|
|
||||||
void write_native_method_call(FILE* out, const string& methodName,
|
|
||||||
const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
|
|
||||||
int argIndex = 1);
|
|
||||||
|
|
||||||
// Common Java helpers.
|
|
||||||
void write_java_atom_codes(FILE* out, const Atoms& atoms);
|
|
||||||
|
|
||||||
void write_java_enum_values(FILE* out, const Atoms& atoms);
|
|
||||||
|
|
||||||
void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
|
|
||||||
const AtomDecl& atom);
|
|
||||||
|
|
||||||
int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap);
|
|
||||||
|
|
||||||
int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap);
|
|
||||||
|
|
||||||
} // namespace stats_log_api_gen
|
|
||||||
} // namespace android
|
|
||||||
Reference in New Issue
Block a user