Structured parcelables.
Example:
parcelable StructuredParcelable {
int[] shouldContainThreeFs;
int f;
@utf8InCpp String shouldBeJerry;
}
Bug: 110758329
Test: runtests.sh
Change-Id: I4af2317fba33a0024f354828ad0b310bf8fe8752
diff --git a/Android.bp b/Android.bp
index 78207e5..95809a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -166,6 +166,7 @@
srcs: [
"tests/android/aidl/tests/ITestService.aidl",
"tests/android/aidl/tests/INamedCallback.aidl",
+ "tests/android/aidl/tests/StructuredParcelable.aidl",
"tests/simple_parcelable.cpp",
],
}
@@ -208,6 +209,7 @@
srcs: [
"tests/android/aidl/tests/INamedCallback.aidl",
"tests/android/aidl/tests/ITestService.aidl",
+ "tests/android/aidl/tests/StructuredParcelable.aidl",
"tests/java_app/src/android/aidl/tests/NullableTests.java",
"tests/java_app/src/android/aidl/tests/SimpleParcelable.java",
"tests/java_app/src/android/aidl/tests/TestFailException.java",
diff --git a/aidl.cpp b/aidl.cpp
index 5cc186f..48f72e6 100644
--- a/aidl.cpp
+++ b/aidl.cpp
@@ -170,6 +170,25 @@
return success;
}
+int check_types(const string& filename, const AidlStructuredParcelable* parcel,
+ TypeNamespace* types) {
+ int err = 0;
+ for (const auto& v : parcel->GetFields()) {
+ if (!types->MaybeAddContainerType(v->GetType())) {
+ err = 1; // return type is invalid
+ }
+
+ const ValidatableType* type = types->GetReturnType(v->GetType(), filename, *parcel);
+ if (!type) {
+ err = 1;
+ }
+
+ v->GetMutableType()->SetLanguageType(type);
+ }
+
+ return err;
+}
+
int check_types(const string& filename,
const AidlInterface* c,
TypeNamespace* types) {
@@ -290,8 +309,7 @@
return true;
}
-bool write_cpp_dep_file(const CppOptions& options,
- const AidlInterface& interface,
+bool write_cpp_dep_file(const CppOptions& options, const AidlDefinedType& defined_type,
const vector<unique_ptr<AidlImport>>& imports,
const IoDelegate& io_delegate) {
using ::android::aidl::cpp::HeaderFile;
@@ -323,7 +341,7 @@
ClassNames::SERVER,
ClassNames::INTERFACE}) {
headers.push_back(options.OutputHeaderDir() + '/' +
- HeaderFile(interface, c, false /* use_os_sep */));
+ HeaderFile(defined_type, c, false /* use_os_sep */));
}
writer->Write("\n");
@@ -336,33 +354,32 @@
return true;
}
-string generate_outputFileName(const JavaOptions& options,
- const AidlInterface& interface) {
- const string& name = interface.GetName();
- string package = interface.GetPackage();
- string result;
+string generate_outputFileName(const JavaOptions& options, const AidlDefinedType& defined_type) {
+ const string& name = defined_type.GetName();
+ string package = defined_type.GetPackage();
+ string result;
- // create the path to the destination folder based on the
- // interface package name
- result = options.output_base_folder_;
- result += OS_PATH_SEPARATOR;
+ // create the path to the destination folder based on the
+ // defined_type package name
+ result = options.output_base_folder_;
+ result += OS_PATH_SEPARATOR;
- string packageStr = package;
- size_t len = packageStr.length();
- for (size_t i=0; i<len; i++) {
- if (packageStr[i] == '.') {
- packageStr[i] = OS_PATH_SEPARATOR;
- }
+ string packageStr = package;
+ size_t len = packageStr.length();
+ for (size_t i = 0; i < len; i++) {
+ if (packageStr[i] == '.') {
+ packageStr[i] = OS_PATH_SEPARATOR;
}
+ }
- result += packageStr;
+ result += packageStr;
- // add the filename by replacing the .aidl extension to .java
- result += OS_PATH_SEPARATOR;
- result.append(name, 0, name.find('.'));
- result += ".java";
+ // add the filename by replacing the .aidl extension to .java
+ result += OS_PATH_SEPARATOR;
+ result.append(name, 0, name.find('.'));
+ result += ".java";
- return result;
+ return result;
}
int check_and_assign_method_ids(const char * filename,
@@ -543,15 +560,12 @@
return success;
}
-AidlError load_and_validate_aidl(
- const std::vector<std::string>& preprocessed_files,
- const std::vector<std::string>& import_paths,
- const std::string& input_file_name,
- const bool generate_traces,
- const IoDelegate& io_delegate,
- TypeNamespace* types,
- std::unique_ptr<AidlInterface>* returned_interface,
- std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
+AidlError load_and_validate_aidl(const std::vector<std::string>& preprocessed_files,
+ const std::vector<std::string>& import_paths,
+ const std::string& input_file_name, const bool generate_traces,
+ const IoDelegate& io_delegate, TypeNamespace* types,
+ std::unique_ptr<AidlDefinedType>* returned_type,
+ std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
AidlError err = AidlError::OK;
std::map<AidlImport*,std::unique_ptr<AidlDocument>> docs;
@@ -575,18 +589,23 @@
AidlDocument* parsed_doc = p.GetDocument();
unique_ptr<AidlInterface> interface(parsed_doc->ReleaseInterface());
+ unique_ptr<AidlStructuredParcelable> parcelable(parsed_doc->ReleaseStructuredParcelable());
- if (!interface) {
- LOG(ERROR) << "refusing to generate code from aidl file defining "
- "parcelable";
+ CHECK(interface == nullptr || parcelable == nullptr); // grammar invariant
+
+ AidlDefinedType* defined_type = interface.get();
+ if (defined_type == nullptr) defined_type = parcelable.get();
+
+ if (!defined_type) {
+ LOG(ERROR)
+ << "cannot generate code from aidl file w/o either one interface or structured parcelable";
return AidlError::FOUND_PARCELABLE;
}
- if (!check_filename(input_file_name.c_str(), interface->GetPackage(),
- interface->GetName(), interface->GetLine()) ||
- !types->IsValidPackage(interface->GetPackage())) {
- LOG(ERROR) << "Invalid package declaration '" << interface->GetPackage()
- << "'";
+ if (!check_filename(input_file_name.c_str(), defined_type->GetPackage(), defined_type->GetName(),
+ defined_type->GetLine()) ||
+ !types->IsValidPackage(defined_type->GetPackage())) {
+ LOG(ERROR) << "Invalid package declaration '" << defined_type->GetPackage() << "'";
return AidlError::BAD_PACKAGE;
}
@@ -626,14 +645,22 @@
return err;
}
- // gather the types that have been declared
- if (!types->AddBinderType(*interface.get(), input_file_name)) {
- err = AidlError::BAD_TYPE;
+ if (interface) {
+ // gather the types that have been declared
+ if (!types->AddBinderType(*interface.get(), input_file_name)) {
+ err = AidlError::BAD_TYPE;
+ }
+
+ interface->SetGenerateTraces(generate_traces);
}
- interface->SetLanguageType(types->GetInterfaceType(*interface));
+ if (parcelable) {
+ if (!types->AddParcelableType(*parcelable.get(), input_file_name)) {
+ err = AidlError::BAD_TYPE;
+ }
+ }
- interface->SetGenerateTraces(generate_traces);
+ defined_type->SetLanguageType(types->GetDefinedType(*defined_type));
for (const auto& import : p.GetImports()) {
// If we skipped an unresolved import above (see comment there) we'll have
@@ -649,25 +676,27 @@
}
// check the referenced types in parsed_doc to make sure we've imported them
- if (check_types(input_file_name, interface.get(), types) != 0) {
+ if (interface && check_types(input_file_name, interface.get(), types) != 0) {
+ err = AidlError::BAD_TYPE;
+ }
+ if (parcelable && check_types(input_file_name, parcelable.get(), types) != 0) {
err = AidlError::BAD_TYPE;
}
if (err != AidlError::OK) {
return err;
}
-
// assign method ids and validate.
- if (check_and_assign_method_ids(input_file_name.c_str(),
- interface->GetMethods()) != 0) {
+ if (interface &&
+ check_and_assign_method_ids(input_file_name.c_str(), interface->GetMethods()) != 0) {
return AidlError::BAD_METHOD_ID;
}
- if (!validate_constants(*interface)) {
+ if (interface && !validate_constants(*interface)) {
return AidlError::BAD_CONSTANTS;
}
- if (returned_interface)
- *returned_interface = std::move(interface);
+ if (returned_type && interface) *returned_type = std::move(interface);
+ if (returned_type && parcelable) *returned_type = std::move(parcelable);
if (returned_imports)
p.ReleaseImports(returned_imports);
@@ -679,45 +708,36 @@
int compile_aidl_to_cpp(const CppOptions& options,
const IoDelegate& io_delegate) {
- unique_ptr<AidlInterface> interface;
+ unique_ptr<AidlDefinedType> defined_type;
std::vector<std::unique_ptr<AidlImport>> imports;
unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
types->Init();
AidlError err = internals::load_and_validate_aidl(
std::vector<std::string>{}, // no preprocessed files
- options.ImportPaths(),
- options.InputFileName(),
- options.ShouldGenTraces(),
- io_delegate,
- types.get(),
- &interface,
- &imports);
+ options.ImportPaths(), options.InputFileName(), options.ShouldGenTraces(), io_delegate,
+ types.get(), &defined_type, &imports);
if (err != AidlError::OK) {
return 1;
}
- if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) {
+ CHECK(defined_type != nullptr);
+
+ if (!write_cpp_dep_file(options, *defined_type, imports, io_delegate)) {
return 1;
}
- return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1;
+ return (cpp::GenerateCpp(options, *types, *defined_type, io_delegate)) ? 0 : 1;
}
int compile_aidl_to_java(const JavaOptions& options,
const IoDelegate& io_delegate) {
- unique_ptr<AidlInterface> interface;
+ unique_ptr<AidlDefinedType> defined_type;
std::vector<std::unique_ptr<AidlImport>> imports;
unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
types->Init();
AidlError aidl_err = internals::load_and_validate_aidl(
- options.preprocessed_files_,
- options.import_paths_,
- options.input_file_name_,
- options.gen_traces_,
- io_delegate,
- types.get(),
- &interface,
- &imports);
+ options.preprocessed_files_, options.import_paths_, options.input_file_name_,
+ options.gen_traces_, io_delegate, types.get(), &defined_type, &imports);
if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) {
// We aborted code generation because this file contains parcelables.
// However, we were not told to complain if we find parcelables.
@@ -730,10 +750,12 @@
return 1;
}
+ CHECK(defined_type != nullptr);
+
string output_file_name = options.output_file_name_;
// if needed, generate the output file name from the base folder
if (output_file_name.empty() && !options.output_base_folder_.empty()) {
- output_file_name = generate_outputFileName(options, *interface);
+ output_file_name = generate_outputFileName(options, *defined_type);
}
// make sure the folders of the output file all exists
@@ -745,8 +767,8 @@
return 1;
}
- return generate_java(output_file_name, options.input_file_name_.c_str(),
- interface.get(), types.get(), io_delegate, options);
+ return generate_java(output_file_name, options.input_file_name_.c_str(), defined_type.get(),
+ types.get(), io_delegate, options);
}
bool preprocess_aidl(const JavaOptions& options,
diff --git a/aidl.h b/aidl.h
index eb260c0..7eb22c2 100644
--- a/aidl.h
+++ b/aidl.h
@@ -54,15 +54,12 @@
namespace internals {
-AidlError load_and_validate_aidl(
- const std::vector<std::string>& preprocessed_files,
- const std::vector<std::string>& import_paths,
- const std::string& input_file_name,
- const bool generate_traces,
- const IoDelegate& io_delegate,
- TypeNamespace* types,
- std::unique_ptr<AidlInterface>* returned_interface,
- std::vector<std::unique_ptr<AidlImport>>* returned_imports);
+AidlError load_and_validate_aidl(const std::vector<std::string>& preprocessed_files,
+ const std::vector<std::string>& import_paths,
+ const std::string& input_file_name, const bool generate_traces,
+ const IoDelegate& io_delegate, TypeNamespace* types,
+ std::unique_ptr<AidlDefinedType>* returned_type,
+ std::vector<std::unique_ptr<AidlImport>>* returned_imports);
bool parse_preprocessed_file(const IoDelegate& io_delegate,
const std::string& filename, TypeNamespace* types);
diff --git a/aidl_language.cpp b/aidl_language.cpp
index 95a3369..3f9e78c 100644
--- a/aidl_language.cpp
+++ b/aidl_language.cpp
@@ -49,20 +49,23 @@
return name_ + (is_array_ ? "[]" : "");
}
-AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type,
- std::string name, unsigned line)
- : type_(type),
+AidlVariableDeclaration::AidlVariableDeclaration(AidlType* type, std::string name, unsigned line)
+ : type_(type), name_(name), line_(line) {}
+
+string AidlVariableDeclaration::ToString() const {
+ return type_->ToString() + " " + name_;
+}
+
+AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type, std::string name,
+ unsigned line)
+ : AidlVariableDeclaration(type, name, line),
direction_(direction),
- direction_specified_(true),
- name_(name),
- line_(line) {}
+ direction_specified_(true) {}
AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line)
- : type_(type),
+ : AidlVariableDeclaration(type, name, line),
direction_(AidlArgument::IN_DIR),
- direction_specified_(false),
- name_(name),
- line_(line) {}
+ direction_specified_(false) {}
string AidlArgument::ToString() const {
string ret;
@@ -81,9 +84,7 @@
}
}
- ret += type_->ToString();
- ret += " ";
- ret += name_;
+ ret += AidlVariableDeclaration::ToString();
return ret;
}
@@ -188,6 +189,11 @@
}
}
+AidlStructuredParcelable::AidlStructuredParcelable(
+ AidlQualifiedName* name, unsigned line, const std::vector<std::string>& package,
+ std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables)
+ : AidlParcelable(name, line, package, "" /*cpp_header*/), variables_(std::move(*variables)) {}
+
AidlInterface::AidlInterface(const std::string& name, unsigned line,
const std::string& comments, bool oneway,
std::vector<std::unique_ptr<AidlMember>>* members,
@@ -217,6 +223,26 @@
AidlDocument::AidlDocument(AidlInterface* interface)
: interface_(interface) {}
+AidlStructuredParcelable* AidlDocument::ReleaseStructuredParcelable() {
+ if (parcelables_.size() == 0) {
+ return nullptr;
+ }
+
+ AidlStructuredParcelable* ret = nullptr;
+ for (auto& p : parcelables_) {
+ if (p->AsStructuredParcelable() == nullptr) continue;
+
+ if (ret != nullptr) {
+ LOG(ERROR) << "AIDL only supports one structured parcelable per file.";
+ return nullptr;
+ }
+
+ ret = static_cast<AidlStructuredParcelable*>(p.release());
+ }
+
+ return ret;
+}
+
AidlQualifiedName::AidlQualifiedName(std::string term,
std::string comments)
: terms_({term}),
diff --git a/aidl_language.h b/aidl_language.h
index ddbd58a..91fbf17 100644
--- a/aidl_language.h
+++ b/aidl_language.h
@@ -108,7 +108,27 @@
DISALLOW_COPY_AND_ASSIGN(AidlType);
};
-class AidlArgument : public AidlNode {
+class AidlVariableDeclaration : public AidlNode {
+ public:
+ AidlVariableDeclaration(AidlType* type, std::string name, unsigned line);
+ virtual ~AidlVariableDeclaration() = default;
+
+ std::string GetName() const { return name_; }
+ int GetLine() const { return line_; }
+ const AidlType& GetType() const { return *type_; }
+ AidlType* GetMutableType() { return type_.get(); }
+
+ std::string ToString() const;
+
+ private:
+ std::unique_ptr<AidlType> type_;
+ std::string name_;
+ unsigned line_;
+
+ DISALLOW_COPY_AND_ASSIGN(AidlVariableDeclaration);
+};
+
+class AidlArgument : public AidlVariableDeclaration {
public:
enum Direction { IN_DIR = 1, OUT_DIR = 2, INOUT_DIR = 3 };
@@ -122,19 +142,11 @@
bool IsIn() const { return direction_ & IN_DIR; }
bool DirectionWasSpecified() const { return direction_specified_; }
- std::string GetName() const { return name_; }
- int GetLine() const { return line_; }
- const AidlType& GetType() const { return *type_; }
- AidlType* GetMutableType() { return type_.get(); }
-
std::string ToString() const;
private:
- std::unique_ptr<AidlType> type_;
Direction direction_;
bool direction_specified_;
- std::string name_;
- unsigned line_;
DISALLOW_COPY_AND_ASSIGN(AidlArgument);
};
@@ -245,6 +257,7 @@
};
class AidlParcelable;
+class AidlStructuredParcelable;
class AidlInterface;
class AidlDocument : public AidlNode {
public:
@@ -254,11 +267,11 @@
const AidlInterface* GetInterface() const { return interface_.get(); }
AidlInterface* ReleaseInterface() { return interface_.release(); }
+ AidlStructuredParcelable* ReleaseStructuredParcelable();
const std::vector<std::unique_ptr<AidlParcelable>>& GetParcelables() const {
return parcelables_;
}
-
void AddParcelable(AidlParcelable* parcelable) {
parcelables_.push_back(std::unique_ptr<AidlParcelable>(parcelable));
}
@@ -302,8 +315,13 @@
std::string GetCanonicalName() const;
const std::vector<std::string>& GetSplitPackage() const { return package_; }
+ virtual const AidlStructuredParcelable* AsStructuredParcelable() const { return nullptr; }
+ virtual const AidlInterface* AsInterface() const { return nullptr; }
+
private:
const std::vector<std::string> package_;
+
+ DISALLOW_COPY_AND_ASSIGN(AidlDefinedType);
};
class AidlParcelable : public AidlDefinedType {
@@ -315,6 +333,8 @@
// C++ uses "::" instead of "." to refer to a inner class.
std::string GetCppName() const { return name_->GetColonName(); }
+
+ void SetCppHeader(const std::string& cpp_header) { cpp_header_ = cpp_header; }
std::string GetCppHeader() const { return cpp_header_; }
private:
@@ -324,6 +344,24 @@
DISALLOW_COPY_AND_ASSIGN(AidlParcelable);
};
+class AidlStructuredParcelable : public AidlParcelable {
+ public:
+ AidlStructuredParcelable(AidlQualifiedName* name, unsigned line,
+ const std::vector<std::string>& package,
+ std::vector<std::unique_ptr<AidlVariableDeclaration>>* variables);
+
+ const std::vector<std::unique_ptr<AidlVariableDeclaration>>& GetFields() const {
+ return variables_;
+ }
+
+ virtual const AidlStructuredParcelable* AsStructuredParcelable() const { return this; }
+
+ private:
+ const std::vector<std::unique_ptr<AidlVariableDeclaration>> variables_;
+
+ DISALLOW_COPY_AND_ASSIGN(AidlStructuredParcelable);
+};
+
class AidlInterface : public AidlDefinedType {
public:
AidlInterface(const std::string& name, unsigned line,
@@ -348,6 +386,8 @@
return generate_traces_;
}
+ virtual const AidlInterface* AsInterface() const { return this; }
+
private:
bool oneway_;
std::vector<std::unique_ptr<AidlMethod>> methods_;
diff --git a/aidl_language_y.yy b/aidl_language_y.yy
index 68997b7..529abba 100644
--- a/aidl_language_y.yy
+++ b/aidl_language_y.yy
@@ -30,6 +30,8 @@
AidlArgument* arg;
AidlArgument::Direction direction;
std::vector<std::unique_ptr<AidlArgument>>* arg_list;
+ AidlVariableDeclaration* variable;
+ std::vector<std::unique_ptr<AidlVariableDeclaration>>* variable_list;
AidlMethod* method;
AidlMember* constant;
std::vector<std::unique_ptr<AidlMember>>* members;
@@ -49,6 +51,8 @@
%type<parcelable_list> parcelable_decls
%type<parcelable> parcelable_decl
+%type<variable_list> variable_decls
+%type<variable> variable_decl
%type<members> members
%type<interface_obj> interface_decl
%type<method> method_decl
@@ -114,9 +118,17 @@
parcelable_decls
:
{ $$ = new AidlDocument(); }
- | parcelable_decls parcelable_decl {
+ | parcelable_decls annotation_list parcelable_decl {
$$ = $1;
- $$->AddParcelable($2);
+
+ if ($2 != AidlType::AnnotationNone && !$3->AsStructuredParcelable()) {
+ std::cerr << ps->FileName() << ":" << @3 << ": unstructured parcelables cannot be annotated"
+ << std::endl;
+ ps->AddError();
+ }
+
+ $3->Annotate($2);
+ $$->AddParcelable($3);
}
| parcelable_decls error {
ps->AddError();
@@ -130,11 +142,34 @@
| PARCELABLE qualified_name CPP_HEADER C_STR ';' {
$$ = new AidlParcelable($2, @2.begin.line, ps->Package(), $4->GetText());
}
+ | PARCELABLE identifier '{' variable_decls '}' {
+ AidlQualifiedName* name = new AidlQualifiedName($2->GetText(), $2->GetComments());
+ $$ = new AidlStructuredParcelable(name, @2.begin.line, ps->Package(), $4);
+ }
| PARCELABLE error ';' {
ps->AddError();
$$ = NULL;
};
+variable_decls
+ : /* empty */ {
+ $$ = new std::vector<std::unique_ptr<AidlVariableDeclaration>>; }
+ | variable_decls variable_decl {
+ $$ = $1;
+ if ($2 != nullptr) {
+ $$->push_back(std::unique_ptr<AidlVariableDeclaration>($2));
+ }
+ };
+
+variable_decl
+ : type identifier ';' {
+ $$ = new AidlVariableDeclaration($1, $2->GetText(), @2.begin.line);
+ }
+ | error ';' {
+ ps->AddError();
+ $$ = nullptr;
+ }
+
interface_decl
: annotation_list INTERFACE identifier '{' members '}' {
$$ = new AidlInterface($3->GetText(), @2.begin.line, $2->GetComments(),
diff --git a/aidl_unittest.cpp b/aidl_unittest.cpp
index 597a766..6e4f4fc 100644
--- a/aidl_unittest.cpp
+++ b/aidl_unittest.cpp
@@ -69,12 +69,10 @@
cpp_types_.Init();
}
- unique_ptr<AidlInterface> Parse(const string& path,
- const string& contents,
- TypeNamespace* types,
- AidlError* error = nullptr) {
+ unique_ptr<AidlDefinedType> Parse(const string& path, const string& contents,
+ TypeNamespace* types, AidlError* error = nullptr) {
io_delegate_.SetFileContents(path, contents);
- unique_ptr<AidlInterface> ret;
+ unique_ptr<AidlDefinedType> ret;
std::vector<std::unique_ptr<AidlImport>> imports;
AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl(
preprocessed_files_,
@@ -151,9 +149,10 @@
(is_nullable) ? "@nullable" : ""),
&cpp_types_);
ASSERT_NE(nullptr, parse_result);
- ASSERT_FALSE(parse_result->GetMethods().empty());
- EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsNullable(),
- is_nullable);
+ const AidlInterface* interface = parse_result->AsInterface();
+ ASSERT_NE(nullptr, interface);
+ ASSERT_FALSE(interface->GetMethods().empty());
+ EXPECT_EQ(interface->GetMethods()[0]->GetType().IsNullable(), is_nullable);
}
}
@@ -165,9 +164,10 @@
(is_utf8) ? "@utf8InCpp" : ""),
&cpp_types_);
ASSERT_NE(nullptr, parse_result);
- ASSERT_FALSE(parse_result->GetMethods().empty());
- EXPECT_EQ(parse_result->GetMethods()[0]->GetType().IsUtf8InCpp(),
- is_utf8);
+ const AidlInterface* interface = parse_result->AsInterface();
+ ASSERT_NE(nullptr, interface);
+ ASSERT_FALSE(interface->GetMethods().empty());
+ EXPECT_EQ(interface->GetMethods()[0]->GetType().IsUtf8InCpp(), is_utf8);
}
}
@@ -314,7 +314,9 @@
&cpp_types_,
&reported_error);
EXPECT_NE(nullptr, cpp_parse_result);
- const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
+ const AidlInterface* interface = cpp_parse_result->AsInterface();
+ ASSERT_NE(nullptr, interface);
+ const auto& cpp_int_constants = interface->GetIntConstants();
EXPECT_EQ((size_t)1, cpp_int_constants.size());
EXPECT_EQ("POSITIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
EXPECT_EQ(245, cpp_int_constants[0]->GetValue());
@@ -332,7 +334,9 @@
&cpp_types_,
&reported_error);
EXPECT_NE(nullptr, cpp_parse_result);
- const auto& cpp_int_constants = cpp_parse_result->GetIntConstants();
+ const AidlInterface* interface = cpp_parse_result->AsInterface();
+ ASSERT_NE(nullptr, interface);
+ const auto& cpp_int_constants = interface->GetIntConstants();
EXPECT_EQ((size_t)1, cpp_int_constants.size());
EXPECT_EQ("NEGATIVE_HEX_VALUE", cpp_int_constants[0]->GetName());
EXPECT_EQ(-1, cpp_int_constants[0]->GetValue());
diff --git a/ast_cpp.cpp b/ast_cpp.cpp
index 14fa8a6..7af94ac 100644
--- a/ast_cpp.cpp
+++ b/ast_cpp.cpp
@@ -29,6 +29,12 @@
namespace aidl {
namespace cpp {
+LiteralDecl::LiteralDecl(const std::string& expression) : expression_(expression) {}
+
+void LiteralDecl::Write(CodeWriter* to) const {
+ to->Write("%s", expression_.c_str());
+}
+
ClassDecl::ClassDecl(const std::string& name, const std::string& parent)
: name_(name),
parent_(parent) {}
diff --git a/ast_cpp.h b/ast_cpp.h
index bb251ec..9fff316 100644
--- a/ast_cpp.h
+++ b/ast_cpp.h
@@ -49,6 +49,18 @@
DISALLOW_COPY_AND_ASSIGN(Declaration);
}; // class Declaration
+class LiteralDecl : public Declaration {
+ public:
+ explicit LiteralDecl(const std::string& expression);
+ ~LiteralDecl() = default;
+ void Write(CodeWriter* to) const override;
+
+ private:
+ const std::string expression_;
+
+ DISALLOW_COPY_AND_ASSIGN(LiteralDecl);
+}; // class LiteralDecl
+
class ClassDecl : public Declaration {
public:
ClassDecl(const std::string& name,
diff --git a/ast_java.cpp b/ast_java.cpp
index c534e4e..9499ec6 100644
--- a/ast_java.cpp
+++ b/ast_java.cpp
@@ -421,6 +421,10 @@
}
}
+void LiteralClassElement::Write(CodeWriter* to) const {
+ to->Write("%s", element.c_str());
+}
+
void IntConstant::Write(CodeWriter* to) const {
WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS);
to->Write("int %s = %d;\n", name.c_str(), value);
diff --git a/ast_java.h b/ast_java.h
index c5ded58..b28e7b0 100644
--- a/ast_java.h
+++ b/ast_java.h
@@ -326,6 +326,15 @@
void Write(CodeWriter* to) const override;
};
+struct LiteralClassElement : public ClassElement {
+ std::string element;
+
+ LiteralClassElement(std::string e) : element(e) {}
+ virtual ~LiteralClassElement() = default;
+
+ void Write(CodeWriter* to) const override;
+};
+
struct IntConstant : public ClassElement {
const std::string name;
const int value;
diff --git a/generate_cpp.cpp b/generate_cpp.cpp
index b6181eb..f7e90cf 100644
--- a/generate_cpp.cpp
+++ b/generate_cpp.cpp
@@ -81,6 +81,13 @@
return unique_ptr<AstNode>(ret);
}
+unique_ptr<AstNode> ReturnOnStatusNotOk() {
+ IfStatement* ret = new IfStatement(new Comparison(new LiteralExpression(kAndroidStatusVarName),
+ "!=", new LiteralExpression(kAndroidStatusOk)));
+ ret->OnTrue()->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+ return unique_ptr<AstNode>(ret);
+}
+
string UpperCase(const std::string& s) {
string result = s;
for (char& c : result)
@@ -199,8 +206,8 @@
return true;
}
-string ClassName(const AidlInterface& interface, ClassNames type) {
- string c_name = interface.GetName();
+string ClassName(const AidlDefinedType& defined_type, ClassNames type) {
+ string c_name = defined_type.GetName();
if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1]))
c_name = c_name.substr(1);
@@ -221,17 +228,15 @@
return c_name;
}
-string BuildHeaderGuard(const AidlInterface& interface,
- ClassNames header_type) {
- string class_name = ClassName(interface, header_type);
+string BuildHeaderGuard(const AidlDefinedType& defined_type, ClassNames header_type) {
+ string class_name = ClassName(defined_type, header_type);
for (size_t i = 1; i < class_name.size(); ++i) {
if (isupper(class_name[i])) {
class_name.insert(i, "_");
++i;
}
}
- string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_",
- interface.GetPackage().c_str(),
+ string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_", defined_type.GetPackage().c_str(),
class_name.c_str());
for (char& c : ret) {
if (c == '.') {
@@ -772,6 +777,82 @@
NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}};
}
+std::unique_ptr<Document> BuildParcelHeader(const TypeNamespace& /*types*/,
+ const AidlStructuredParcelable& parcel) {
+ unique_ptr<ClassDecl> parcel_class{new ClassDecl{parcel.GetName(), "::android::Parcelable"}};
+
+ set<string> includes = {kStatusHeader, kParcelHeader};
+ for (const auto& variable : parcel.GetFields()) {
+ const Type* type = variable->GetType().GetLanguageType<Type>();
+ type->GetHeaders(&includes);
+ }
+
+ for (const auto& variable : parcel.GetFields()) {
+ const Type* type = variable->GetType().GetLanguageType<Type>();
+
+ parcel_class->AddPublic(std::unique_ptr<LiteralDecl>(new LiteralDecl(
+ StringPrintf("%s %s;\n", type->CppType().c_str(), variable->GetName().c_str()))));
+ }
+
+ unique_ptr<MethodDecl> read(new MethodDecl(kAndroidStatusLiteral, "readFromParcel",
+ ArgList("const Parcel* _aidl_parcel"),
+ MethodDecl::IS_OVERRIDE));
+ parcel_class->AddPublic(std::move(read));
+ unique_ptr<MethodDecl> write(new MethodDecl(kAndroidStatusLiteral, "writeToParcel",
+ ArgList("Parcel* _aidl_parcel"),
+ MethodDecl::IS_OVERRIDE | MethodDecl::IS_CONST));
+ parcel_class->AddPublic(std::move(write));
+
+ return unique_ptr<Document>{new CppHeader{
+ BuildHeaderGuard(parcel, ClassNames::BASE), vector<string>(includes.begin(), includes.end()),
+ NestInNamespaces(std::move(parcel_class), parcel.GetSplitPackage())}};
+}
+std::unique_ptr<Document> BuildParcelSource(const TypeNamespace& types,
+ const AidlStructuredParcelable& parcel) {
+ unique_ptr<MethodImpl> read{new MethodImpl{kAndroidStatusLiteral, parcel.GetName(),
+ "readFromParcel",
+ ArgList("const Parcel* _aidl_parcel")}};
+ StatementBlock* read_block = read->GetStatementBlock();
+ read_block->AddLiteral(
+ StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk));
+ for (const auto& variable : parcel.GetFields()) {
+ string method = variable->GetType().GetLanguageType<Type>()->ReadFromParcelMethod();
+
+ read_block->AddStatement(new Assignment(
+ kAndroidStatusVarName, new MethodCall(StringPrintf("_aidl_parcel->%s", method.c_str()),
+ ArgList("&" + variable->GetName()))));
+ read_block->AddStatement(ReturnOnStatusNotOk());
+ }
+ read_block->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+
+ unique_ptr<MethodImpl> write{new MethodImpl{kAndroidStatusLiteral, parcel.GetName(),
+ "writeToParcel", ArgList("Parcel* _aidl_parcel"),
+ true /*const*/}};
+ StatementBlock* write_block = write->GetStatementBlock();
+ write_block->AddLiteral(
+ StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk));
+ for (const auto& variable : parcel.GetFields()) {
+ string method = variable->GetType().GetLanguageType<Type>()->WriteToParcelMethod();
+
+ write_block->AddStatement(new Assignment(
+ kAndroidStatusVarName, new MethodCall(StringPrintf("_aidl_parcel->%s", method.c_str()),
+ ArgList(variable->GetName()))));
+ write_block->AddStatement(ReturnOnStatusNotOk());
+ }
+ write_block->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName));
+
+ vector<unique_ptr<Declaration>> file_decls;
+ file_decls.push_back(std::move(read));
+ file_decls.push_back(std::move(write));
+
+ set<string> includes = {};
+ parcel.GetLanguageType<Type>()->GetHeaders(&includes);
+
+ return unique_ptr<Document>{
+ new CppSource{vector<string>(includes.begin(), includes.end()),
+ NestInNamespaces(std::move(file_decls), parcel.GetSplitPackage())}};
+}
+
bool WriteHeader(const CppOptions& options,
const TypeNamespace& types,
const AidlInterface& interface,
@@ -813,10 +894,8 @@
using namespace internals;
-string HeaderFile(const AidlInterface& interface,
- ClassNames class_type,
- bool use_os_sep) {
- string file_path = interface.GetPackage();
+string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type, bool use_os_sep) {
+ string file_path = defined_type.GetPackage();
for (char& c: file_path) {
if (c == '.') {
c = (use_os_sep) ? OS_PATH_SEPARATOR : '/';
@@ -825,16 +904,14 @@
if (!file_path.empty()) {
file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/';
}
- file_path += ClassName(interface, class_type);
+ file_path += ClassName(defined_type, class_type);
file_path += ".h";
return file_path;
}
-bool GenerateCpp(const CppOptions& options,
- const TypeNamespace& types,
- const AidlInterface& interface,
- const IoDelegate& io_delegate) {
+bool GenerateCppInterface(const CppOptions& options, const TypeNamespace& types,
+ const AidlInterface& interface, const IoDelegate& io_delegate) {
auto interface_src = BuildInterfaceSource(types, interface);
auto client_src = BuildClientSource(types, interface);
auto server_src = BuildServerSource(types, interface);
@@ -872,6 +949,48 @@
return success;
}
+bool GenerateCppParcel(const CppOptions& options, const cpp::TypeNamespace& types,
+ const AidlStructuredParcelable& parcelable, const IoDelegate& io_delegate) {
+ auto header = BuildParcelHeader(types, parcelable);
+ auto source = BuildParcelSource(types, parcelable);
+
+ if (!header || !source) {
+ return false;
+ }
+
+ if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(), parcelable.GetSplitPackage())) {
+ LOG(ERROR) << "Failed to create directory structure for headers.";
+ }
+
+ const string header_path =
+ options.OutputHeaderDir() + OS_PATH_SEPARATOR + HeaderFile(parcelable, ClassNames::BASE);
+ unique_ptr<CodeWriter> header_writer(io_delegate.GetCodeWriter(header_path));
+ header->Write(header_writer.get());
+ CHECK(header_writer->Close());
+
+ unique_ptr<CodeWriter> source_writer = io_delegate.GetCodeWriter(options.OutputCppFilePath());
+ source->Write(source_writer.get());
+ CHECK(source_writer->Close());
+
+ return true;
+}
+
+bool GenerateCpp(const CppOptions& options, const TypeNamespace& types,
+ const AidlDefinedType& defined_type, const IoDelegate& io_delegate) {
+ const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable();
+ if (parcelable != nullptr) {
+ return GenerateCppParcel(options, types, *parcelable, io_delegate);
+ }
+
+ const AidlInterface* interface = defined_type.AsInterface();
+ if (interface != nullptr) {
+ return GenerateCppInterface(options, types, *interface, io_delegate);
+ }
+
+ CHECK(false) << "Unrecognized type sent for cpp generation.";
+ return false;
+}
+
} // namespace cpp
} // namespace aidl
} // namespace android
diff --git a/generate_cpp.h b/generate_cpp.h
index 1ffc681..2aa8341 100644
--- a/generate_cpp.h
+++ b/generate_cpp.h
@@ -29,10 +29,8 @@
namespace aidl {
namespace cpp {
-bool GenerateCpp(const CppOptions& options,
- const cpp::TypeNamespace& types,
- const AidlInterface& parsed_doc,
- const IoDelegate& io_delegate);
+bool GenerateCpp(const CppOptions& options, const cpp::TypeNamespace& types,
+ const AidlDefinedType& parsed_doc, const IoDelegate& io_delegate);
// These roughly correspond to the various class names in the C++ hierarchy:
enum class ClassNames {
@@ -45,7 +43,7 @@
// Generate the relative path to a header file. If |use_os_sep| we'll use the
// operating system specific path separator rather than C++'s expected '/' when
// including headers.
-std::string HeaderFile(const AidlInterface& interface, ClassNames class_type,
+std::string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type,
bool use_os_sep = true);
namespace internals {
@@ -61,6 +59,11 @@
const AidlInterface& parsed_doc);
std::unique_ptr<Document> BuildInterfaceHeader(const TypeNamespace& types,
const AidlInterface& parsed_doc);
+
+std::unique_ptr<Document> BuildParcelHeader(const TypeNamespace& types,
+ const AidlStructuredParcelable& parsed_doc);
+std::unique_ptr<Document> BuildParcelSource(const TypeNamespace& types,
+ const AidlStructuredParcelable& parsed_doc);
}
} // namespace cpp
} // namespace aidl
diff --git a/generate_cpp_unittest.cpp b/generate_cpp_unittest.cpp
index 209f173..1e15f6b 100644
--- a/generate_cpp_unittest.cpp
+++ b/generate_cpp_unittest.cpp
@@ -1286,10 +1286,10 @@
types_.Init();
}
- unique_ptr<AidlInterface> Parse() {
+ unique_ptr<AidlInterface> ParseInterface() {
io_delegate_.SetFileContents(file_path_, file_contents_);
- unique_ptr<AidlInterface> ret;
+ unique_ptr<AidlDefinedType> ret;
std::vector<std::unique_ptr<AidlImport>> imports;
AidlError err = ::android::aidl::internals::load_and_validate_aidl(
{}, // no preprocessed files
@@ -1301,10 +1301,15 @@
&ret,
&imports);
- if (err != AidlError::OK)
+ if (err != AidlError::OK) {
return nullptr;
+ }
- return ret;
+ if (ret->AsInterface() == nullptr) {
+ return nullptr;
+ }
+
+ return unique_ptr<AidlInterface>(static_cast<AidlInterface*>(ret.release()));
}
void Compare(Document* doc, const char* expected) {
@@ -1338,21 +1343,21 @@
};
TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientHeader) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
unique_ptr<Document> doc = internals::BuildClientHeader(types_, *interface);
Compare(doc.get(), kExpectedComplexTypeClientHeaderOutput);
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSource) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
unique_ptr<Document> doc = internals::BuildClientSource(types_, *interface);
Compare(doc.get(), kExpectedComplexTypeClientSourceOutput);
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSourceWithTrace) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
interface->SetGenerateTraces(true);
unique_ptr<Document> doc = internals::BuildClientSource(types_, *interface);
@@ -1360,21 +1365,21 @@
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerHeader) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
unique_ptr<Document> doc = internals::BuildServerHeader(types_, *interface);
Compare(doc.get(), kExpectedComplexTypeServerHeaderOutput);
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSource) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
unique_ptr<Document> doc = internals::BuildServerSource(types_, *interface);
Compare(doc.get(), kExpectedComplexTypeServerSourceOutput);
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSourceWithTrace) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
interface->SetGenerateTraces(true);
unique_ptr<Document> doc = internals::BuildServerSource(types_, *interface);
@@ -1382,14 +1387,14 @@
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceHeader) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
unique_ptr<Document> doc = internals::BuildInterfaceHeader(types_, *interface);
Compare(doc.get(), kExpectedComplexTypeInterfaceHeaderOutput);
}
TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceSource) {
- unique_ptr<AidlInterface> interface = Parse();
+ unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
unique_ptr<Document> doc = internals::BuildInterfaceSource(types_, *interface);
Compare(doc.get(), kExpectedComplexTypeInterfaceSourceOutput);
@@ -1427,14 +1432,14 @@
TEST_F(IoErrorHandlingTest, GenerateCorrectlyAbsentErrors) {
// Confirm that this is working correctly without I/O problems.
- const unique_ptr<AidlInterface> interface = Parse();
+ const unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
ASSERT_TRUE(GenerateCpp(*options_, types_, *interface, io_delegate_));
}
TEST_F(IoErrorHandlingTest, HandlesBadHeaderWrite) {
using namespace test_io_handling;
- const unique_ptr<AidlInterface> interface = Parse();
+ const unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
// Simulate issues closing the interface header.
@@ -1451,7 +1456,7 @@
TEST_F(IoErrorHandlingTest, HandlesBadCppWrite) {
using test_io_handling::kOutputPath;
- const unique_ptr<AidlInterface> interface = Parse();
+ const unique_ptr<AidlInterface> interface = ParseInterface();
ASSERT_NE(interface, nullptr);
// Simulate issues closing the cpp file.
diff --git a/generate_java.cpp b/generate_java.cpp
index afa188a..1ca285b 100644
--- a/generate_java.cpp
+++ b/generate_java.cpp
@@ -16,10 +16,11 @@
#include "generate_java.h"
-#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <memory>
+#include <sstream>
#include <android-base/stringprintf.h>
@@ -54,16 +55,13 @@
namespace java {
-int generate_java(const string& filename, const string& originalSrc,
- AidlInterface* iface, JavaTypeNamespace* types,
- const IoDelegate& io_delegate, const JavaOptions& options) {
+int generate_java_interface(const string& filename, const string& original_src,
+ const AidlInterface* iface, JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const JavaOptions& options) {
Class* cl = generate_binder_interface_class(iface, types, options);
- Document* document = new Document(
- "" /* no comment */,
- iface->GetPackage(),
- originalSrc,
- unique_ptr<Class>(cl));
+ Document* document =
+ new Document("" /* no comment */, iface->GetPackage(), original_src, unique_ptr<Class>(cl));
CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
document->Write(code_writer.get());
@@ -71,6 +69,106 @@
return 0;
}
+int generate_java_parcel(const std::string& filename, const std::string& original_src,
+ const AidlStructuredParcelable* parcel, JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const JavaOptions& options) {
+ Class* cl = generate_parcel_class(parcel, types, options);
+
+ Document* document =
+ new Document("" /* no comment */, parcel->GetPackage(), original_src, unique_ptr<Class>(cl));
+
+ CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename);
+ document->Write(code_writer.get());
+
+ return 0;
+}
+
+int generate_java(const std::string& filename, const std::string& original_src,
+ const AidlDefinedType* defined_type, JavaTypeNamespace* types,
+ const IoDelegate& io_delegate, const JavaOptions& options) {
+ const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable();
+ if (parcelable != nullptr) {
+ return generate_java_parcel(filename, original_src, parcelable, types, io_delegate, options);
+ }
+
+ const AidlInterface* interface = defined_type->AsInterface();
+ if (interface != nullptr) {
+ return generate_java_interface(filename, original_src, interface, types, io_delegate, options);
+ }
+
+ CHECK(false) << "Unrecognized type sent for cpp generation.";
+ return false;
+}
+
+android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
+ java::JavaTypeNamespace* types,
+ const JavaOptions& options) {
+ const ParcelType* parcelType = parcel->GetLanguageType<ParcelType>();
+
+ Class* parcel_class = new Class;
+ parcel_class->comment = parcel->GetComments();
+ parcel_class->modifiers = PUBLIC;
+ parcel_class->what = Class::CLASS;
+ parcel_class->type = parcelType;
+
+ for (const auto& variable : parcel->GetFields()) {
+ const Type* type = variable->GetType().GetLanguageType<Type>();
+ Variable* variable_element =
+ new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
+ parcel_class->elements.push_back(new Field(PUBLIC, variable_element));
+ }
+
+ std::ostringstream out;
+ out << "public static final android.os.Parcelable.Creator<" << parcel->GetName() << "> CREATOR = "
+ << "new android.os.Parcelable.Creator<" << parcel->GetName() << ">() {\n";
+ out << " public " << parcel->GetName()
+ << " createFromParcel(android.os.Parcel _aidl_source) {\n";
+ out << " " << parcel->GetName() << " _aidl_out = new " << parcel->GetName() << "();\n";
+ out << " _aidl_out.readFromParcel(_aidl_source);\n";
+ out << " return _aidl_out;\n";
+ out << " }\n";
+ out << " public " << parcel->GetName() << "[] newArray(int _aidl_size) {\n";
+ out << " return new " << parcel->GetName() << "[_aidl_size];\n";
+ out << " }\n";
+ out << "};\n";
+ parcel_class->elements.push_back(new LiteralClassElement(out.str()));
+
+ Variable* flag_variable = new Variable(new Type(types, "int", 0, false, false), "_aidl_flag");
+ Variable* parcel_variable =
+ new Variable(new Type(types, "android.os.Parcel", 0, false, false), "_aidl_parcel");
+
+ Method* write_method = new Method;
+ write_method->modifiers = PUBLIC;
+ write_method->returnType = new Type(types, "void", 0, false, false);
+ write_method->name = "writeToParcel";
+ write_method->parameters.push_back(parcel_variable);
+ write_method->parameters.push_back(flag_variable);
+ write_method->statements = new StatementBlock();
+ for (const auto& variable : parcel->GetFields()) {
+ const Type* type = variable->GetType().GetLanguageType<Type>();
+ Variable* variable_element =
+ new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
+ type->WriteToParcel(write_method->statements, variable_element, parcel_variable, 0 /*flags*/);
+ }
+ parcel_class->elements.push_back(write_method);
+
+ Method* read_method = new Method;
+ read_method->modifiers = PUBLIC;
+ read_method->returnType = new Type(types, "void", 0, false, false);
+ read_method->name = "readFromParcel";
+ read_method->parameters.push_back(parcel_variable);
+ read_method->statements = new StatementBlock();
+ for (const auto& variable : parcel->GetFields()) {
+ const Type* type = variable->GetType().GetLanguageType<Type>();
+ Variable* variable_element =
+ new Variable(type, variable->GetName(), variable->GetType().IsArray() ? 1 : 0);
+ type->CreateFromParcel(read_method->statements, variable_element, parcel_variable, 0 /*flags*/);
+ }
+ parcel_class->elements.push_back(read_method);
+
+ return parcel_class;
+}
+
} // namespace java
} // namespace android
} // namespace aidl
diff --git a/generate_java.h b/generate_java.h
index 59fed62..680a199 100644
--- a/generate_java.h
+++ b/generate_java.h
@@ -32,14 +32,18 @@
class JavaTypeNamespace;
-int generate_java(const std::string& filename, const std::string& originalSrc,
- AidlInterface* iface, java::JavaTypeNamespace* types,
+int generate_java(const std::string& filename, const std::string& original_src,
+ const AidlDefinedType* iface, java::JavaTypeNamespace* types,
const IoDelegate& io_delegate, const JavaOptions& options);
android::aidl::java::Class* generate_binder_interface_class(
const AidlInterface* iface, java::JavaTypeNamespace* types,
const JavaOptions& options);
+android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel,
+ java::JavaTypeNamespace* types,
+ const JavaOptions& options);
+
} // namespace java
class VariableFactory {
diff --git a/tests/aidl_test_client.cpp b/tests/aidl_test_client.cpp
index 84c8183..8c06889 100644
--- a/tests/aidl_test_client.cpp
+++ b/tests/aidl_test_client.cpp
@@ -90,6 +90,8 @@
if (!client_tests::ConfirmPersistableBundles(service)) return 1;
+ if (!client_tests::ConfirmStructuredParcelables(service)) return 1;
+
if (!client_tests::ConfirmFileDescriptors(service)) return 1;
if (!client_tests::ConfirmFileDescriptorArrays(service)) return 1;
diff --git a/tests/aidl_test_client_parcelables.cpp b/tests/aidl_test_client_parcelables.cpp
index 09e7f0a..66b66c0 100644
--- a/tests/aidl_test_client_parcelables.cpp
+++ b/tests/aidl_test_client_parcelables.cpp
@@ -145,6 +145,35 @@
return true;
}
+bool ConfirmStructuredParcelables(const sp<ITestService>& s) {
+ constexpr int kDesiredValue = 23;
+
+ StructuredParcelable parcelable;
+ parcelable.f = kDesiredValue;
+
+ s->FillOutStructuredParcelable(&parcelable);
+
+ if (parcelable.shouldContainThreeFs.size() != 3) {
+ cout << "shouldContainThreeFs is of length " << parcelable.shouldContainThreeFs.size() << endl;
+ return false;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ if (parcelable.shouldContainThreeFs[i] != kDesiredValue) {
+ cout << "shouldContainThreeFs[" << i << "] is " << parcelable.shouldContainThreeFs[i]
+ << " but should be " << kDesiredValue << endl;
+ return false;
+ }
+ }
+
+ if (parcelable.shouldBeJerry != "Jerry") {
+ cout << "shouldBeJerry is not Jerry and is instead " << parcelable.shouldBeJerry << endl;
+ return false;
+ }
+
+ return true;
+}
+
} // namespace client
} // namespace tests
} // namespace aidl
diff --git a/tests/aidl_test_client_parcelables.h b/tests/aidl_test_client_parcelables.h
index 9616e02..168f6cd 100644
--- a/tests/aidl_test_client_parcelables.h
+++ b/tests/aidl_test_client_parcelables.h
@@ -29,6 +29,7 @@
bool ConfirmSimpleParcelables(const sp<ITestService>& s);
bool ConfirmPersistableBundles(const sp<ITestService>& s);
+bool ConfirmStructuredParcelables(const sp<ITestService>& s);
} // namespace client
} // namespace tests
diff --git a/tests/aidl_test_service.cpp b/tests/aidl_test_service.cpp
index c5e4bcd..8a64ebc 100644
--- a/tests/aidl_test_service.cpp
+++ b/tests/aidl_test_service.cpp
@@ -438,6 +438,13 @@
return Status::ok();
}
+ virtual ::android::binder::Status FillOutStructuredParcelable(
+ ::android::aidl::tests::StructuredParcelable* parcelable) {
+ parcelable->shouldBeJerry = "Jerry";
+ parcelable->shouldContainThreeFs = {parcelable->f, parcelable->f, parcelable->f};
+ return Status::ok();
+ }
+
private:
map<String16, sp<INamedCallback>> service_map_;
};
diff --git a/tests/android/aidl/tests/ITestService.aidl b/tests/android/aidl/tests/ITestService.aidl
index 1f2ae8c..5fd962c 100644
--- a/tests/android/aidl/tests/ITestService.aidl
+++ b/tests/android/aidl/tests/ITestService.aidl
@@ -18,6 +18,7 @@
import android.aidl.tests.INamedCallback;
import android.aidl.tests.SimpleParcelable;
+import android.aidl.tests.StructuredParcelable;
import android.os.PersistableBundle;
interface ITestService {
@@ -113,4 +114,7 @@
out @nullable @utf8InCpp List<String> repeated);
@nullable INamedCallback GetCallback(boolean return_null);
+
+ // This is not a well designed API and should not be taken as an example
+ void FillOutStructuredParcelable(inout StructuredParcelable parcel);
}
diff --git a/tests/android/aidl/tests/StructuredParcelable.aidl b/tests/android/aidl/tests/StructuredParcelable.aidl
new file mode 100644
index 0000000..bc23eb6
--- /dev/null
+++ b/tests/android/aidl/tests/StructuredParcelable.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.aidl.tests;
+
+parcelable StructuredParcelable {
+ int[] shouldContainThreeFs;
+ int f;
+ @utf8InCpp String shouldBeJerry;
+}
diff --git a/tests/java_app/src/android/aidl/tests/TestServiceClient.java b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
index 04ca2e9..18dd236 100644
--- a/tests/java_app/src/android/aidl/tests/TestServiceClient.java
+++ b/tests/java_app/src/android/aidl/tests/TestServiceClient.java
@@ -17,6 +17,7 @@
package android.aidl.tests;
import android.aidl.tests.SimpleParcelable;
+import android.aidl.tests.StructuredParcelable;
import android.aidl.tests.TestFailException;
import android.aidl.tests.TestLogger;
import android.app.Activity;
@@ -699,6 +700,37 @@
mLog.log("...UTF8 annotations work.");
}
+ private void checkStructuredParcelable(ITestService service) throws TestFailException {
+ final int kDesiredFValue = 17;
+
+ StructuredParcelable parcelable = new StructuredParcelable();
+ parcelable.shouldContainThreeFs = new int[0];
+ parcelable.f = kDesiredFValue;
+ parcelable.shouldBeJerry = "";
+
+ try {
+ service.FillOutStructuredParcelable(parcelable);
+ } catch (RemoteException ex) {
+ mLog.log(ex.toString());
+ mLog.logAndThrow("Service failed to handle structured parcelable.");
+ }
+
+ if (parcelable.shouldContainThreeFs.length != 3) {
+ mLog.logAndThrow(
+ "shouldContainThreeFs is of length " + parcelable.shouldContainThreeFs.length);
+ }
+ for (int i = 0; i < 3; i++) {
+ if (parcelable.shouldContainThreeFs[i] != kDesiredFValue) {
+ mLog.logAndThrow("shouldContainThreeFs[" + i + "] is "
+ + parcelable.shouldContainThreeFs[i] + " but should be " + kDesiredFValue);
+ }
+ }
+
+ if (!parcelable.shouldBeJerry.equals("Jerry")) {
+ mLog.logAndThrow("shouldBeJerry should be 'Jerry' but is " + parcelable.shouldBeJerry);
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -715,6 +747,7 @@
checkFileDescriptorPassing(service);
checkServiceSpecificExceptions(service);
checkUtf8Strings(service);
+ checkStructuredParcelable(service);
new NullableTests(service, mLog).runTests();
mLog.log(mSuccessSentinel);
diff --git a/type_cpp.cpp b/type_cpp.cpp
index 6159231..ead99f8 100644
--- a/type_cpp.cpp
+++ b/type_cpp.cpp
@@ -171,6 +171,12 @@
DISALLOW_COPY_AND_ASSIGN(ByteType);
}; // class PrimitiveType
+static string GetCppHeader(const AidlDefinedType& defined_type) {
+ vector<string> name = defined_type.GetSplitPackage();
+ name.push_back(defined_type.GetName());
+ return Join(name, '/') + ".h";
+}
+
class BinderType : public Type {
public:
BinderType(const AidlInterface& interface, const std::string& src_file_name)
@@ -212,25 +218,16 @@
return ret;
}
- static string GetCppHeader(const AidlInterface& interface) {
- vector<string> name = interface.GetSplitPackage();
- name.push_back(interface.GetName());
- return Join(name, '/') + ".h";
- }
-
std::string write_cast_;
};
class NullableParcelableType : public Type {
public:
- NullableParcelableType(const AidlParcelable& parcelable,
+ NullableParcelableType(const AidlParcelable& parcelable, const std::string& cpp_header,
const std::string& src_file_name)
- : Type(ValidatableType::KIND_PARCELABLE,
- parcelable.GetPackage(), parcelable.GetName(),
- {parcelable.GetCppHeader()}, GetCppName(parcelable),
- "readParcelable", "writeNullableParcelable",
- kNoArrayType, kNoNullableType,
- src_file_name, parcelable.GetLine()) {}
+ : Type(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(),
+ {cpp_header}, GetCppName(parcelable), "readParcelable", "writeNullableParcelable",
+ kNoArrayType, kNoNullableType, src_file_name, parcelable.GetLine()) {}
virtual ~NullableParcelableType() = default;
bool CanBeOutParameter() const override { return true; }
@@ -243,20 +240,16 @@
class ParcelableType : public Type {
public:
- ParcelableType(const AidlParcelable& parcelable,
+ ParcelableType(const AidlParcelable& parcelable, const std::string& cpp_header,
const std::string& src_file_name)
- : Type(ValidatableType::KIND_PARCELABLE,
- parcelable.GetPackage(), parcelable.GetName(),
- {parcelable.GetCppHeader()}, GetCppName(parcelable),
- "readParcelable", "writeParcelable",
- new CppArrayType(
- ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(),
- parcelable.GetName(), parcelable.GetCppHeader(),
- GetCppName(parcelable), GetCppName(parcelable),
- "readParcelableVector", "writeParcelableVector", false,
- src_file_name),
- new NullableParcelableType(parcelable, src_file_name),
- src_file_name, parcelable.GetLine()) {}
+ : Type(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(),
+ {cpp_header}, GetCppName(parcelable), "readParcelable", "writeParcelable",
+ new CppArrayType(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(),
+ parcelable.GetName(), cpp_header, GetCppName(parcelable),
+ GetCppName(parcelable), "readParcelableVector",
+ "writeParcelableVector", false, src_file_name),
+ new NullableParcelableType(parcelable, cpp_header, src_file_name), src_file_name,
+ parcelable.GetLine()) {}
virtual ~ParcelableType() = default;
bool CanBeOutParameter() const override { return true; }
@@ -515,12 +508,15 @@
bool TypeNamespace::AddParcelableType(const AidlParcelable& p,
const string& filename) {
- if (p.GetCppHeader().empty()) {
+ const std::string cpp_header = p.AsStructuredParcelable() ? GetCppHeader(p) : p.GetCppHeader();
+
+ if (cpp_header.empty()) {
LOG(ERROR) << "Parcelable " << p.GetCanonicalName()
<< " has no C++ header defined.";
return false;
}
- Add(new ParcelableType(p, filename));
+
+ Add(new ParcelableType(p, cpp_header, filename));
return true;
}
@@ -578,10 +574,9 @@
return true;
}
-const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a,
- int arg_index,
- const std::string& filename,
- const AidlInterface& interface) const {
+const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index,
+ const std::string& filename,
+ const AidlDefinedType& context) const {
const string error_prefix = StringPrintf(
"In file %s line %d parameter %s (%d):\n ",
filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
@@ -593,8 +588,7 @@
return nullptr;
}
- return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename,
- interface);
+ return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename, context);
}
} // namespace cpp
diff --git a/type_cpp.h b/type_cpp.h
index 0a6a4a9..65c9886 100644
--- a/type_cpp.h
+++ b/type_cpp.h
@@ -102,10 +102,9 @@
const std::string& value_type_name) override;
bool IsValidPackage(const std::string& package) const override;
- const ValidatableType* GetArgType(const AidlArgument& a,
- int arg_index,
- const std::string& filename,
- const AidlInterface& interface) const override;
+ const ValidatableType* GetArgType(const AidlArgument& a, int arg_index,
+ const std::string& filename,
+ const AidlDefinedType& context) const override;
const Type* VoidType() const { return void_type_; }
const Type* IBinderType() const { return ibinder_type_; }
diff --git a/type_namespace.cpp b/type_namespace.cpp
index d3f4aaf..06695c6 100644
--- a/type_namespace.cpp
+++ b/type_namespace.cpp
@@ -97,12 +97,11 @@
return true;
}
-const ValidatableType* TypeNamespace::GetReturnType(
- const AidlType& raw_type, const string& filename,
- const AidlInterface& interface) const {
+const ValidatableType* TypeNamespace::GetReturnType(const AidlType& raw_type,
+ const string& filename,
+ const AidlDefinedType& context) const {
string error_msg;
- const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg,
- interface);
+ const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg, context);
if (return_type == nullptr) {
LOG(ERROR) << StringPrintf("In file %s line %d return type %s:\n ",
filename.c_str(), raw_type.GetLine(),
@@ -114,17 +113,16 @@
return return_type;
}
-const ValidatableType* TypeNamespace::GetArgType(
- const AidlArgument& a, int arg_index, const string& filename,
- const AidlInterface& interface) const {
+const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index,
+ const string& filename,
+ const AidlDefinedType& context) const {
string error_prefix = StringPrintf(
"In file %s line %d parameter %s (argument %d):\n ",
filename.c_str(), a.GetLine(), a.GetName().c_str(), arg_index);
// check the arg type
string error_msg;
- const ValidatableType* t = GetValidatableType(a.GetType(), &error_msg,
- interface);
+ const ValidatableType* t = GetValidatableType(a.GetType(), &error_msg, context);
if (t == nullptr) {
LOG(ERROR) << error_prefix << error_msg;
return nullptr;
diff --git a/type_namespace.h b/type_namespace.h
index 7defd24..315641e 100644
--- a/type_namespace.h
+++ b/type_namespace.h
@@ -97,6 +97,7 @@
// Load this TypeNamespace with user defined types.
virtual bool AddParcelableType(const AidlParcelable& p,
const std::string& filename) = 0;
+
virtual bool AddBinderType(const AidlInterface& b,
const std::string& filename) = 0;
// Add a container type to this namespace. Returns false only
@@ -111,30 +112,25 @@
// Returns a pointer to a type corresponding to |raw_type| or nullptr
// if this is an invalid return type.
- virtual const ValidatableType* GetReturnType(
- const AidlType& raw_type,
- const std::string& filename,
- const AidlInterface& interface) const;
+ virtual const ValidatableType* GetReturnType(const AidlType& raw_type,
+ const std::string& filename,
+ const AidlDefinedType& context) const;
// Returns a pointer to a type corresponding to |a| or nullptr if |a|
// has an invalid argument type.
- virtual const ValidatableType* GetArgType(
- const AidlArgument& a,
- int arg_index,
- const std::string& filename,
- const AidlInterface& interface) const;
+ virtual const ValidatableType* GetArgType(const AidlArgument& a, int arg_index,
+ const std::string& filename,
+ const AidlDefinedType& context) const;
- // Returns a pointer to a type corresponding to |interface|.
- virtual const ValidatableType* GetInterfaceType(
- const AidlInterface& interface) const = 0;
+ // Returns a pointer to a type corresponding to |defined_type|.
+ virtual const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const = 0;
protected:
TypeNamespace() = default;
virtual ~TypeNamespace() = default;
- virtual const ValidatableType* GetValidatableType(
- const AidlType& type, std::string* error_msg,
- const AidlInterface& interface) const = 0;
+ virtual const ValidatableType* GetValidatableType(const AidlType& type, std::string* error_msg,
+ const AidlDefinedType& context) const = 0;
private:
DISALLOW_COPY_AND_ASSIGN(TypeNamespace);
@@ -160,9 +156,8 @@
bool HasImportType(const AidlImport& import) const override {
return HasTypeByCanonicalName(import.GetNeededClass());
}
- const ValidatableType* GetInterfaceType(
- const AidlInterface& interface) const override {
- return FindTypeByCanonicalName(interface.GetCanonicalName());
+ const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const override {
+ return FindTypeByCanonicalName(defined_type.GetCanonicalName());
}
bool MaybeAddContainerType(const AidlType& aidl_type) override;
@@ -185,9 +180,8 @@
// Returns true if this is a container type, rather than a normal type.
bool IsContainerType(const std::string& type_name) const;
- const ValidatableType* GetValidatableType(
- const AidlType& type, std::string* error_msg,
- const AidlInterface& interface) const override;
+ const ValidatableType* GetValidatableType(const AidlType& type, std::string* error_msg,
+ const AidlDefinedType& context) const override;
std::vector<std::unique_ptr<const T>> types_;
@@ -383,10 +377,9 @@
return false;
}
-template<typename T>
+template <typename T>
const ValidatableType* LanguageTypeNamespace<T>::GetValidatableType(
- const AidlType& aidl_type, std::string* error_msg,
- const AidlInterface& interface) const {
+ const AidlType& aidl_type, std::string* error_msg, const AidlDefinedType& context) const {
using android::base::StringPrintf;
const ValidatableType* type = Find(aidl_type);
@@ -428,8 +421,8 @@
utf8InCpp = false;
} else if (aidl_type.GetName() == "String" ||
aidl_type.GetName() == "java.lang.String") {
- utf8 = utf8 || interface.IsUtf8();
- utf8InCpp = utf8InCpp || interface.IsUtf8InCpp();
+ utf8 = utf8 || context.IsUtf8();
+ utf8InCpp = utf8InCpp || context.IsUtf8InCpp();
} else if (utf8 || utf8InCpp) {
const char* annotation_literal =
(utf8) ? kUtf8Annotation : kUtf8InCppAnnotation;
@@ -469,7 +462,7 @@
}
}
- if (interface.IsNullable()) {
+ if (context.IsNullable()) {
const ValidatableType* nullableType = type->NullableType();
if (nullableType) {