Android.bp0100644 0000000 0000000 00000011731 13277516055 011526 0ustar000000000 0000000 // // Copyright (C) 2015 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. // cc_defaults { name: "aidl_defaults", clang_cflags: [ "-Wall", "-Wextra", "-Werror", ], whole_static_libs: ["libgtest_prod"], static_libs: [ "libbase", "libcutils", ], target: { windows: { enabled: true, }, }, } // Logic shared between aidl and its unittests cc_library_host_static { name: "libaidl-common", defaults: ["aidl_defaults"], clang_cflags: [ // Tragically, the code is riddled with unused parameters. "-Wno-unused-parameter", // yacc dumps a lot of code *just in case*. "-Wno-unused-function", "-Wno-unneeded-internal-declaration", // yacc is a tool from a more civilized age. "-Wno-deprecated-register", // yacc also has a habit of using char* over const char*. "-Wno-writable-strings", ], srcs: [ "aidl.cpp", "aidl_language.cpp", "aidl_language_l.ll", "aidl_language_y.yy", "ast_cpp.cpp", "ast_java.cpp", "code_writer.cpp", "generate_cpp.cpp", "generate_java.cpp", "generate_java_binder.cpp", "import_resolver.cpp", "line_reader.cpp", "io_delegate.cpp", "options.cpp", "type_cpp.cpp", "type_java.cpp", "type_namespace.cpp", ], } // aidl executable cc_binary_host { name: "aidl", defaults: ["aidl_defaults"], srcs: ["main_java.cpp"], static_libs: [ "libaidl-common", "libbase", ], } // aidl-cpp executable cc_binary_host { name: "aidl-cpp", defaults: ["aidl_defaults"], srcs: ["main_cpp.cpp"], static_libs: [ "libaidl-common", "libbase", ], } // Unit tests cc_test_host { name: "aidl_unittests", cflags: [ "-Wall", "-Wextra", "-Werror", "-g", "-DUNIT_TEST", ], // Tragically, the code is riddled with unused parameters. clang_cflags: ["-Wno-unused-parameter"], srcs: [ "aidl_unittest.cpp", "ast_cpp_unittest.cpp", "ast_java_unittest.cpp", "generate_cpp_unittest.cpp", "io_delegate_unittest.cpp", "options_unittest.cpp", "tests/end_to_end_tests.cpp", "tests/fake_io_delegate.cpp", "tests/main.cpp", "tests/test_data_example_interface.cpp", "tests/test_data_ping_responder.cpp", "tests/test_data_string_constants.cpp", "tests/test_util.cpp", "type_cpp_unittest.cpp", "type_java_unittest.cpp", ], static_libs: [ "libaidl-common", "libbase", "libcutils", "libgmock_host", ], target: { linux: { host_ldlibs: ["-lrt"], }, }, } // // Everything below here is used for integration testing of generated AIDL code. // cc_binary { name: "aidl_test_sentinel_searcher", srcs: ["tests/aidl_test_sentinel_searcher.cpp"], cflags: [ "-Wall", "-Wextra", "-Werror", "-Wunused-parameter", ], } cc_defaults { name: "aidl_test_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", "-Wunused-parameter", ], shared_libs: [ "libbase", "libbinder", "liblog", "libutils", ], } cc_library_shared { name: "libaidl-integration-test", defaults: ["aidl_test_defaults"], aidl: { export_aidl_headers: true, local_include_dirs: ["tests"], include_dirs: ["frameworks/native/aidl/binder"], }, srcs: [ "tests/android/aidl/tests/ITestService.aidl", "tests/android/aidl/tests/INamedCallback.aidl", "tests/simple_parcelable.cpp", ], } cc_binary { name: "aidl_test_service", defaults: ["aidl_test_defaults"], shared_libs: ["libaidl-integration-test"], srcs: ["tests/aidl_test_service.cpp"], } cc_binary { name: "aidl_test_client", defaults: ["aidl_test_defaults"], shared_libs: ["libaidl-integration-test"], srcs: [ "tests/aidl_test_client.cpp", "tests/aidl_test_client_file_descriptors.cpp", "tests/aidl_test_client_parcelables.cpp", "tests/aidl_test_client_nullables.cpp", "tests/aidl_test_client_primitives.cpp", "tests/aidl_test_client_utf8_strings.cpp", "tests/aidl_test_client_service_exceptions.cpp", ], } Android.mk0100644 0000000 0000000 00000003362 13277516055 011535 0ustar000000000 0000000 # # Copyright (C) 2015 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. # LOCAL_PATH := $(call my-dir) # # Everything below here is used for integration testing of generated AIDL code. # # aidl on its own doesn't need the framework, but testing native/java # compatibility introduces java dependencies. ifndef BRILLO include $(CLEAR_VARS) LOCAL_PACKAGE_NAME := aidl_test_services # Turn off Java optimization tools to speed up our test iterations. LOCAL_PROGUARD_ENABLED := disabled LOCAL_DEX_PREOPT := false LOCAL_CERTIFICATE := platform LOCAL_MANIFEST_FILE := tests/java_app/AndroidManifest.xml LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/tests/java_app/resources LOCAL_SRC_FILES := \ tests/android/aidl/tests/INamedCallback.aidl \ tests/android/aidl/tests/ITestService.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 \ tests/java_app/src/android/aidl/tests/TestLogger.java \ tests/java_app/src/android/aidl/tests/TestServiceClient.java LOCAL_AIDL_INCLUDES := \ system/tools/aidl/tests/ \ frameworks/native/aidl/binder include $(BUILD_PACKAGE) endif # not defined BRILLO MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13277516055 012743 0ustar000000000 0000000 NOTICE0100644 0000000 0000000 00000024707 13277516055 010536 0ustar000000000 0000000 Copyright (c) 2005-2008, 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. 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. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS OWNERS0100644 0000000 0000000 00000000022 13277516055 010552 0ustar000000000 0000000 sadmac@google.com aidl.cpp0100644 0000000 0000000 00000056224 13277516055 011246 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "aidl.h" #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #include #endif #include #include "aidl_language.h" #include "generate_cpp.h" #include "generate_java.h" #include "import_resolver.h" #include "logging.h" #include "options.h" #include "os.h" #include "type_cpp.h" #include "type_java.h" #include "type_namespace.h" #ifndef O_BINARY # define O_BINARY 0 #endif using android::base::Join; using android::base::Split; using std::cerr; using std::endl; using std::map; using std::set; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace { // The following are gotten as the offset from the allowable id's between // android.os.IBinder.FIRST_CALL_TRANSACTION=1 and // android.os.IBinder.LAST_CALL_TRANSACTION=16777215 const int kMinUserSetMethodId = 0; const int kMaxUserSetMethodId = 16777214; bool check_filename(const std::string& filename, const std::string& package, const std::string& name, unsigned line) { const char* p; string expected; string fn; size_t len; bool valid = false; if (!IoDelegate::GetAbsolutePath(filename, &fn)) { return false; } if (!package.empty()) { expected = package; expected += '.'; } len = expected.length(); for (size_t i=0; i= expected.length()); if (valid) { p = fn.c_str() + (len - expected.length()); #ifdef _WIN32 if (OS_PATH_SEPARATOR != '/') { // Input filename under cygwin most likely has / separators // whereas the expected string uses \\ separators. Adjust // them accordingly. for (char *c = const_cast(p); *c; ++c) { if (*c == '/') *c = OS_PATH_SEPARATOR; } } #endif // aidl assumes case-insensitivity on Mac Os and Windows. #if defined(__linux__) valid = (expected == p); #else valid = !strcasecmp(expected.c_str(), p); #endif } if (!valid) { fprintf(stderr, "%s:%d interface %s should be declared in a file" " called %s.\n", filename.c_str(), line, name.c_str(), expected.c_str()); } return valid; } bool check_filenames(const std::string& filename, const AidlDocument* doc) { if (!doc) return true; const AidlInterface* interface = doc->GetInterface(); if (interface) { return check_filename(filename, interface->GetPackage(), interface->GetName(), interface->GetLine()); } bool success = true; for (const auto& item : doc->GetParcelables()) { success &= check_filename(filename, item->GetPackage(), item->GetName(), item->GetLine()); } return success; } bool gather_types(const std::string& filename, const AidlDocument* doc, TypeNamespace* types) { bool success = true; const AidlInterface* interface = doc->GetInterface(); if (interface) return types->AddBinderType(*interface, filename); for (const auto& item : doc->GetParcelables()) { success &= types->AddParcelableType(*item, filename); } return success; } int check_types(const string& filename, const AidlInterface* c, TypeNamespace* types) { int err = 0; if (c->IsUtf8() && c->IsUtf8InCpp()) { cerr << filename << ":" << c->GetLine() << "Interface cannot be marked as both @utf8 and @utf8InCpp"; err = 1; } // Has to be a pointer due to deleting copy constructor. No idea why. map method_names; for (const auto& m : c->GetMethods()) { bool oneway = m->IsOneway() || c->IsOneway(); if (!types->MaybeAddContainerType(m->GetType())) { err = 1; // return type is invalid } const ValidatableType* return_type = types->GetReturnType(m->GetType(), filename, *c); if (!return_type) { err = 1; } m->GetMutableType()->SetLanguageType(return_type); if (oneway && m->GetType().GetName() != "void") { cerr << filename << ":" << m->GetLine() << " oneway method '" << m->GetName() << "' cannot return a value" << endl; err = 1; } int index = 1; for (const auto& arg : m->GetArguments()) { if (!types->MaybeAddContainerType(arg->GetType())) { err = 1; } const ValidatableType* arg_type = types->GetArgType(*arg, index, filename, *c); if (!arg_type) { err = 1; } arg->GetMutableType()->SetLanguageType(arg_type); if (oneway && arg->IsOut()) { cerr << filename << ":" << m->GetLine() << " oneway method '" << m->GetName() << "' cannot have out parameters" << endl; err = 1; } } auto it = method_names.find(m->GetName()); // prevent duplicate methods if (it == method_names.end()) { method_names[m->GetName()] = m.get(); } else { cerr << filename << ":" << m->GetLine() << " attempt to redefine method " << m->GetName() << "," << endl << filename << ":" << it->second->GetLine() << " previously defined here." << endl; err = 1; } } return err; } void write_common_dep_file(const string& output_file, const vector& aidl_sources, CodeWriter* writer, const bool ninja) { // Encode that the output file depends on aidl input files. writer->Write("%s : \\\n", output_file.c_str()); writer->Write(" %s", Join(aidl_sources, " \\\n ").c_str()); writer->Write("\n"); if (!ninja) { writer->Write("\n"); // Output ": " so make won't fail if the input .aidl file // has been deleted, moved or renamed in incremental build. for (const auto& src : aidl_sources) { writer->Write("%s :\n", src.c_str()); } } } bool write_java_dep_file(const JavaOptions& options, const vector>& imports, const IoDelegate& io_delegate, const string& output_file_name) { string dep_file_name = options.DependencyFilePath(); if (dep_file_name.empty()) { return true; // nothing to do } CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name); if (!writer) { LOG(ERROR) << "Could not open dependency file: " << dep_file_name; return false; } vector source_aidl = {options.input_file_name_}; for (const auto& import : imports) { if (!import->GetFilename().empty()) { source_aidl.push_back(import->GetFilename()); } } write_common_dep_file(output_file_name, source_aidl, writer.get(), options.DependencyFileNinja()); return true; } bool write_cpp_dep_file(const CppOptions& options, const AidlInterface& interface, const vector>& imports, const IoDelegate& io_delegate) { using ::android::aidl::cpp::HeaderFile; using ::android::aidl::cpp::ClassNames; string dep_file_name = options.DependencyFilePath(); if (dep_file_name.empty()) { return true; // nothing to do } CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name); if (!writer) { LOG(ERROR) << "Could not open dependency file: " << dep_file_name; return false; } vector source_aidl = {options.InputFileName()}; for (const auto& import : imports) { if (!import->GetFilename().empty()) { source_aidl.push_back(import->GetFilename()); } } write_common_dep_file(options.OutputCppFilePath(), source_aidl, writer.get(), options.DependencyFileNinja()); if (!options.DependencyFileNinja()) { vector headers; for (ClassNames c : {ClassNames::CLIENT, ClassNames::SERVER, ClassNames::INTERFACE}) { headers.push_back(options.OutputHeaderDir() + '/' + HeaderFile(interface, c, false /* use_os_sep */)); } writer->Write("\n"); // Generated headers also depend on the source aidl files. writer->Write("%s : \\\n %s\n", Join(headers, " \\\n ").c_str(), Join(source_aidl, " \\\n ").c_str()); } return true; } string generate_outputFileName(const JavaOptions& options, const AidlInterface& interface) { const string& name = interface.GetName(); string package = interface.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; string packageStr = package; size_t len = packageStr.length(); for (size_t i=0; i>& items) { // Check whether there are any methods with manually assigned id's and any that are not. // Either all method id's must be manually assigned or all of them must not. // Also, check for duplicates of user set id's and that the id's are within the proper bounds. set usedIds; bool hasUnassignedIds = false; bool hasAssignedIds = false; for (const auto& item : items) { if (item->HasId()) { hasAssignedIds = true; // Ensure that the user set id is not duplicated. if (usedIds.find(item->GetId()) != usedIds.end()) { // We found a duplicate id, so throw an error. fprintf(stderr, "%s:%d Found duplicate method id (%d) for method: %s\n", filename, item->GetLine(), item->GetId(), item->GetName().c_str()); return 1; } // Ensure that the user set id is within the appropriate limits if (item->GetId() < kMinUserSetMethodId || item->GetId() > kMaxUserSetMethodId) { fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n", filename, item->GetLine(), item->GetId(), item->GetName().c_str()); fprintf(stderr, " Value for id must be between %d and %d inclusive.\n", kMinUserSetMethodId, kMaxUserSetMethodId); return 1; } usedIds.insert(item->GetId()); } else { hasUnassignedIds = true; } if (hasAssignedIds && hasUnassignedIds) { fprintf(stderr, "%s: You must either assign id's to all methods or to none of them.\n", filename); return 1; } } // In the case that all methods have unassigned id's, set a unique id for them. if (hasUnassignedIds) { int newId = 0; for (const auto& item : items) { item->SetId(newId++); } } // success return 0; } bool validate_constants(const AidlInterface& interface) { bool success = true; set names; for (const std::unique_ptr& int_constant : interface.GetIntConstants()) { if (names.count(int_constant->GetName()) > 0) { LOG(ERROR) << "Found duplicate constant name '" << int_constant->GetName() << "'"; success = false; } names.insert(int_constant->GetName()); // We've logged an error message for this on object construction. success = success && int_constant->IsValid(); } for (const std::unique_ptr& string_constant : interface.GetStringConstants()) { if (names.count(string_constant->GetName()) > 0) { LOG(ERROR) << "Found duplicate constant name '" << string_constant->GetName() << "'"; success = false; } names.insert(string_constant->GetName()); // We've logged an error message for this on object construction. success = success && string_constant->IsValid(); } return success; } // TODO: Remove this in favor of using the YACC parser b/25479378 bool ParsePreprocessedLine(const string& line, string* decl, vector* package, string* class_name) { // erase all trailing whitespace and semicolons const size_t end = line.find_last_not_of(" ;\t"); if (end == string::npos) { return false; } if (line.rfind(';', end) != string::npos) { return false; } decl->clear(); string type; vector pieces = Split(line.substr(0, end + 1), " \t"); for (const string& piece : pieces) { if (piece.empty()) { continue; } if (decl->empty()) { *decl = std::move(piece); } else if (type.empty()) { type = std::move(piece); } else { return false; } } // Note that this logic is absolutely wrong. Given a parcelable // org.some.Foo.Bar, the class name is Foo.Bar, but this code will claim that // the class is just Bar. However, this was the way it was done in the past. // // See b/17415692 size_t dot_pos = type.rfind('.'); if (dot_pos != string::npos) { *class_name = type.substr(dot_pos + 1); *package = Split(type.substr(0, dot_pos), "."); } else { *class_name = type; package->clear(); } return true; } } // namespace namespace internals { bool parse_preprocessed_file(const IoDelegate& io_delegate, const string& filename, TypeNamespace* types) { bool success = true; unique_ptr line_reader = io_delegate.GetLineReader(filename); if (!line_reader) { LOG(ERROR) << "cannot open preprocessed file: " << filename; success = false; return success; } string line; unsigned lineno = 1; for ( ; line_reader->ReadLine(&line); ++lineno) { if (line.empty() || line.compare(0, 2, "//") == 0) { // skip comments and empty lines continue; } string decl; vector package; string class_name; if (!ParsePreprocessedLine(line, &decl, &package, &class_name)) { success = false; break; } if (decl == "parcelable") { AidlParcelable doc(new AidlQualifiedName(class_name, ""), lineno, package); types->AddParcelableType(doc, filename); } else if (decl == "interface") { auto temp = new std::vector>(); AidlInterface doc(class_name, lineno, "", false, temp, package); types->AddBinderType(doc, filename); } else { success = false; break; } } if (!success) { LOG(ERROR) << filename << ':' << lineno << " malformed preprocessed file line: '" << line << "'"; } return success; } AidlError load_and_validate_aidl( const std::vector& preprocessed_files, const std::vector& import_paths, const std::string& input_file_name, const IoDelegate& io_delegate, TypeNamespace* types, std::unique_ptr* returned_interface, std::vector>* returned_imports) { AidlError err = AidlError::OK; std::map> docs; // import the preprocessed file for (const string& s : preprocessed_files) { if (!parse_preprocessed_file(io_delegate, s, types)) { err = AidlError::BAD_PRE_PROCESSED_FILE; } } if (err != AidlError::OK) { return err; } // parse the input file Parser p{io_delegate}; if (!p.ParseFile(input_file_name)) { return AidlError::PARSE_ERROR; } AidlDocument* parsed_doc = p.GetDocument(); unique_ptr interface(parsed_doc->ReleaseInterface()); if (!interface) { LOG(ERROR) << "refusing to generate code from aidl file defining " "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() << "'"; return AidlError::BAD_PACKAGE; } // parse the imports of the input file ImportResolver import_resolver{io_delegate, import_paths}; for (auto& import : p.GetImports()) { if (types->HasImportType(*import)) { // There are places in the Android tree where an import doesn't resolve, // but we'll pick the type up through the preprocessed types. // This seems like an error, but legacy support demands we support it... continue; } string import_path = import_resolver.FindImportFile(import->GetNeededClass()); if (import_path.empty()) { cerr << import->GetFileFrom() << ":" << import->GetLine() << ": couldn't find import for class " << import->GetNeededClass() << endl; err = AidlError::BAD_IMPORT; continue; } import->SetFilename(import_path); Parser p{io_delegate}; if (!p.ParseFile(import->GetFilename())) { cerr << "error while parsing import for class " << import->GetNeededClass() << endl; err = AidlError::BAD_IMPORT; continue; } std::unique_ptr document(p.ReleaseDocument()); if (!check_filenames(import->GetFilename(), document.get())) err = AidlError::BAD_IMPORT; docs[import.get()] = std::move(document); } if (err != AidlError::OK) { return err; } // gather the types that have been declared if (!types->AddBinderType(*interface.get(), input_file_name)) { err = AidlError::BAD_TYPE; } interface->SetLanguageType(types->GetInterfaceType(*interface)); for (const auto& import : p.GetImports()) { // If we skipped an unresolved import above (see comment there) we'll have // an empty bucket here. const auto import_itr = docs.find(import.get()); if (import_itr == docs.cend()) { continue; } if (!gather_types(import->GetFilename(), import_itr->second.get(), types)) { err = AidlError::BAD_TYPE; } } // check the referenced types in parsed_doc to make sure we've imported them if (check_types(input_file_name, interface.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) { return AidlError::BAD_METHOD_ID; } if (!validate_constants(*interface)) { return AidlError::BAD_CONSTANTS; } if (returned_interface) *returned_interface = std::move(interface); if (returned_imports) p.ReleaseImports(returned_imports); return AidlError::OK; } } // namespace internals int compile_aidl_to_cpp(const CppOptions& options, const IoDelegate& io_delegate) { unique_ptr interface; std::vector> imports; unique_ptr types(new cpp::TypeNamespace()); types->Init(); AidlError err = internals::load_and_validate_aidl( std::vector{}, // no preprocessed files options.ImportPaths(), options.InputFileName(), io_delegate, types.get(), &interface, &imports); if (err != AidlError::OK) { return 1; } if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) { return 1; } return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1; } int compile_aidl_to_java(const JavaOptions& options, const IoDelegate& io_delegate) { unique_ptr interface; std::vector> imports; unique_ptr types(new java::JavaTypeNamespace()); types->Init(); AidlError aidl_err = internals::load_and_validate_aidl( options.preprocessed_files_, options.import_paths_, options.input_file_name_, io_delegate, types.get(), &interface, &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. // Just generate a dep file and exit quietly. The dep file is for a legacy // use case by the SDK. write_java_dep_file(options, imports, io_delegate, ""); return 0; } if (aidl_err != AidlError::OK) { return 1; } 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); } // make sure the folders of the output file all exists if (!io_delegate.CreatePathForFile(output_file_name)) { return 1; } if (!write_java_dep_file(options, imports, io_delegate, output_file_name)) { return 1; } return generate_java(output_file_name, options.input_file_name_.c_str(), interface.get(), types.get(), io_delegate); } bool preprocess_aidl(const JavaOptions& options, const IoDelegate& io_delegate) { unique_ptr writer = io_delegate.GetCodeWriter(options.output_file_name_); for (const auto& file : options.files_to_preprocess_) { Parser p{io_delegate}; if (!p.ParseFile(file)) return false; AidlDocument* doc = p.GetDocument(); string line; const AidlInterface* interface = doc->GetInterface(); if (interface != nullptr && !writer->Write("interface %s;\n", interface->GetCanonicalName().c_str())) { return false; } for (const auto& parcelable : doc->GetParcelables()) { if (!writer->Write("parcelable %s;\n", parcelable->GetCanonicalName().c_str())) { return false; } } } return writer->Close(); } } // namespace android } // namespace aidl aidl.h0100644 0000000 0000000 00000004017 13277516055 010704 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_AIDL_H_ #define AIDL_AIDL_H_ #include #include #include #include #include "aidl_language.h" #include "io_delegate.h" #include "options.h" #include "type_namespace.h" namespace android { namespace aidl { enum class AidlError { UNKOWN = std::numeric_limits::min(), BAD_PRE_PROCESSED_FILE, PARSE_ERROR, FOUND_PARCELABLE, BAD_PACKAGE, BAD_IMPORT, BAD_TYPE, BAD_METHOD_ID, GENERATION_ERROR, BAD_CONSTANTS, OK = 0, }; int compile_aidl_to_cpp(const CppOptions& options, const IoDelegate& io_delegate); int compile_aidl_to_java(const JavaOptions& options, const IoDelegate& io_delegate); bool preprocess_aidl(const JavaOptions& options, const IoDelegate& io_delegate); namespace internals { AidlError load_and_validate_aidl( const std::vector& preprocessed_files, const std::vector& import_paths, const std::string& input_file_name, const IoDelegate& io_delegate, TypeNamespace* types, std::unique_ptr* returned_interface, std::vector>* returned_imports); bool parse_preprocessed_file(const IoDelegate& io_delegate, const std::string& filename, TypeNamespace* types); } // namespace internals } // namespace android } // namespace aidl #endif // AIDL_AIDL_H_ aidl_language.cpp0100644 0000000 0000000 00000020644 13277516055 013106 0ustar000000000 0000000 #include "aidl_language.h" #include #include #include #include #include #include #include #include "aidl_language_y.h" #include "logging.h" #ifdef _WIN32 int isatty(int fd) { return (fd == 0); } #endif using android::aidl::IoDelegate; using android::base::Join; using android::base::Split; using std::cerr; using std::endl; using std::string; using std::unique_ptr; void yylex_init(void **); void yylex_destroy(void *); void yyset_in(FILE *f, void *); int yyparse(Parser*); YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *); void yy_delete_buffer(YY_BUFFER_STATE, void *); AidlToken::AidlToken(const std::string& text, const std::string& comments) : text_(text), comments_(comments) {} AidlType::AidlType(const std::string& name, unsigned line, const std::string& comments, bool is_array) : name_(name), line_(line), is_array_(is_array), comments_(comments) {} string AidlType::ToString() const { return name_ + (is_array_ ? "[]" : ""); } AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type, std::string name, unsigned line) : type_(type), direction_(direction), direction_specified_(true), name_(name), line_(line) {} AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line) : type_(type), direction_(AidlArgument::IN_DIR), direction_specified_(false), name_(name), line_(line) {} string AidlArgument::ToString() const { string ret; if (direction_specified_) { switch(direction_) { case AidlArgument::IN_DIR: ret += "in "; break; case AidlArgument::OUT_DIR: ret += "out "; break; case AidlArgument::INOUT_DIR: ret += "inout "; break; } } ret += type_->ToString(); ret += " "; ret += name_; return ret; } AidlIntConstant::AidlIntConstant(std::string name, int32_t value) : name_(name), value_(value), is_valid_(true) {} AidlIntConstant::AidlIntConstant(std::string name, std::string value, unsigned line_number) : name_(name) { uint32_t unsigned_val; if (!android::base::ParseUint(value.c_str(), &unsigned_val)) { is_valid_ = false; LOG(ERROR) << "Found invalid int value '" << value << "' on line " << line_number; } else { // Converting from unsigned to signed integer. value_ = unsigned_val; is_valid_ = true; } } AidlStringConstant::AidlStringConstant(std::string name, std::string value, unsigned line_number) : name_(name), value_(value) { is_valid_ = true; for (size_t i = 0; i < value_.length(); ++i) { const char& c = value_[i]; if (c <= 0x1f || // control characters are < 0x20 c >= 0x7f || // DEL is 0x7f c == '\\') { // Disallow backslashes for future proofing. LOG(ERROR) << "Found invalid character at index " << i << " in string constant '" << value_ << "' beginning on line " << line_number; is_valid_ = false; break; } } } AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name, std::vector>* args, unsigned line, const std::string& comments, int id) : oneway_(oneway), comments_(comments), type_(type), name_(name), line_(line), arguments_(std::move(*args)), id_(id) { has_id_ = true; delete args; for (const unique_ptr& a : arguments_) { if (a->IsIn()) { in_arguments_.push_back(a.get()); } if (a->IsOut()) { out_arguments_.push_back(a.get()); } } } AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name, std::vector>* args, unsigned line, const std::string& comments) : AidlMethod(oneway, type, name, args, line, comments, 0) { has_id_ = false; } Parser::Parser(const IoDelegate& io_delegate) : io_delegate_(io_delegate) { yylex_init(&scanner_); } AidlParcelable::AidlParcelable(AidlQualifiedName* name, unsigned line, const std::vector& package, const std::string& cpp_header) : name_(name), line_(line), package_(package), cpp_header_(cpp_header) { // Strip off quotation marks if we actually have a cpp header. if (cpp_header_.length() >= 2) { cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2); } } std::string AidlParcelable::GetPackage() const { return Join(package_, '.'); } std::string AidlParcelable::GetCanonicalName() const { if (package_.empty()) { return GetName(); } return GetPackage() + "." + GetName(); } AidlInterface::AidlInterface(const std::string& name, unsigned line, const std::string& comments, bool oneway, std::vector>* members, const std::vector& package) : name_(name), comments_(comments), line_(line), oneway_(oneway), package_(package) { for (auto& member : *members) { AidlMember* local = member.release(); AidlMethod* method = local->AsMethod(); AidlIntConstant* int_constant = local->AsIntConstant(); AidlStringConstant* string_constant = local->AsStringConstant(); if (method) { methods_.emplace_back(method); } else if (int_constant) { int_constants_.emplace_back(int_constant); } else if (string_constant) { string_constants_.emplace_back(string_constant); } else { LOG(FATAL) << "Member is neither method nor constant!"; } } delete members; } std::string AidlInterface::GetPackage() const { return Join(package_, '.'); } std::string AidlInterface::GetCanonicalName() const { if (package_.empty()) { return GetName(); } return GetPackage() + "." + GetName(); } AidlDocument::AidlDocument(AidlInterface* interface) : interface_(interface) {} AidlQualifiedName::AidlQualifiedName(std::string term, std::string comments) : terms_({term}), comments_(comments) { if (term.find('.') != string::npos) { terms_ = Split(term, "."); for (const auto& term: terms_) { if (term.empty()) { LOG(FATAL) << "Malformed qualified identifier: '" << term << "'"; } } } } void AidlQualifiedName::AddTerm(const std::string& term) { terms_.push_back(term); } AidlImport::AidlImport(const std::string& from, const std::string& needed_class, unsigned line) : from_(from), needed_class_(needed_class), line_(line) {} Parser::~Parser() { if (raw_buffer_) { yy_delete_buffer(buffer_, scanner_); raw_buffer_.reset(); } yylex_destroy(scanner_); } bool Parser::ParseFile(const string& filename) { // Make sure we can read the file first, before trashing previous state. unique_ptr new_buffer = io_delegate_.GetFileContents(filename); if (!new_buffer) { LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'"; return false; } // Throw away old parsing state if we have any. if (raw_buffer_) { yy_delete_buffer(buffer_, scanner_); raw_buffer_.reset(); } raw_buffer_ = std::move(new_buffer); // We're going to scan this buffer in place, and yacc demands we put two // nulls at the end. raw_buffer_->append(2u, '\0'); filename_ = filename; package_.reset(); error_ = 0; document_.reset(); buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_); if (yy::parser(this).parse() != 0 || error_ != 0) { return false;} if (document_.get() != nullptr) return true; LOG(ERROR) << "Parser succeeded but yielded no document!"; return false; } void Parser::ReportError(const string& err, unsigned line) { cerr << filename_ << ":" << line << ": " << err << endl; error_ = 1; } std::vector Parser::Package() const { if (!package_) { return {}; } return package_->GetTerms(); } void Parser::AddImport(AidlQualifiedName* name, unsigned line) { imports_.emplace_back(new AidlImport(this->FileName(), name->GetDotName(), line)); delete name; } aidl_language.h0100644 0000000 0000000 00000030670 13277516055 012553 0ustar000000000 0000000 #ifndef AIDL_AIDL_LANGUAGE_H_ #define AIDL_AIDL_LANGUAGE_H_ #include #include #include #include #include #include struct yy_buffer_state; typedef yy_buffer_state* YY_BUFFER_STATE; class AidlToken { public: AidlToken(const std::string& text, const std::string& comments); const std::string& GetText() const { return text_; } const std::string& GetComments() const { return comments_; } private: std::string text_; std::string comments_; DISALLOW_COPY_AND_ASSIGN(AidlToken); }; class AidlNode { public: AidlNode() = default; virtual ~AidlNode() = default; private: DISALLOW_COPY_AND_ASSIGN(AidlNode); }; namespace android { namespace aidl { class ValidatableType; } // namespace aidl } // namespace android class AidlAnnotatable : public AidlNode { public: enum Annotation : uint32_t { AnnotationNone = 0, AnnotationNullable = 1 << 0, AnnotationUtf8 = 1 << 1, AnnotationUtf8InCpp = 1 << 2, }; AidlAnnotatable() = default; virtual ~AidlAnnotatable() = default; void Annotate(AidlAnnotatable::Annotation annotation) { annotations_ = static_cast(annotations_ | annotation); } bool IsNullable() const { return annotations_ & AnnotationNullable; } bool IsUtf8() const { return annotations_ & AnnotationUtf8; } bool IsUtf8InCpp() const { return annotations_ & AnnotationUtf8InCpp; } private: Annotation annotations_ = AnnotationNone; DISALLOW_COPY_AND_ASSIGN(AidlAnnotatable); }; class AidlType : public AidlAnnotatable { public: AidlType(const std::string& name, unsigned line, const std::string& comments, bool is_array); virtual ~AidlType() = default; const std::string& GetName() const { return name_; } unsigned GetLine() const { return line_; } bool IsArray() const { return is_array_; } const std::string& GetComments() const { return comments_; } std::string ToString() const; void SetLanguageType(const android::aidl::ValidatableType* language_type) { language_type_ = language_type; } template const T* GetLanguageType() const { return reinterpret_cast(language_type_); } private: std::string name_; unsigned line_; bool is_array_; std::string comments_; const android::aidl::ValidatableType* language_type_ = nullptr; DISALLOW_COPY_AND_ASSIGN(AidlType); }; class AidlArgument : public AidlNode { public: enum Direction { IN_DIR = 1, OUT_DIR = 2, INOUT_DIR = 3 }; AidlArgument(AidlArgument::Direction direction, AidlType* type, std::string name, unsigned line); AidlArgument(AidlType* type, std::string name, unsigned line); virtual ~AidlArgument() = default; Direction GetDirection() const { return direction_; } bool IsOut() const { return direction_ & OUT_DIR; } 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 type_; Direction direction_; bool direction_specified_; std::string name_; unsigned line_; DISALLOW_COPY_AND_ASSIGN(AidlArgument); }; class AidlMethod; class AidlIntConstant; class AidlStringConstant; class AidlMember : public AidlNode { public: AidlMember() = default; virtual ~AidlMember() = default; virtual AidlMethod* AsMethod() { return nullptr; } virtual AidlIntConstant* AsIntConstant() { return nullptr; } virtual AidlStringConstant* AsStringConstant() { return nullptr; } private: DISALLOW_COPY_AND_ASSIGN(AidlMember); }; class AidlIntConstant : public AidlMember { public: AidlIntConstant(std::string name, int32_t value); AidlIntConstant(std::string name, std::string value, unsigned line_number); virtual ~AidlIntConstant() = default; const std::string& GetName() const { return name_; } int GetValue() const { return value_; } bool IsValid() const { return is_valid_; } AidlIntConstant* AsIntConstant() override { return this; } private: std::string name_; int32_t value_; bool is_valid_; DISALLOW_COPY_AND_ASSIGN(AidlIntConstant); }; class AidlStringConstant : public AidlMember { public: AidlStringConstant(std::string name, std::string value, unsigned line_number); virtual ~AidlStringConstant() = default; const std::string& GetName() const { return name_; } const std::string& GetValue() const { return value_; } bool IsValid() const { return is_valid_; } AidlStringConstant* AsStringConstant() override { return this; } private: std::string name_; std::string value_; bool is_valid_; DISALLOW_COPY_AND_ASSIGN(AidlStringConstant); }; class AidlMethod : public AidlMember { public: AidlMethod(bool oneway, AidlType* type, std::string name, std::vector>* args, unsigned line, const std::string& comments); AidlMethod(bool oneway, AidlType* type, std::string name, std::vector>* args, unsigned line, const std::string& comments, int id); virtual ~AidlMethod() = default; AidlMethod* AsMethod() override { return this; } const std::string& GetComments() const { return comments_; } const AidlType& GetType() const { return *type_; } AidlType* GetMutableType() { return type_.get(); } bool IsOneway() const { return oneway_; } const std::string& GetName() const { return name_; } unsigned GetLine() const { return line_; } bool HasId() const { return has_id_; } int GetId() { return id_; } void SetId(unsigned id) { id_ = id; } const std::vector>& GetArguments() const { return arguments_; } // An inout parameter will appear in both GetInArguments() // and GetOutArguments(). AidlMethod retains ownership of the argument // pointers returned in this way. const std::vector& GetInArguments() const { return in_arguments_; } const std::vector& GetOutArguments() const { return out_arguments_; } private: bool oneway_; std::string comments_; std::unique_ptr type_; std::string name_; unsigned line_; const std::vector> arguments_; std::vector in_arguments_; std::vector out_arguments_; bool has_id_; int id_; DISALLOW_COPY_AND_ASSIGN(AidlMethod); }; class AidlParcelable; class AidlInterface; class AidlDocument : public AidlNode { public: AidlDocument() = default; explicit AidlDocument(AidlInterface* interface); virtual ~AidlDocument() = default; const AidlInterface* GetInterface() const { return interface_.get(); } AidlInterface* ReleaseInterface() { return interface_.release(); } const std::vector>& GetParcelables() const { return parcelables_; } void AddParcelable(AidlParcelable* parcelable) { parcelables_.push_back(std::unique_ptr(parcelable)); } private: std::vector> parcelables_; std::unique_ptr interface_; DISALLOW_COPY_AND_ASSIGN(AidlDocument); }; class AidlQualifiedName : public AidlNode { public: AidlQualifiedName(std::string term, std::string comments); virtual ~AidlQualifiedName() = default; const std::vector& GetTerms() const { return terms_; } const std::string& GetComments() const { return comments_; } std::string GetDotName() const { return android::base::Join(terms_, '.'); } std::string GetColonName() const { return android::base::Join(terms_, "::"); } void AddTerm(const std::string& term); private: std::vector terms_; std::string comments_; DISALLOW_COPY_AND_ASSIGN(AidlQualifiedName); }; class AidlParcelable : public AidlNode { public: AidlParcelable(AidlQualifiedName* name, unsigned line, const std::vector& package, const std::string& cpp_header = ""); virtual ~AidlParcelable() = default; std::string GetName() const { return name_->GetDotName(); } // C++ uses "::" instead of "." to refer to a inner class. std::string GetCppName() const { return name_->GetColonName(); } unsigned GetLine() const { return line_; } std::string GetPackage() const; const std::vector& GetSplitPackage() const { return package_; } std::string GetCppHeader() const { return cpp_header_; } std::string GetCanonicalName() const; private: std::unique_ptr name_; unsigned line_; const std::vector package_; std::string cpp_header_; DISALLOW_COPY_AND_ASSIGN(AidlParcelable); }; class AidlInterface : public AidlAnnotatable { public: AidlInterface(const std::string& name, unsigned line, const std::string& comments, bool oneway_, std::vector>* members, const std::vector& package); virtual ~AidlInterface() = default; const std::string& GetName() const { return name_; } unsigned GetLine() const { return line_; } const std::string& GetComments() const { return comments_; } bool IsOneway() const { return oneway_; } const std::vector>& GetMethods() const { return methods_; } const std::vector>& GetIntConstants() const { return int_constants_; } const std::vector>& GetStringConstants() const { return string_constants_; } std::string GetPackage() const; std::string GetCanonicalName() const; const std::vector& GetSplitPackage() const { return package_; } void SetLanguageType(const android::aidl::ValidatableType* language_type) { language_type_ = language_type; } template const T* GetLanguageType() const { return reinterpret_cast(language_type_); } private: std::string name_; std::string comments_; unsigned line_; bool oneway_; std::vector> methods_; std::vector> int_constants_; std::vector> string_constants_; std::vector package_; const android::aidl::ValidatableType* language_type_ = nullptr; DISALLOW_COPY_AND_ASSIGN(AidlInterface); }; class AidlImport : public AidlNode { public: AidlImport(const std::string& from, const std::string& needed_class, unsigned line); virtual ~AidlImport() = default; const std::string& GetFileFrom() const { return from_; } const std::string& GetFilename() const { return filename_; } const std::string& GetNeededClass() const { return needed_class_; } unsigned GetLine() const { return line_; } void SetFilename(const std::string& filename) { filename_ = filename; } private: std::string from_; std::string filename_; std::string needed_class_; unsigned line_; DISALLOW_COPY_AND_ASSIGN(AidlImport); }; class Parser { public: explicit Parser(const android::aidl::IoDelegate& io_delegate); ~Parser(); // Parse contents of file |filename|. bool ParseFile(const std::string& filename); void ReportError(const std::string& err, unsigned line); bool FoundNoErrors() const { return error_ == 0; } const std::string& FileName() const { return filename_; } void* Scanner() const { return scanner_; } void SetDocument(AidlDocument* doc) { document_.reset(doc); }; void AddImport(AidlQualifiedName* name, unsigned line); std::vector Package() const; void SetPackage(AidlQualifiedName* name) { package_.reset(name); } AidlDocument* GetDocument() const { return document_.get(); } AidlDocument* ReleaseDocument() { return document_.release(); } const std::vector>& GetImports() { return imports_; } void ReleaseImports(std::vector>* ret) { *ret = std::move(imports_); imports_.clear(); } private: const android::aidl::IoDelegate& io_delegate_; int error_ = 0; std::string filename_; std::unique_ptr package_; void* scanner_ = nullptr; std::unique_ptr document_; std::vector> imports_; std::unique_ptr raw_buffer_; YY_BUFFER_STATE buffer_; DISALLOW_COPY_AND_ASSIGN(Parser); }; #endif // AIDL_AIDL_LANGUAGE_H_ aidl_language_l.ll0100644 0000000 0000000 00000007432 13277516055 013246 0ustar000000000 0000000 %{ #include #include #include "aidl_language.h" #include "aidl_language_y.h" #define YY_USER_ACTION yylloc->columns(yyleng); %} %option yylineno %option noyywrap %option reentrant %option bison-bridge %option bison-locations %x COPYING LONG_COMMENT identifier [_a-zA-Z][_a-zA-Z0-9]* whitespace ([ \t\r]+) intvalue [-+]?(0|[1-9][0-9]*) hexvalue 0[x|X][0-9a-fA-F]+ %% %{ /* This happens at every call to yylex (every time we receive one token) */ std::string extra_text; yylloc->step(); %} \%\%\{ { extra_text += "/**"; BEGIN(COPYING); } \}\%\% { extra_text += "**/"; yylloc->step(); BEGIN(INITIAL); } .* { extra_text += yytext; } \n+ { extra_text += yytext; yylloc->lines(yyleng); } \/\* { extra_text += yytext; BEGIN(LONG_COMMENT); } \*+\/ { extra_text += yytext; yylloc->step(); BEGIN(INITIAL); } \*+ { extra_text += yytext; } \n+ { extra_text += yytext; yylloc->lines(yyleng); } [^*\n]+ { extra_text += yytext; } \"[^\"]*\" { yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::C_STR; } \/\/.*\n { extra_text += yytext; yylloc->lines(1); yylloc->step(); } \n+ { yylloc->lines(yyleng); yylloc->step(); } {whitespace} {} <> { yyterminate(); } /* symbols */ ; { return ';'; } \{ { return '{'; } \} { return '}'; } = { return '='; } , { return ','; } \. { return '.'; } \( { return '('; } \) { return ')'; } \[ { return '['; } \] { return ']'; } \< { return '<'; } \> { return '>'; } /* keywords */ parcelable { return yy::parser::token::PARCELABLE; } import { return yy::parser::token::IMPORT; } package { return yy::parser::token::PACKAGE; } int { return yy::parser::token::INT; } String { return yy::parser::token::STRING; } in { return yy::parser::token::IN; } out { return yy::parser::token::OUT; } inout { return yy::parser::token::INOUT; } cpp_header { return yy::parser::token::CPP_HEADER; } const { return yy::parser::token::CONST; } @nullable { return yy::parser::token::ANNOTATION_NULLABLE; } @utf8 { return yy::parser::token::ANNOTATION_UTF8; } @utf8InCpp { return yy::parser::token::ANNOTATION_UTF8_CPP; } interface { yylval->token = new AidlToken("interface", extra_text); return yy::parser::token::INTERFACE; } oneway { yylval->token = new AidlToken("oneway", extra_text); return yy::parser::token::ONEWAY; } /* scalars */ {identifier} { yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::IDENTIFIER; } {intvalue} { yylval->integer = std::stoi(yytext); return yy::parser::token::INTVALUE; } {hexvalue} { yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::HEXVALUE; } /* syntax error! */ . { printf("UNKNOWN(%s)", yytext); yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::IDENTIFIER; } %% // comment and whitespace handling // ================================================ aidl_language_y.yy0100644 0000000 0000000 00000020623 13277516055 013312 0ustar000000000 0000000 %{ #include "aidl_language.h" #include "aidl_language_y.h" #include #include #include int yylex(yy::parser::semantic_type *, yy::parser::location_type *, void *); #define lex_scanner ps->Scanner() %} %parse-param { Parser* ps } %lex-param { void *lex_scanner } %pure-parser %skeleton "glr.cc" %union { AidlToken* token; int integer; std::string *str; AidlType::Annotation annotation; AidlType::Annotation annotation_list; AidlType* type; AidlType* unannotated_type; AidlArgument* arg; AidlArgument::Direction direction; std::vector>* arg_list; AidlMethod* method; AidlMember* constant; std::vector>* members; AidlQualifiedName* qname; AidlInterface* interface_obj; AidlParcelable* parcelable; AidlDocument* parcelable_list; } %token IDENTIFIER INTERFACE ONEWAY C_STR HEXVALUE %token INTVALUE %token '(' ')' ',' '=' '[' ']' '<' '>' '.' '{' '}' ';' %token IN OUT INOUT PACKAGE IMPORT PARCELABLE CPP_HEADER CONST INT STRING %token ANNOTATION_NULLABLE ANNOTATION_UTF8 ANNOTATION_UTF8_CPP %type parcelable_decls %type parcelable_decl %type members %type interface_decl %type method_decl %type constant_decl %type annotation %typeannotation_list %type type %type unannotated_type %type arg_list %type arg %type direction %type generic_list %type qualified_name %type identifier error %% document : package imports parcelable_decls { ps->SetDocument($3); } | package imports interface_decl { ps->SetDocument(new AidlDocument($3)); }; /* A couple of tokens that are keywords elsewhere are identifiers when * occurring in the identifier position. Therefore identifier is a * non-terminal, which is either an IDENTIFIER token, or one of the * aforementioned keyword tokens. */ identifier : IDENTIFIER { $$ = $1; } | CPP_HEADER { $$ = new AidlToken("cpp_header", ""); } | INT { $$ = new AidlToken("int", ""); } | STRING { $$ = new AidlToken("String", ""); } ; package : {} | PACKAGE qualified_name ';' { ps->SetPackage($2); }; imports : {} | import imports {}; import : IMPORT qualified_name ';' { ps->AddImport($2, @1.begin.line); }; qualified_name : identifier { $$ = new AidlQualifiedName($1->GetText(), $1->GetComments()); delete $1; } | qualified_name '.' identifier { $$ = $1; $$->AddTerm($3->GetText()); delete $3; }; parcelable_decls : { $$ = new AidlDocument(); } | parcelable_decls parcelable_decl { $$ = $1; $$->AddParcelable($2); } | parcelable_decls error { fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n", ps->FileName().c_str(), @2.begin.line, $2->GetText().c_str()); $$ = $1; }; parcelable_decl : PARCELABLE qualified_name ';' { $$ = new AidlParcelable($2, @2.begin.line, ps->Package()); } | PARCELABLE qualified_name CPP_HEADER C_STR ';' { $$ = new AidlParcelable($2, @2.begin.line, ps->Package(), $4->GetText()); } | PARCELABLE ';' { fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n", ps->FileName().c_str(), @1.begin.line); $$ = NULL; } | PARCELABLE error ';' { fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n", ps->FileName().c_str(), @2.begin.line, $2->GetText().c_str()); $$ = NULL; }; interface_decl : annotation_list INTERFACE identifier '{' members '}' { $$ = new AidlInterface($3->GetText(), @2.begin.line, $2->GetComments(), false, $5, ps->Package()); $$->Annotate($1); delete $2; delete $3; } | annotation_list ONEWAY INTERFACE identifier '{' members '}' { $$ = new AidlInterface($4->GetText(), @4.begin.line, $2->GetComments(), true, $6, ps->Package()); $$->Annotate($1); delete $2; delete $3; delete $4; } | annotation_list INTERFACE error '{' members '}' { fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected " "type name, saw \"%s\"\n", ps->FileName().c_str(), @3.begin.line, $3->GetText().c_str()); $$ = NULL; delete $2; delete $3; delete $5; } | annotation_list INTERFACE error '}' { fprintf(stderr, "%s:%d: syntax error in interface declaration. Expected " "type name, saw \"%s\"\n", ps->FileName().c_str(), @3.begin.line, $3->GetText().c_str()); $$ = NULL; delete $2; delete $3; }; members : { $$ = new std::vector>(); } | members method_decl { $1->push_back(std::unique_ptr($2)); } | members constant_decl { $1->push_back(std::unique_ptr($2)); } | members error ';' { fprintf(stderr, "%s:%d: syntax error before ';' " "(expected method or constant declaration)\n", ps->FileName().c_str(), @3.begin.line); $$ = $1; }; constant_decl : CONST INT identifier '=' INTVALUE ';' { $$ = new AidlIntConstant($3->GetText(), $5); delete $3; } | CONST INT identifier '=' HEXVALUE ';' { $$ = new AidlIntConstant($3->GetText(), $5->GetText(), @5.begin.line); delete $3; } | CONST STRING identifier '=' C_STR ';' { $$ = new AidlStringConstant($3->GetText(), $5->GetText(), @5.begin.line); delete $3; delete $5; } ; method_decl : type identifier '(' arg_list ')' ';' { $$ = new AidlMethod(false, $1, $2->GetText(), $4, @2.begin.line, $1->GetComments()); delete $2; } | ONEWAY type identifier '(' arg_list ')' ';' { $$ = new AidlMethod(true, $2, $3->GetText(), $5, @3.begin.line, $1->GetComments()); delete $1; delete $3; } | type identifier '(' arg_list ')' '=' INTVALUE ';' { $$ = new AidlMethod(false, $1, $2->GetText(), $4, @2.begin.line, $1->GetComments(), $7); delete $2; } | ONEWAY type identifier '(' arg_list ')' '=' INTVALUE ';' { $$ = new AidlMethod(true, $2, $3->GetText(), $5, @3.begin.line, $1->GetComments(), $8); delete $1; delete $3; }; arg_list : { $$ = new std::vector>(); } | arg { $$ = new std::vector>(); $$->push_back(std::unique_ptr($1)); } | arg_list ',' arg { $$ = $1; $$->push_back(std::unique_ptr($3)); } | error { fprintf(stderr, "%s:%d: syntax error in parameter list\n", ps->FileName().c_str(), @1.begin.line); $$ = new std::vector>(); }; arg : direction type identifier { $$ = new AidlArgument($1, $2, $3->GetText(), @3.begin.line); delete $3; }; | type identifier { $$ = new AidlArgument($1, $2->GetText(), @2.begin.line); delete $2; }; unannotated_type : qualified_name { $$ = new AidlType($1->GetDotName(), @1.begin.line, $1->GetComments(), false); delete $1; } | qualified_name '[' ']' { $$ = new AidlType($1->GetDotName(), @1.begin.line, $1->GetComments(), true); delete $1; } | qualified_name '<' generic_list '>' { $$ = new AidlType($1->GetDotName() + "<" + *$3 + ">", @1.begin.line, $1->GetComments(), false); delete $1; delete $3; }; type : annotation_list unannotated_type { $$ = $2; $2->Annotate($1); }; generic_list : qualified_name { $$ = new std::string($1->GetDotName()); delete $1; } | generic_list ',' qualified_name { $$ = new std::string(*$1 + "," + $3->GetDotName()); delete $1; delete $3; }; annotation_list : { $$ = AidlType::AnnotationNone; } | annotation_list annotation { $$ = static_cast($1 | $2); }; annotation : ANNOTATION_NULLABLE { $$ = AidlType::AnnotationNullable; } | ANNOTATION_UTF8 { $$ = AidlType::AnnotationUtf8; } | ANNOTATION_UTF8_CPP { $$ = AidlType::AnnotationUtf8InCpp; }; direction : IN { $$ = AidlArgument::IN_DIR; } | OUT { $$ = AidlArgument::OUT_DIR; } | INOUT { $$ = AidlArgument::INOUT_DIR; }; %% #include #include void yy::parser::error(const yy::parser::location_type& l, const std::string& errstr) { ps->ReportError(errstr, l.begin.line); } aidl_unittest.cpp0100644 0000000 0000000 00000040356 13277516055 013204 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include #include #include #include #include "aidl.h" #include "aidl_language.h" #include "tests/fake_io_delegate.h" #include "type_cpp.h" #include "type_java.h" #include "type_namespace.h" using android::aidl::test::FakeIoDelegate; using android::base::StringPrintf; using std::set; using std::string; using std::unique_ptr; using std::vector; using android::aidl::internals::parse_preprocessed_file; namespace android { namespace aidl { namespace { const char kExpectedDepFileContents[] = R"(place/for/output/p/IFoo.java : \ p/IFoo.aidl p/IFoo.aidl : )"; const char kExpectedNinjaDepFileContents[] = R"(place/for/output/p/IFoo.java : \ p/IFoo.aidl )"; const char kExpectedParcelableDepFileContents[] = R"( : \ p/Foo.aidl p/Foo.aidl : )"; } // namespace class AidlTest : public ::testing::Test { protected: void SetUp() override { java_types_.Init(); cpp_types_.Init(); } unique_ptr Parse(const string& path, const string& contents, TypeNamespace* types, AidlError* error = nullptr) { io_delegate_.SetFileContents(path, contents); unique_ptr ret; std::vector> imports; AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl( preprocessed_files_, import_paths_, path, io_delegate_, types, &ret, &imports); if (error != nullptr) { *error = actual_error; } return ret; } FakeIoDelegate io_delegate_; vector preprocessed_files_; vector import_paths_; java::JavaTypeNamespace java_types_; cpp::TypeNamespace cpp_types_; }; TEST_F(AidlTest, JavaAcceptsMissingPackage) { EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_)); } TEST_F(AidlTest, RejectsArraysOfBinders) { import_paths_.push_back(""); io_delegate_.SetFileContents("bar/IBar.aidl", "package bar; interface IBar {}"); string path = "foo/IFoo.aidl"; string contents = "package foo;\n" "import bar.IBar;\n" "interface IFoo { void f(in IBar[] input); }"; EXPECT_EQ(nullptr, Parse(path, contents, &java_types_)); EXPECT_EQ(nullptr, Parse(path, contents, &cpp_types_)); } TEST_F(AidlTest, CppRejectsMissingPackage) { EXPECT_EQ(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &cpp_types_)); EXPECT_NE(nullptr, Parse("a/IFoo.aidl", "package a; interface IFoo { }", &cpp_types_)); } TEST_F(AidlTest, RejectsOnewayOutParameters) { string oneway_interface = "package a; oneway interface IFoo { void f(out int bar); }"; string oneway_method = "package a; interface IBar { oneway void f(out int bar); }"; EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &cpp_types_)); EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_interface, &java_types_)); EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &cpp_types_)); EXPECT_EQ(nullptr, Parse("a/IBar.aidl", oneway_method, &java_types_)); } TEST_F(AidlTest, RejectsOnewayNonVoidReturn) { string oneway_method = "package a; interface IFoo { oneway int f(); }"; EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_)); EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_)); } TEST_F(AidlTest, RejectsNullablePrimitive) { string oneway_method = "package a; interface IFoo { @nullable int f(); }"; EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_)); EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_)); } TEST_F(AidlTest, ParsesNullableAnnotation) { for (auto is_nullable: {true, false}) { auto parse_result = Parse( "a/IFoo.aidl", StringPrintf( "package a; interface IFoo {%s String f(); }", (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); } } TEST_F(AidlTest, ParsesUtf8Annotations) { for (auto is_utf8: {true, false}) { auto parse_result = Parse( "a/IFoo.aidl", StringPrintf( "package a; interface IFoo {%s String f(); }", (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); } } TEST_F(AidlTest, AcceptsOneway) { string oneway_method = "package a; interface IFoo { oneway void f(int a); }"; string oneway_interface = "package a; oneway interface IBar { void f(int a); }"; EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &cpp_types_)); EXPECT_NE(nullptr, Parse("a/IFoo.aidl", oneway_method, &java_types_)); EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &cpp_types_)); EXPECT_NE(nullptr, Parse("a/IBar.aidl", oneway_interface, &java_types_)); } TEST_F(AidlTest, ParsesPreprocessedFile) { string simple_content = "parcelable a.Foo;\ninterface b.IBar;"; io_delegate_.SetFileContents("path", simple_content); EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo")); EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_)); EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo")); EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar")); } TEST_F(AidlTest, ParsesPreprocessedFileWithWhitespace) { string simple_content = "parcelable a.Foo;\n interface b.IBar ;\t"; io_delegate_.SetFileContents("path", simple_content); EXPECT_FALSE(java_types_.HasTypeByCanonicalName("a.Foo")); EXPECT_TRUE(parse_preprocessed_file(io_delegate_, "path", &java_types_)); EXPECT_TRUE(java_types_.HasTypeByCanonicalName("a.Foo")); EXPECT_TRUE(java_types_.HasTypeByCanonicalName("b.IBar")); } TEST_F(AidlTest, PreferImportToPreprocessed) { io_delegate_.SetFileContents("preprocessed", "interface another.IBar;"); io_delegate_.SetFileContents("one/IBar.aidl", "package one; " "interface IBar {}"); preprocessed_files_.push_back("preprocessed"); import_paths_.push_back(""); auto parse_result = Parse( "p/IFoo.aidl", "package p; import one.IBar; interface IFoo {}", &java_types_); EXPECT_NE(nullptr, parse_result); // We expect to know about both kinds of IBar EXPECT_TRUE(java_types_.HasTypeByCanonicalName("one.IBar")); EXPECT_TRUE(java_types_.HasTypeByCanonicalName("another.IBar")); // But if we request just "IBar" we should get our imported one. AidlType ambiguous_type("IBar", 0, "", false /* not an array */); const java::Type* type = java_types_.Find(ambiguous_type); ASSERT_TRUE(type); EXPECT_EQ("one.IBar", type->CanonicalName()); } TEST_F(AidlTest, WritePreprocessedFile) { io_delegate_.SetFileContents("p/Outer.aidl", "package p; parcelable Outer.Inner;"); io_delegate_.SetFileContents("one/IBar.aidl", "package one; import p.Outer;" "interface IBar {}"); JavaOptions options; options.output_file_name_ = "preprocessed"; options.files_to_preprocess_.resize(2); options.files_to_preprocess_[0] = "p/Outer.aidl"; options.files_to_preprocess_[1] = "one/IBar.aidl"; EXPECT_TRUE(::android::aidl::preprocess_aidl(options, io_delegate_)); string output; EXPECT_TRUE(io_delegate_.GetWrittenContents("preprocessed", &output)); EXPECT_EQ("parcelable p.Outer.Inner;\ninterface one.IBar;\n", output); } TEST_F(AidlTest, RequireOuterClass) { io_delegate_.SetFileContents("p/Outer.aidl", "package p; parcelable Outer.Inner;"); import_paths_.push_back(""); auto parse_result = Parse( "p/IFoo.aidl", "package p; import p.Outer; interface IFoo { void f(in Inner c); }", &java_types_); EXPECT_EQ(nullptr, parse_result); } TEST_F(AidlTest, ParseCompoundParcelableFromPreprocess) { io_delegate_.SetFileContents("preprocessed", "parcelable p.Outer.Inner;"); preprocessed_files_.push_back("preprocessed"); auto parse_result = Parse( "p/IFoo.aidl", "package p; interface IFoo { void f(in Inner c); }", &java_types_); // TODO(wiley): This should actually return nullptr because we require // the outer class name. However, for legacy reasons, // this behavior must be maintained. b/17415692 EXPECT_NE(nullptr, parse_result); } TEST_F(AidlTest, FailOnParcelable) { JavaOptions options; options.input_file_name_ = "p/IFoo.aidl"; io_delegate_.SetFileContents(options.input_file_name_, "package p; parcelable IFoo;"); // By default, we shouldn't fail on parcelable. EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_)); options.fail_on_parcelable_ = true; EXPECT_NE(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_)); } TEST_F(AidlTest, FailOnDuplicateConstantNames) { AidlError reported_error; EXPECT_EQ(nullptr, Parse("p/IFoo.aidl", R"(package p; interface IFoo { const String DUPLICATED = "d"; const int DUPLICATED = 1; } )", &cpp_types_, &reported_error)); EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error); } TEST_F(AidlTest, FailOnMalformedConstHexValue) { AidlError reported_error; EXPECT_EQ(nullptr, Parse("p/IFoo.aidl", R"(package p; interface IFoo { const int BAD_HEX_VALUE = 0xffffffffffffffffff; } )", &cpp_types_, &reported_error)); EXPECT_EQ(AidlError::BAD_CONSTANTS, reported_error); } TEST_F(AidlTest, ParsePositiveConstHexValue) { AidlError reported_error; auto cpp_parse_result = Parse("p/IFoo.aidl", R"(package p; interface IFoo { const int POSITIVE_HEX_VALUE = 0xf5; } )", &cpp_types_, &reported_error); EXPECT_NE(nullptr, cpp_parse_result); const auto& cpp_int_constants = cpp_parse_result->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()); } TEST_F(AidlTest, ParseNegativeConstHexValue) { AidlError reported_error; auto cpp_parse_result = Parse("p/IFoo.aidl", R"(package p; interface IFoo { const int NEGATIVE_HEX_VALUE = 0xffffffff; } )", &cpp_types_, &reported_error); EXPECT_NE(nullptr, cpp_parse_result); const auto& cpp_int_constants = cpp_parse_result->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()); } TEST_F(AidlTest, UnderstandsNestedParcelables) { io_delegate_.SetFileContents( "p/Outer.aidl", "package p; parcelable Outer.Inner cpp_header \"baz/header\";"); import_paths_.push_back(""); const string input_path = "p/IFoo.aidl"; const string input = "package p; import p.Outer; interface IFoo" " { Outer.Inner get(); }"; auto cpp_parse_result = Parse(input_path, input, &cpp_types_); EXPECT_NE(nullptr, cpp_parse_result); auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Outer.Inner"); ASSERT_NE(nullptr, cpp_type); // C++ uses "::" instead of "." to refer to a inner class. EXPECT_EQ("::p::Outer::Inner", cpp_type->CppType()); } TEST_F(AidlTest, UnderstandsNativeParcelables) { io_delegate_.SetFileContents( "p/Bar.aidl", "package p; parcelable Bar cpp_header \"baz/header\";"); import_paths_.push_back(""); const string input_path = "p/IFoo.aidl"; const string input = "package p; import p.Bar; interface IFoo { }"; // C++ understands C++ specific stuff auto cpp_parse_result = Parse(input_path, input, &cpp_types_); EXPECT_NE(nullptr, cpp_parse_result); auto cpp_type = cpp_types_.FindTypeByCanonicalName("p.Bar"); ASSERT_NE(nullptr, cpp_type); EXPECT_EQ("::p::Bar", cpp_type->CppType()); set headers; cpp_type->GetHeaders(&headers); EXPECT_EQ(1u, headers.size()); EXPECT_EQ(1u, headers.count("baz/header")); // Java ignores C++ specific stuff auto java_parse_result = Parse(input_path, input, &java_types_); EXPECT_NE(nullptr, java_parse_result); auto java_type = java_types_.FindTypeByCanonicalName("p.Bar"); ASSERT_NE(nullptr, java_type); EXPECT_EQ("p.Bar", java_type->InstantiableName()); } TEST_F(AidlTest, WritesCorrectDependencyFile) { // While the in tree build system always gives us an output file name, // other android tools take advantage of our ability to infer the intended // file name. This test makes sure we handle this correctly. JavaOptions options; options.input_file_name_ = "p/IFoo.aidl"; options.output_base_folder_ = "place/for/output"; options.dep_file_name_ = "dep/file/path"; io_delegate_.SetFileContents(options.input_file_name_, "package p; interface IFoo {}"); EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_, &actual_dep_file_contents)); EXPECT_EQ(actual_dep_file_contents, kExpectedDepFileContents); } TEST_F(AidlTest, WritesCorrectDependencyFileNinja) { // While the in tree build system always gives us an output file name, // other android tools take advantage of our ability to infer the intended // file name. This test makes sure we handle this correctly. JavaOptions options; options.input_file_name_ = "p/IFoo.aidl"; options.output_base_folder_ = "place/for/output"; options.dep_file_name_ = "dep/file/path"; options.dep_file_ninja_ = true; io_delegate_.SetFileContents(options.input_file_name_, "package p; interface IFoo {}"); EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_, &actual_dep_file_contents)); EXPECT_EQ(actual_dep_file_contents, kExpectedNinjaDepFileContents); } TEST_F(AidlTest, WritesTrivialDependencyFileForParcelable) { // The SDK uses aidl to decide whether a .aidl file is a parcelable. It does // this by calling aidl with every .aidl file it finds, then parsing the // generated dependency files. Those that reference .java output files are // for interfaces and those that do not are parcelables. However, for both // parcelables and interfaces, we *must* generate a non-empty dependency file. JavaOptions options; options.input_file_name_ = "p/Foo.aidl"; options.output_base_folder_ = "place/for/output"; options.dep_file_name_ = "dep/file/path"; io_delegate_.SetFileContents(options.input_file_name_, "package p; parcelable Foo;"); EXPECT_EQ(0, ::android::aidl::compile_aidl_to_java(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.dep_file_name_, &actual_dep_file_contents)); EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDepFileContents); } } // namespace aidl } // namespace android ast_cpp.cpp0100644 0000000 0000000 00000031105 13277516055 011755 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "ast_cpp.h" #include #include "code_writer.h" #include "logging.h" using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace cpp { ClassDecl::ClassDecl(const std::string& name, const std::string& parent) : name_(name), parent_(parent) {} ClassDecl::ClassDecl(const std::string& name, const std::string& parent, std::vector> public_members, std::vector> private_members) : name_(name), parent_(parent), public_members_(std::move(public_members)), private_members_(std::move(private_members)) {} void ClassDecl::Write(CodeWriter* to) const { to->Write("class %s ", name_.c_str()); if (parent_.length() > 0) to->Write(": public %s ", parent_.c_str()); to->Write("{\n"); if (!public_members_.empty()) to->Write("public:\n"); for (const auto& dec : public_members_) dec->Write(to); if (!private_members_.empty()) to->Write("private:\n"); for (const auto& dec : private_members_) dec->Write(to); to->Write("}; // class %s\n", name_.c_str()); } void ClassDecl::AddPublic(std::unique_ptr member) { public_members_.push_back(std::move(member)); } void ClassDecl::AddPrivate(std::unique_ptr member) { private_members_.push_back(std::move(member)); } Enum::EnumField::EnumField(const string& k, const string& v) : key(k), value(v) {} Enum::Enum(const string& name, const string& base_type) : enum_name_(name), underlying_type_(base_type) {} Enum::Enum(const string& name) : Enum(name, "") {} void Enum::Write(CodeWriter* to) const { if (underlying_type_.empty()) { to->Write("enum %s {\n", enum_name_.c_str()); } else { to->Write("enum %s : %s {\n", enum_name_.c_str(), underlying_type_.c_str()); } for (const auto& field : fields_) { if (field.value.empty()) { to->Write(" %s,\n", field.key.c_str()); } else { to->Write(" %s = %s,\n", field.key.c_str(), field.value.c_str()); } } to->Write("};\n"); } void Enum::AddValue(const string& key, const string& value) { fields_.emplace_back(key, value); } ArgList::ArgList(const std::string& single_argument) : ArgList(vector{single_argument}) {} ArgList::ArgList(const std::vector& arg_list) { for (const auto& s : arg_list) { arguments_.emplace_back(new LiteralExpression(s)); } } ArgList::ArgList(std::vector> arg_list) : arguments_(std::move(arg_list)) {} ArgList::ArgList(ArgList&& arg_list) : arguments_(std::move(arg_list.arguments_)) {} void ArgList::Write(CodeWriter* to) const { to->Write("("); bool is_first = true; for (const auto& s : arguments_) { if (!is_first) { to->Write(", "); } is_first = false; s->Write(to); } to->Write(")"); } ConstructorDecl::ConstructorDecl( const std::string& name, ArgList&& arg_list) : ConstructorDecl(name, std::move(arg_list), 0u) {} ConstructorDecl::ConstructorDecl( const std::string& name, ArgList&& arg_list, uint32_t modifiers) : name_(name), arguments_(std::move(arg_list)), modifiers_(modifiers) {} void ConstructorDecl::Write(CodeWriter* to) const { if (modifiers_ & Modifiers::IS_VIRTUAL) to->Write("virtual "); if (modifiers_ & Modifiers::IS_EXPLICIT) to->Write("explicit "); to->Write("%s", name_.c_str()); arguments_.Write(to); if (modifiers_ & Modifiers::IS_DEFAULT) to->Write(" = default"); to->Write(";\n"); } MacroDecl::MacroDecl(const std::string& name, ArgList&& arg_list) : name_(name), arguments_(std::move(arg_list)) {} void MacroDecl::Write(CodeWriter* to) const { to->Write("%s", name_.c_str()); arguments_.Write(to); to->Write("\n"); } MethodDecl::MethodDecl(const std::string& return_type, const std::string& name, ArgList&& arg_list) : MethodDecl(return_type, name, std::move(arg_list), 0u) {} MethodDecl::MethodDecl(const std::string& return_type, const std::string& name, ArgList&& arg_list, uint32_t modifiers) : return_type_(return_type), name_(name), arguments_(std::move(arg_list)), is_const_(modifiers & IS_CONST), is_virtual_(modifiers & IS_VIRTUAL), is_override_(modifiers & IS_OVERRIDE), is_pure_virtual_(modifiers & IS_PURE_VIRTUAL), is_static_(modifiers & IS_STATIC) {} void MethodDecl::Write(CodeWriter* to) const { if (is_virtual_) to->Write("virtual "); if (is_static_) to->Write("static "); to->Write("%s %s", return_type_.c_str(), name_.c_str()); arguments_.Write(to); if (is_const_) to->Write(" const"); if (is_override_) to->Write(" override"); if (is_pure_virtual_) to->Write(" = 0"); to->Write(";\n"); } void StatementBlock::AddStatement(unique_ptr statement) { statements_.push_back(std::move(statement)); } void StatementBlock::AddStatement(AstNode* statement) { statements_.emplace_back(statement); } void StatementBlock::AddLiteral(const std::string& expression_str, bool add_semicolon) { if (add_semicolon) { statements_.push_back(unique_ptr(new Statement(expression_str))); } else { statements_.push_back(unique_ptr( new LiteralExpression(expression_str))); } } void StatementBlock::Write(CodeWriter* to) const { to->Write("{\n"); for (const auto& statement : statements_) { statement->Write(to); } to->Write("}\n"); } ConstructorImpl::ConstructorImpl(const string& class_name, ArgList&& arg_list, const vector& initializer_list) : class_name_(class_name), arguments_(std::move(arg_list)), initializer_list_(initializer_list) {} void ConstructorImpl::Write(CodeWriter* to) const { to->Write("%s::%s", class_name_.c_str(), class_name_.c_str()); arguments_.Write(to); to->Write("\n"); bool is_first = true; for (const string& i : initializer_list_) { if (is_first) { to->Write(" : %s", i.c_str()); } else { to->Write(",\n %s", i.c_str()); } is_first = false; } body_.Write(to); } MethodImpl::MethodImpl(const string& return_type, const string& class_name, const string& method_name, ArgList&& arg_list, bool is_const_method) : return_type_(return_type), method_name_(method_name), arguments_(std::move(arg_list)), is_const_method_(is_const_method) { if (!class_name.empty()) { method_name_ = class_name + "::" + method_name; } } StatementBlock* MethodImpl::GetStatementBlock() { return &statements_; } void MethodImpl::Write(CodeWriter* to) const { to->Write("%s %s", return_type_.c_str(), method_name_.c_str()); arguments_.Write(to); to->Write("%s ", (is_const_method_) ? " const" : ""); statements_.Write(to); } SwitchStatement::SwitchStatement(const std::string& expression) : switch_expression_(expression) {} StatementBlock* SwitchStatement::AddCase(const string& value_expression) { auto it = std::find(case_values_.begin(), case_values_.end(), value_expression); if (it != case_values_.end()) { LOG(ERROR) << "internal error: duplicate switch case labels"; return nullptr; } StatementBlock* ret = new StatementBlock(); case_values_.push_back(value_expression); case_logic_.push_back(unique_ptr{ret}); return ret; } void SwitchStatement::Write(CodeWriter* to) const { to->Write("switch (%s) {\n", switch_expression_.c_str()); for (size_t i = 0; i < case_values_.size(); ++i) { const string& case_value = case_values_[i]; const unique_ptr& statements = case_logic_[i]; if (case_value.empty()) { to->Write("default:\n"); } else { to->Write("case %s:\n", case_value.c_str()); } statements->Write(to); to->Write("break;\n"); } to->Write("}\n"); } Assignment::Assignment(const std::string& left, const std::string& right) : Assignment(left, new LiteralExpression{right}) {} Assignment::Assignment(const std::string& left, AstNode* right) : lhs_(left), rhs_(right) {} void Assignment::Write(CodeWriter* to) const { to->Write("%s = ", lhs_.c_str()); rhs_->Write(to); to->Write(";\n"); } MethodCall::MethodCall(const std::string& method_name, const std::string& single_argument) : MethodCall(method_name, ArgList{single_argument}) {} MethodCall::MethodCall(const std::string& method_name, ArgList&& arg_list) : method_name_(method_name), arguments_{std::move(arg_list)} {} void MethodCall::Write(CodeWriter* to) const { to->Write("%s", method_name_.c_str()); arguments_.Write(to); } IfStatement::IfStatement(AstNode* expression, bool invert_expression) : expression_(expression), invert_expression_(invert_expression) {} void IfStatement::Write(CodeWriter* to) const { to->Write("if (%s", (invert_expression_) ? "!(" : ""); expression_->Write(to); to->Write(")%s ", (invert_expression_) ? ")" : ""); on_true_.Write(to); if (!on_false_.Empty()) { to->Write("else "); on_false_.Write(to); } } Statement::Statement(unique_ptr expression) : expression_(std::move(expression)) {} Statement::Statement(AstNode* expression) : expression_(expression) {} Statement::Statement(const string& expression) : expression_(new LiteralExpression(expression)) {} void Statement::Write(CodeWriter* to) const { expression_->Write(to); to->Write(";\n"); } Comparison::Comparison(AstNode* lhs, const string& comparison, AstNode* rhs) : left_(lhs), right_(rhs), operator_(comparison) {} void Comparison::Write(CodeWriter* to) const { to->Write("(("); left_->Write(to); to->Write(") %s (", operator_.c_str()); right_->Write(to); to->Write("))"); } LiteralExpression::LiteralExpression(const std::string& expression) : expression_(expression) {} void LiteralExpression::Write(CodeWriter* to) const { to->Write("%s", expression_.c_str()); } CppNamespace::CppNamespace(const std::string& name, std::vector> declarations) : declarations_(std::move(declarations)), name_(name) {} CppNamespace::CppNamespace(const std::string& name, unique_ptr declaration) : name_(name) { declarations_.push_back(std::move(declaration)); } CppNamespace::CppNamespace(const std::string& name) : name_(name) {} void CppNamespace::Write(CodeWriter* to) const { to->Write("namespace %s {\n\n", name_.c_str()); for (const auto& dec : declarations_) { dec->Write(to); to->Write("\n"); } to->Write("} // namespace %s\n", name_.c_str()); } Document::Document(const std::vector& include_list, unique_ptr a_namespace) : include_list_(include_list), namespace_(std::move(a_namespace)) {} void Document::Write(CodeWriter* to) const { for (const auto& include : include_list_) { to->Write("#include <%s>\n", include.c_str()); } to->Write("\n"); namespace_->Write(to); } CppHeader::CppHeader(const std::string& include_guard, const std::vector& include_list, unique_ptr a_namespace) : Document(include_list, std::move(a_namespace)), include_guard_(include_guard) {} void CppHeader::Write(CodeWriter* to) const { to->Write("#ifndef %s\n", include_guard_.c_str()); to->Write("#define %s\n\n", include_guard_.c_str()); Document::Write(to); to->Write("\n"); to->Write("#endif // %s\n", include_guard_.c_str()); } CppSource::CppSource(const std::vector& include_list, unique_ptr a_namespace) : Document(include_list, std::move(a_namespace)) {} } // namespace cpp } // namespace aidl } // namespace android ast_cpp.h0100644 0000000 0000000 00000026520 13277516055 011427 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_AST_CPP_H_ #define AIDL_AST_CPP_H_ #include #include #include #include namespace android { namespace aidl { class CodeWriter; } // namespace aidl } // namespace android namespace android { namespace aidl { namespace cpp { class AstNode { public: AstNode() = default; virtual ~AstNode() = default; virtual void Write(CodeWriter* to) const = 0; }; // class AstNode class Declaration : public AstNode { public: Declaration() = default; virtual ~Declaration() = default; private: DISALLOW_COPY_AND_ASSIGN(Declaration); }; // class Declaration class ClassDecl : public Declaration { public: ClassDecl(const std::string& name, const std::string& parent); ClassDecl(const std::string& name, const std::string& parent, std::vector> public_members, std::vector> private_members); virtual ~ClassDecl() = default; void Write(CodeWriter* to) const override; void AddPublic(std::unique_ptr member); void AddPrivate(std::unique_ptr member); private: std::string name_; std::string parent_; std::vector> public_members_; std::vector> private_members_; DISALLOW_COPY_AND_ASSIGN(ClassDecl); }; // class ClassDecl class Enum : public Declaration { public: Enum(const std::string& name, const std::string& base_type); explicit Enum(const std::string& name); virtual ~Enum() = default; bool HasValues() const { return !fields_.empty(); } void Write(CodeWriter* to) const override; void AddValue(const std::string& key, const std::string& value); private: struct EnumField { EnumField(const std::string& k, const std::string& v); const std::string key; const std::string value; }; std::string enum_name_; std::string underlying_type_; std::vector fields_; DISALLOW_COPY_AND_ASSIGN(Enum); }; // class Enum class ArgList : public AstNode { public: ArgList() = default; explicit ArgList(const std::string& single_argument); explicit ArgList(const std::vector& arg_list); explicit ArgList(std::vector> arg_list); ArgList(ArgList&& arg_list); virtual ~ArgList() = default; void Write(CodeWriter* to) const override; private: std::vector> arguments_; DISALLOW_COPY_AND_ASSIGN(ArgList); }; // class ArgList class ConstructorDecl : public Declaration { public: enum Modifiers { IS_VIRTUAL = 1 << 0, IS_DEFAULT = 1 << 1, IS_EXPLICIT = 1 << 2, }; ConstructorDecl(const std::string& name, ArgList&& arg_list); ConstructorDecl(const std::string& name, ArgList&& arg_list, uint32_t modifiers); virtual ~ConstructorDecl() = default; void Write(CodeWriter* to) const override; private: const std::string name_; const ArgList arguments_; const uint32_t modifiers_; DISALLOW_COPY_AND_ASSIGN(ConstructorDecl); }; // class ConstructorDecl class MacroDecl : public Declaration { public: MacroDecl(const std::string& name, ArgList&& arg_list); virtual ~MacroDecl() = default; void Write(CodeWriter* to) const override; private: const std::string name_; const ArgList arguments_; DISALLOW_COPY_AND_ASSIGN(MacroDecl); }; // class MacroDecl class MethodDecl : public Declaration { public: enum Modifiers { IS_CONST = 1 << 0, IS_VIRTUAL = 1 << 1, IS_OVERRIDE = 1 << 2, IS_PURE_VIRTUAL = 1 << 3, IS_STATIC = 1 << 4, }; MethodDecl(const std::string& return_type, const std::string& name, ArgList&& arg_list); MethodDecl(const std::string& return_type, const std::string& name, ArgList&& arg_list, uint32_t modifiers); virtual ~MethodDecl() = default; void Write(CodeWriter* to) const override; private: const std::string return_type_; const std::string name_; const ArgList arguments_; bool is_const_ = false; bool is_virtual_ = false; bool is_override_ = false; bool is_pure_virtual_ = false; bool is_static_ = true; DISALLOW_COPY_AND_ASSIGN(MethodDecl); }; // class MethodDecl class StatementBlock : public Declaration { public: StatementBlock() = default; virtual ~StatementBlock() = default; void AddStatement(std::unique_ptr statement); void AddStatement(AstNode* statement); // Takes ownership void AddLiteral(const std::string& expression, bool add_semicolon = true); bool Empty() const { return statements_.empty(); } void Write(CodeWriter* to) const override; private: std::vector> statements_; DISALLOW_COPY_AND_ASSIGN(StatementBlock); }; // class StatementBlock class ConstructorImpl : public Declaration { public: ConstructorImpl(const std::string& class_name, ArgList&& arg_list, const std::vector& initializer_list); virtual ~ConstructorImpl() = default; void Write(CodeWriter* to) const override; private: std::string class_name_; ArgList arguments_; std::vector initializer_list_; StatementBlock body_; DISALLOW_COPY_AND_ASSIGN(ConstructorImpl); }; // class ConstructorImpl class MethodImpl : public Declaration { public: // Passing an empty class name causes the method to be declared as a normal // function (ie. no ClassName:: qualifier). MethodImpl(const std::string& return_type, const std::string& class_name, const std::string& method_name, ArgList&& arg_list, bool is_const_method = false); virtual ~MethodImpl() = default; // MethodImpl retains ownership of the statement block. StatementBlock* GetStatementBlock(); void Write(CodeWriter* to) const override; private: std::string return_type_; std::string method_name_; const ArgList arguments_; StatementBlock statements_; bool is_const_method_ = false; DISALLOW_COPY_AND_ASSIGN(MethodImpl); }; // class MethodImpl class SwitchStatement : public AstNode { public: explicit SwitchStatement(const std::string& expression); virtual ~SwitchStatement() = default; // Add a case statement and return a pointer code block corresponding // to the case. The switch statement will add a break statement // after the code block by default to prevent accidental fall-through. // Returns nullptr on duplicate value expressions (by strcmp, not value // equivalence). StatementBlock* AddCase(const std::string& value_expression); void Write(CodeWriter* to) const override; private: const std::string switch_expression_; std::vector case_values_; std::vector> case_logic_; DISALLOW_COPY_AND_ASSIGN(SwitchStatement); }; // class SwitchStatement class Assignment : public AstNode { public: Assignment(const std::string& left, const std::string& right); Assignment(const std::string& left, AstNode* right); ~Assignment() = default; void Write(CodeWriter* to) const override; private: const std::string lhs_; std::unique_ptr rhs_; DISALLOW_COPY_AND_ASSIGN(Assignment); }; // class Assignment class MethodCall : public AstNode { public: MethodCall(const std::string& method_name, const std::string& single_argument); MethodCall(const std::string& method_name, ArgList&& arg_list); ~MethodCall() = default; void Write(CodeWriter* to) const override; private: const std::string method_name_; const ArgList arguments_; DISALLOW_COPY_AND_ASSIGN(MethodCall); }; // class MethodCall class IfStatement : public AstNode { public: explicit IfStatement(AstNode* expression, bool invert_expression = false); virtual ~IfStatement() = default; StatementBlock* OnTrue() { return &on_true_; } StatementBlock* OnFalse() { return &on_false_; } void Write(CodeWriter* to) const override; private: std::unique_ptr expression_; bool invert_expression_ = false; StatementBlock on_true_; StatementBlock on_false_; DISALLOW_COPY_AND_ASSIGN(IfStatement); }; // class IfStatement class Statement : public AstNode { public: explicit Statement(std::unique_ptr expression); explicit Statement(AstNode* expression); // Takes possession. explicit Statement(const std::string& expression); ~Statement() = default; void Write(CodeWriter* to) const override; private: std::unique_ptr expression_; DISALLOW_COPY_AND_ASSIGN(Statement); }; // class Statement class Comparison : public AstNode { public: Comparison(AstNode* lhs, const std::string& comparison, AstNode* rhs); ~Comparison() = default; void Write(CodeWriter* to) const override; private: std::unique_ptr left_; std::unique_ptr right_; const std::string operator_; DISALLOW_COPY_AND_ASSIGN(Comparison); }; // class Comparison class LiteralExpression : public AstNode { public: explicit LiteralExpression(const std::string& expression); ~LiteralExpression() = default; void Write(CodeWriter* to) const override; private: const std::string expression_; DISALLOW_COPY_AND_ASSIGN(LiteralExpression); }; // class LiteralExpression class CppNamespace : public Declaration { public: CppNamespace(const std::string& name, std::vector> declarations); CppNamespace(const std::string& name, std::unique_ptr declaration); explicit CppNamespace(const std::string& name); virtual ~CppNamespace() = default; void Write(CodeWriter* to) const override; private: std::vector> declarations_; std::string name_; DISALLOW_COPY_AND_ASSIGN(CppNamespace); }; // class CppNamespace class Document : public AstNode { public: Document(const std::vector& include_list, std::unique_ptr a_namespace); void Write(CodeWriter* to) const override; private: std::vector include_list_; std::unique_ptr namespace_; DISALLOW_COPY_AND_ASSIGN(Document); }; // class Document class CppHeader final : public Document { public: CppHeader(const std::string& include_guard, const std::vector& include_list, std::unique_ptr a_namespace); void Write(CodeWriter* to) const override; private: const std::string include_guard_; DISALLOW_COPY_AND_ASSIGN(CppHeader); }; // class CppHeader class CppSource final : public Document { public: CppSource(const std::vector& include_list, std::unique_ptr a_namespace); private: DISALLOW_COPY_AND_ASSIGN(CppSource); }; // class CppSource } // namespace cpp } // namespace aidl } // namespace android #endif // AIDL_AST_CPP_H_ ast_cpp_unittest.cpp0100644 0000000 0000000 00000015252 13277516055 013721 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include "ast_cpp.h" #include "code_writer.h" using std::string; using std::vector; using std::unique_ptr; namespace android { namespace aidl { namespace cpp { namespace { const char kExpectedHeaderOutput[] = R"(#ifndef HEADER_INCLUDE_GUARD_H_ #define HEADER_INCLUDE_GUARD_H_ #include #include namespace android { namespace test { class TestClass { public: void NormalMethod(int normalarg, float normal2); virtual void SubMethod(int subarg) const; }; // class TestClass class TestSubClass : public TestClass { public: virtual void SubMethod(int subarg) const; }; // class TestSubClass } // namespace test } // namespace android #endif // HEADER_INCLUDE_GUARD_H_ )"; const char kExpectedEnumOutput[] = R"(enum Foo { BAR = 42, BAZ, }; )"; const char kExpectedSwitchOutput[] = R"(switch (var) { case 2: { baz; } break; case 1: { foo; bar; } break; } )"; const char kExpectedMethodImplOutput[] = R"(return_type ClassName::MethodName(arg 1, arg 2, arg 3) const { foo; bar; } )"; } // namespace class AstCppTests : public ::testing::Test { protected: void CompareGeneratedCode(const AstNode& node, const string& expected_output) { string actual_output; CodeWriterPtr writer = GetStringWriter(&actual_output); node.Write(writer.get()); EXPECT_EQ(expected_output, actual_output); } }; // class AstCppTests TEST_F(AstCppTests, GeneratesHeader) { unique_ptr norm{new MethodDecl( "void", "NormalMethod", ArgList{vector{"int normalarg", "float normal2"}})}; unique_ptr sub{ new MethodDecl("void", "SubMethod", ArgList{ "int subarg" }, MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)}; unique_ptr sub2{ new MethodDecl("void", "SubMethod", ArgList{ "int subarg" }, MethodDecl::IS_CONST | MethodDecl::IS_VIRTUAL)}; vector> test_methods; test_methods.push_back(std::move(norm)); test_methods.push_back(std::move(sub)); vector> test_sub_methods; test_sub_methods.push_back(std::move(sub2)); unique_ptr test{new ClassDecl { "TestClass", "", std::move(test_methods), {} }}; unique_ptr test_sub{new ClassDecl { "TestSubClass", "TestClass", std::move(test_sub_methods), {} }}; vector> classes; classes.push_back(std::move(test)); classes.push_back(std::move(test_sub)); unique_ptr test_ns{new CppNamespace {"test", std::move(classes)}}; vector> test_ns_vec; test_ns_vec.push_back(std::move(test_ns)); unique_ptr android_ns{new CppNamespace {"android", std::move(test_ns_vec) }}; CppHeader cpp_header{"HEADER_INCLUDE_GUARD_H_", {"string", "memory"}, std::move(android_ns) }; CompareGeneratedCode(cpp_header, kExpectedHeaderOutput); } TEST_F(AstCppTests, GeneratesEnum) { Enum e("Foo"); e.AddValue("BAR", "42"); e.AddValue("BAZ", ""); CompareGeneratedCode(e, kExpectedEnumOutput); } TEST_F(AstCppTests, GeneratesArgList) { ArgList simple("foo"); CompareGeneratedCode(simple, "(foo)"); ArgList compound({"foo", "bar", "baz"}); CompareGeneratedCode(compound, "(foo, bar, baz)"); std::vector> args; args.emplace_back(new LiteralExpression("foo()")); ArgList nested(std::move(args)); CompareGeneratedCode(nested, "(foo())"); } TEST_F(AstCppTests, GeneratesStatement) { Statement s(new LiteralExpression("foo")); CompareGeneratedCode(s, "foo;\n"); } TEST_F(AstCppTests, GeneratesComparison) { Comparison c( new LiteralExpression("lhs"), "&&", new LiteralExpression("rhs")); CompareGeneratedCode(c, "((lhs) && (rhs))"); } TEST_F(AstCppTests, GeneratesStatementBlock) { StatementBlock block; block.AddStatement(unique_ptr(new Statement("foo"))); block.AddStatement(unique_ptr(new Statement("bar"))); CompareGeneratedCode(block, "{\nfoo;\nbar;\n}\n"); } TEST_F(AstCppTests, GeneratesConstructorImpl) { ConstructorImpl c("ClassName", ArgList({"a", "b", "c"}), {"baz_(foo)", "bar_(blah)"}); string expected = R"(ClassName::ClassName(a, b, c) : baz_(foo), bar_(blah){ } )"; CompareGeneratedCode(c, expected); } TEST_F(AstCppTests, GeneratesAssignment) { Assignment simple("foo", "8"); CompareGeneratedCode(simple, "foo = 8;\n"); Assignment less_simple("foo", new MethodCall("f", "8")); CompareGeneratedCode(less_simple, "foo = f(8);\n"); } TEST_F(AstCppTests, GeneratesMethodCall) { MethodCall single("single", "arg"); CompareGeneratedCode(single, "single(arg)"); MethodCall multi( "multi", ArgList({"has", "some", "args"})); CompareGeneratedCode(multi, "multi(has, some, args)"); } TEST_F(AstCppTests, GeneratesIfStatement) { IfStatement s(new LiteralExpression("foo")); s.OnTrue()->AddLiteral("on true1"); s.OnFalse()->AddLiteral("on false"); CompareGeneratedCode(s, "if (foo) {\non true1;\n}\nelse {\non false;\n}\n"); IfStatement s2(new LiteralExpression("bar")); s2.OnTrue()->AddLiteral("on true1"); CompareGeneratedCode(s2, "if (bar) {\non true1;\n}\n"); } TEST_F(AstCppTests, GeneratesSwitchStatement) { SwitchStatement s("var"); // These are intentionally out of alphanumeric order. We're testing // that switch respects case addition order. auto case2 = s.AddCase("2"); case2->AddStatement(unique_ptr{new Statement{"baz"}}); auto case1 = s.AddCase("1"); case1->AddStatement(unique_ptr{new Statement{"foo"}}); case1->AddStatement(unique_ptr{new Statement{"bar"}}); CompareGeneratedCode(s, kExpectedSwitchOutput); } TEST_F(AstCppTests, GeneratesMethodImpl) { MethodImpl m{"return_type", "ClassName", "MethodName", ArgList{{"arg 1", "arg 2", "arg 3"}}, true}; auto b = m.GetStatementBlock(); b->AddLiteral("foo"); b->AddLiteral("bar"); CompareGeneratedCode(m, kExpectedMethodImplOutput); } } // namespace cpp } // namespace aidl } // namespace android ast_java.cpp0100644 0000000 0000000 00000031353 13277516055 012121 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "ast_java.h" #include "code_writer.h" #include "type_java.h" using std::vector; using std::string; namespace android { namespace aidl { namespace java { void WriteModifiers(CodeWriter* to, int mod, int mask) { int m = mod & mask; if (m & OVERRIDE) { to->Write("@Override "); } if ((m & SCOPE_MASK) == PUBLIC) { to->Write("public "); } else if ((m & SCOPE_MASK) == PRIVATE) { to->Write("private "); } else if ((m & SCOPE_MASK) == PROTECTED) { to->Write("protected "); } if (m & STATIC) { to->Write("static "); } if (m & FINAL) { to->Write("final "); } if (m & ABSTRACT) { to->Write("abstract "); } } void WriteArgumentList(CodeWriter* to, const vector& arguments) { size_t N = arguments.size(); for (size_t i = 0; i < N; i++) { arguments[i]->Write(to); if (i != N - 1) { to->Write(", "); } } } Field::Field(int m, Variable* v) : ClassElement(), modifiers(m), variable(v) {} void Field::Write(CodeWriter* to) const { if (this->comment.length() != 0) { to->Write("%s\n", this->comment.c_str()); } WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE); to->Write("%s %s", this->variable->type->JavaType().c_str(), this->variable->name.c_str()); if (this->value.length() != 0) { to->Write(" = %s", this->value.c_str()); } to->Write(";\n"); } LiteralExpression::LiteralExpression(const string& v) : value(v) {} void LiteralExpression::Write(CodeWriter* to) const { to->Write("%s", this->value.c_str()); } StringLiteralExpression::StringLiteralExpression(const string& v) : value(v) {} void StringLiteralExpression::Write(CodeWriter* to) const { to->Write("\"%s\"", this->value.c_str()); } Variable::Variable(const Type* t, const string& n) : type(t), name(n), dimension(0) {} Variable::Variable(const Type* t, const string& n, int d) : type(t), name(n), dimension(d) {} void Variable::WriteDeclaration(CodeWriter* to) const { string dim; for (int i = 0; i < this->dimension; i++) { dim += "[]"; } to->Write("%s%s %s", this->type->JavaType().c_str(), dim.c_str(), this->name.c_str()); } void Variable::Write(CodeWriter* to) const { to->Write("%s", name.c_str()); } FieldVariable::FieldVariable(Expression* o, const string& n) : object(o), clazz(NULL), name(n) {} FieldVariable::FieldVariable(const Type* c, const string& n) : object(NULL), clazz(c), name(n) {} void FieldVariable::Write(CodeWriter* to) const { if (this->object != NULL) { this->object->Write(to); } else if (this->clazz != NULL) { to->Write("%s", this->clazz->JavaType().c_str()); } to->Write(".%s", name.c_str()); } void StatementBlock::Write(CodeWriter* to) const { to->Write("{\n"); int N = this->statements.size(); for (int i = 0; i < N; i++) { this->statements[i]->Write(to); } to->Write("}\n"); } void StatementBlock::Add(Statement* statement) { this->statements.push_back(statement); } void StatementBlock::Add(Expression* expression) { this->statements.push_back(new ExpressionStatement(expression)); } ExpressionStatement::ExpressionStatement(Expression* e) : expression(e) {} void ExpressionStatement::Write(CodeWriter* to) const { this->expression->Write(to); to->Write(";\n"); } Assignment::Assignment(Variable* l, Expression* r) : lvalue(l), rvalue(r), cast(NULL) {} Assignment::Assignment(Variable* l, Expression* r, const Type* c) : lvalue(l), rvalue(r), cast(c) {} void Assignment::Write(CodeWriter* to) const { this->lvalue->Write(to); to->Write(" = "); if (this->cast != NULL) { to->Write("(%s)", this->cast->JavaType().c_str()); } this->rvalue->Write(to); } MethodCall::MethodCall(const string& n) : name(n) {} MethodCall::MethodCall(const string& n, int argc = 0, ...) : name(n) { va_list args; va_start(args, argc); init(argc, args); va_end(args); } MethodCall::MethodCall(Expression* o, const string& n) : obj(o), name(n) {} MethodCall::MethodCall(const Type* t, const string& n) : clazz(t), name(n) {} MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...) : obj(o), name(n) { va_list args; va_start(args, argc); init(argc, args); va_end(args); } MethodCall::MethodCall(const Type* t, const string& n, int argc = 0, ...) : clazz(t), name(n) { va_list args; va_start(args, argc); init(argc, args); va_end(args); } void MethodCall::init(int n, va_list args) { for (int i = 0; i < n; i++) { Expression* expression = (Expression*)va_arg(args, void*); this->arguments.push_back(expression); } } void MethodCall::Write(CodeWriter* to) const { if (this->obj != NULL) { this->obj->Write(to); to->Write("."); } else if (this->clazz != NULL) { to->Write("%s.", this->clazz->JavaType().c_str()); } to->Write("%s(", this->name.c_str()); WriteArgumentList(to, this->arguments); to->Write(")"); } Comparison::Comparison(Expression* l, const string& o, Expression* r) : lvalue(l), op(o), rvalue(r) {} void Comparison::Write(CodeWriter* to) const { to->Write("("); this->lvalue->Write(to); to->Write("%s", this->op.c_str()); this->rvalue->Write(to); to->Write(")"); } NewExpression::NewExpression(const Type* t) : type(t) {} NewExpression::NewExpression(const Type* t, int argc = 0, ...) : type(t) { va_list args; va_start(args, argc); init(argc, args); va_end(args); } void NewExpression::init(int n, va_list args) { for (int i = 0; i < n; i++) { Expression* expression = (Expression*)va_arg(args, void*); this->arguments.push_back(expression); } } void NewExpression::Write(CodeWriter* to) const { to->Write("new %s(", this->type->InstantiableName().c_str()); WriteArgumentList(to, this->arguments); to->Write(")"); } NewArrayExpression::NewArrayExpression(const Type* t, Expression* s) : type(t), size(s) {} void NewArrayExpression::Write(CodeWriter* to) const { to->Write("new %s[", this->type->JavaType().c_str()); size->Write(to); to->Write("]"); } Ternary::Ternary(Expression* a, Expression* b, Expression* c) : condition(a), ifpart(b), elsepart(c) {} void Ternary::Write(CodeWriter* to) const { to->Write("(("); this->condition->Write(to); to->Write(")?("); this->ifpart->Write(to); to->Write("):("); this->elsepart->Write(to); to->Write("))"); } Cast::Cast(const Type* t, Expression* e) : type(t), expression(e) {} void Cast::Write(CodeWriter* to) const { to->Write("((%s)", this->type->JavaType().c_str()); expression->Write(to); to->Write(")"); } VariableDeclaration::VariableDeclaration(Variable* l, Expression* r, const Type* c) : lvalue(l), cast(c), rvalue(r) {} VariableDeclaration::VariableDeclaration(Variable* l) : lvalue(l) {} void VariableDeclaration::Write(CodeWriter* to) const { this->lvalue->WriteDeclaration(to); if (this->rvalue != NULL) { to->Write(" = "); if (this->cast != NULL) { to->Write("(%s)", this->cast->JavaType().c_str()); } this->rvalue->Write(to); } to->Write(";\n"); } void IfStatement::Write(CodeWriter* to) const { if (this->expression != NULL) { to->Write("if ("); this->expression->Write(to); to->Write(") "); } this->statements->Write(to); if (this->elseif != NULL) { to->Write("else "); this->elseif->Write(to); } } ReturnStatement::ReturnStatement(Expression* e) : expression(e) {} void ReturnStatement::Write(CodeWriter* to) const { to->Write("return "); this->expression->Write(to); to->Write(";\n"); } void TryStatement::Write(CodeWriter* to) const { to->Write("try "); this->statements->Write(to); } CatchStatement::CatchStatement(Variable* e) : statements(new StatementBlock), exception(e) {} void CatchStatement::Write(CodeWriter* to) const { to->Write("catch "); if (this->exception != NULL) { to->Write("("); this->exception->WriteDeclaration(to); to->Write(") "); } this->statements->Write(to); } void FinallyStatement::Write(CodeWriter* to) const { to->Write("finally "); this->statements->Write(to); } Case::Case(const string& c) { cases.push_back(c); } void Case::Write(CodeWriter* to) const { int N = this->cases.size(); if (N > 0) { for (int i = 0; i < N; i++) { string s = this->cases[i]; if (s.length() != 0) { to->Write("case %s:\n", s.c_str()); } else { to->Write("default:\n"); } } } else { to->Write("default:\n"); } statements->Write(to); } SwitchStatement::SwitchStatement(Expression* e) : expression(e) {} void SwitchStatement::Write(CodeWriter* to) const { to->Write("switch ("); this->expression->Write(to); to->Write(")\n{\n"); int N = this->cases.size(); for (int i = 0; i < N; i++) { this->cases[i]->Write(to); } to->Write("}\n"); } void Break::Write(CodeWriter* to) const { to->Write("break;\n"); } void Method::Write(CodeWriter* to) const { size_t N, i; if (this->comment.length() != 0) { to->Write("%s\n", this->comment.c_str()); } WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE); if (this->returnType != NULL) { string dim; for (i = 0; i < this->returnTypeDimension; i++) { dim += "[]"; } to->Write("%s%s ", this->returnType->JavaType().c_str(), dim.c_str()); } to->Write("%s(", this->name.c_str()); N = this->parameters.size(); for (i = 0; i < N; i++) { this->parameters[i]->WriteDeclaration(to); if (i != N - 1) { to->Write(", "); } } to->Write(")"); N = this->exceptions.size(); for (i = 0; i < N; i++) { if (i == 0) { to->Write(" throws "); } else { to->Write(", "); } to->Write("%s", this->exceptions[i]->JavaType().c_str()); } if (this->statements == NULL) { to->Write(";\n"); } else { to->Write("\n"); this->statements->Write(to); } } void IntConstant::Write(CodeWriter* to) const { WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS); to->Write("int %s = %d;\n", name.c_str(), value); } void StringConstant::Write(CodeWriter* to) const { WriteModifiers(to, STATIC | FINAL | PUBLIC, ALL_MODIFIERS); to->Write("String %s = %s;\n", name.c_str(), value.c_str()); } void Class::Write(CodeWriter* to) const { size_t N, i; if (this->comment.length() != 0) { to->Write("%s\n", this->comment.c_str()); } WriteModifiers(to, this->modifiers, ALL_MODIFIERS); if (this->what == Class::CLASS) { to->Write("class "); } else { to->Write("interface "); } string name = this->type->JavaType(); size_t pos = name.rfind('.'); if (pos != string::npos) { name = name.c_str() + pos + 1; } to->Write("%s", name.c_str()); if (this->extends != NULL) { to->Write(" extends %s", this->extends->JavaType().c_str()); } N = this->interfaces.size(); if (N != 0) { if (this->what == Class::CLASS) { to->Write(" implements"); } else { to->Write(" extends"); } for (i = 0; i < N; i++) { to->Write(" %s", this->interfaces[i]->JavaType().c_str()); } } to->Write("\n"); to->Write("{\n"); N = this->elements.size(); for (i = 0; i < N; i++) { this->elements[i]->Write(to); } to->Write("}\n"); } static string escape_backslashes(const string& str) { string result; const size_t I = str.length(); for (size_t i = 0; i < I; i++) { char c = str[i]; if (c == '\\') { result += "\\\\"; } else { result += c; } } return result; } Document::Document(const std::string& comment, const std::string& package, const std::string& original_src, std::unique_ptr clazz) : comment_(comment), package_(package), original_src_(original_src), clazz_(std::move(clazz)) { } void Document::Write(CodeWriter* to) const { if (!comment_.empty()) { to->Write("%s\n", comment_.c_str()); } to->Write( "/*\n" " * This file is auto-generated. DO NOT MODIFY.\n" " * Original file: %s\n" " */\n", escape_backslashes(original_src_).c_str()); if (!package_.empty()) { to->Write("package %s;\n", package_.c_str()); } if (clazz_) { clazz_->Write(to); } } } // namespace java } // namespace aidl } // namespace android ast_java.h0100644 0000000 0000000 00000023445 13277516055 011571 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_AST_JAVA_H_ #define AIDL_AST_JAVA_H_ #include #include #include #include #include enum { PACKAGE_PRIVATE = 0x00000000, PUBLIC = 0x00000001, PRIVATE = 0x00000002, PROTECTED = 0x00000003, SCOPE_MASK = 0x00000003, STATIC = 0x00000010, FINAL = 0x00000020, ABSTRACT = 0x00000040, OVERRIDE = 0x00000100, ALL_MODIFIERS = 0xffffffff }; namespace android { namespace aidl { class CodeWriter; } // namespace aidl } // namespace android namespace android { namespace aidl { namespace java { class Type; // Write the modifiers that are set in both mod and mask void WriteModifiers(CodeWriter* to, int mod, int mask); struct ClassElement { ClassElement() = default; virtual ~ClassElement() = default; virtual void Write(CodeWriter* to) const = 0; }; struct Expression { virtual ~Expression() = default; virtual void Write(CodeWriter* to) const = 0; }; struct LiteralExpression : public Expression { std::string value; explicit LiteralExpression(const std::string& value); virtual ~LiteralExpression() = default; void Write(CodeWriter* to) const override; }; // TODO: also escape the contents. not needed for now struct StringLiteralExpression : public Expression { std::string value; explicit StringLiteralExpression(const std::string& value); virtual ~StringLiteralExpression() = default; void Write(CodeWriter* to) const override; }; struct Variable : public Expression { const Type* type = nullptr; std::string name; int dimension = 0; Variable() = default; Variable(const Type* type, const std::string& name); Variable(const Type* type, const std::string& name, int dimension); virtual ~Variable() = default; void WriteDeclaration(CodeWriter* to) const; void Write(CodeWriter* to) const; }; struct FieldVariable : public Expression { Expression* object; const Type* clazz; std::string name; FieldVariable(Expression* object, const std::string& name); FieldVariable(const Type* clazz, const std::string& name); virtual ~FieldVariable() = default; void Write(CodeWriter* to) const; }; struct Field : public ClassElement { std::string comment; int modifiers = 0; Variable* variable = nullptr; std::string value; Field() = default; Field(int modifiers, Variable* variable); virtual ~Field() = default; void Write(CodeWriter* to) const override; }; struct Statement { virtual ~Statement() = default; virtual void Write(CodeWriter* to) const = 0; }; struct StatementBlock : public Statement { std::vector statements; StatementBlock() = default; virtual ~StatementBlock() = default; void Write(CodeWriter* to) const override; void Add(Statement* statement); void Add(Expression* expression); }; struct ExpressionStatement : public Statement { Expression* expression; explicit ExpressionStatement(Expression* expression); virtual ~ExpressionStatement() = default; void Write(CodeWriter* to) const override; }; struct Assignment : public Expression { Variable* lvalue; Expression* rvalue; const Type* cast; Assignment(Variable* lvalue, Expression* rvalue); Assignment(Variable* lvalue, Expression* rvalue, const Type* cast); virtual ~Assignment() = default; void Write(CodeWriter* to) const override; }; struct MethodCall : public Expression { Expression* obj = nullptr; const Type* clazz = nullptr; std::string name; std::vector arguments; std::vector exceptions; explicit MethodCall(const std::string& name); MethodCall(const std::string& name, int argc, ...); MethodCall(Expression* obj, const std::string& name); MethodCall(const Type* clazz, const std::string& name); MethodCall(Expression* obj, const std::string& name, int argc, ...); MethodCall(const Type* clazz, const std::string& name, int argc, ...); virtual ~MethodCall() = default; void Write(CodeWriter* to) const override; private: void init(int n, va_list args); }; struct Comparison : public Expression { Expression* lvalue; std::string op; Expression* rvalue; Comparison(Expression* lvalue, const std::string& op, Expression* rvalue); virtual ~Comparison() = default; void Write(CodeWriter* to) const override; }; struct NewExpression : public Expression { const Type* type; std::vector arguments; explicit NewExpression(const Type* type); NewExpression(const Type* type, int argc, ...); virtual ~NewExpression() = default; void Write(CodeWriter* to) const override; private: void init(int n, va_list args); }; struct NewArrayExpression : public Expression { const Type* type; Expression* size; NewArrayExpression(const Type* type, Expression* size); virtual ~NewArrayExpression() = default; void Write(CodeWriter* to) const override; }; struct Ternary : public Expression { Expression* condition = nullptr; Expression* ifpart = nullptr; Expression* elsepart = nullptr; Ternary() = default; Ternary(Expression* condition, Expression* ifpart, Expression* elsepart); virtual ~Ternary() = default; void Write(CodeWriter* to) const override; }; struct Cast : public Expression { const Type* type = nullptr; Expression* expression = nullptr; Cast() = default; Cast(const Type* type, Expression* expression); virtual ~Cast() = default; void Write(CodeWriter* to) const override; }; struct VariableDeclaration : public Statement { Variable* lvalue = nullptr; const Type* cast = nullptr; Expression* rvalue = nullptr; explicit VariableDeclaration(Variable* lvalue); VariableDeclaration(Variable* lvalue, Expression* rvalue, const Type* cast = NULL); virtual ~VariableDeclaration() = default; void Write(CodeWriter* to) const override; }; struct IfStatement : public Statement { Expression* expression = nullptr; StatementBlock* statements = new StatementBlock; IfStatement* elseif = nullptr; IfStatement() = default; virtual ~IfStatement() = default; void Write(CodeWriter* to) const override; }; struct ReturnStatement : public Statement { Expression* expression; explicit ReturnStatement(Expression* expression); virtual ~ReturnStatement() = default; void Write(CodeWriter* to) const override; }; struct TryStatement : public Statement { StatementBlock* statements = new StatementBlock; TryStatement() = default; virtual ~TryStatement() = default; void Write(CodeWriter* to) const override; }; struct CatchStatement : public Statement { StatementBlock* statements; Variable* exception; explicit CatchStatement(Variable* exception); virtual ~CatchStatement() = default; void Write(CodeWriter* to) const override; }; struct FinallyStatement : public Statement { StatementBlock* statements = new StatementBlock; FinallyStatement() = default; virtual ~FinallyStatement() = default; void Write(CodeWriter* to) const override; }; struct Case { std::vector cases; StatementBlock* statements = new StatementBlock; Case() = default; explicit Case(const std::string& c); virtual ~Case() = default; virtual void Write(CodeWriter* to) const; }; struct SwitchStatement : public Statement { Expression* expression; std::vector cases; explicit SwitchStatement(Expression* expression); virtual ~SwitchStatement() = default; void Write(CodeWriter* to) const override; }; struct Break : public Statement { Break() = default; virtual ~Break() = default; void Write(CodeWriter* to) const override; }; struct Method : public ClassElement { std::string comment; int modifiers = 0; const Type* returnType = nullptr; // nullptr means constructor size_t returnTypeDimension = 0; std::string name; std::vector parameters; std::vector exceptions; StatementBlock* statements = nullptr; Method() = default; virtual ~Method() = default; void Write(CodeWriter* to) const override; }; struct IntConstant : public ClassElement { const std::string name; const int value; IntConstant(std::string name, int value) : name(name), value(value) {} virtual ~IntConstant() = default; void Write(CodeWriter* to) const override; }; struct StringConstant : public ClassElement { const std::string name; const std::string value; StringConstant(std::string name, std::string value) : name(name), value(value) {} ~StringConstant() override = default; void Write(CodeWriter* to) const override; }; struct Class : public ClassElement { enum { CLASS, INTERFACE }; std::string comment; int modifiers = 0; int what = CLASS; // CLASS or INTERFACE const Type* type = nullptr; const Type* extends = nullptr; std::vector interfaces; std::vector elements; Class() = default; virtual ~Class() = default; void Write(CodeWriter* to) const override; }; class Document { public: Document(const std::string& comment, const std::string& package, const std::string& original_src, std::unique_ptr clazz); virtual ~Document() = default; virtual void Write(CodeWriter* to) const; private: std::string comment_; std::string package_; std::string original_src_; std::unique_ptr clazz_; }; } // namespace java } // namespace aidl } // namespace android #endif // AIDL_AST_JAVA_H_ ast_java_unittest.cpp0100644 0000000 0000000 00000003175 13277516055 014061 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include "ast_java.h" #include "code_writer.h" #include "type_java.h" using std::string; namespace android { namespace aidl { namespace java { namespace { const char kExpectedClassOutput[] = R"(// class comment final class TestClass extends SuperClass { } )"; } // namespace TEST(AstJavaTests, GeneratesClass) { JavaTypeNamespace types; types.Init(); Type class_type(&types, "TestClass", ValidatableType::KIND_GENERATED, false, false); Type extend_type(&types, "SuperClass", ValidatableType::KIND_BUILT_IN, false, false); Class a_class; a_class.comment = "// class comment"; a_class.modifiers = FINAL; a_class.what = Class::CLASS; a_class.type = &class_type; a_class.extends = &extend_type; string actual_output; CodeWriterPtr writer = GetStringWriter(&actual_output); a_class.Write(writer.get()); EXPECT_EQ(string(kExpectedClassOutput), actual_output); } } // namespace java } // namespace aidl } // namespace android code_writer.cpp0100644 0000000 0000000 00000005513 13277516055 012636 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "code_writer.h" #include #include #include using std::cerr; using std::endl; namespace android { namespace aidl { namespace { class StringCodeWriter : public CodeWriter { public: explicit StringCodeWriter(std::string* output_buffer) : output_(output_buffer) {} virtual ~StringCodeWriter() = default; bool Write(const char* format, ...) override { va_list ap; va_start(ap, format); android::base::StringAppendV(output_, format, ap); va_end(ap); return true; } bool Close() override { return true; } private: std::string* output_; }; // class StringCodeWriter class FileCodeWriter : public CodeWriter { public: FileCodeWriter(FILE* output_file, bool close_on_destruction) : output_(output_file), close_on_destruction_(close_on_destruction) {} virtual ~FileCodeWriter() { if (close_on_destruction_ && output_ != nullptr) { fclose(output_); } } bool Write(const char* format, ...) override { bool success; va_list ap; va_start(ap, format); success = vfprintf(output_, format, ap) >= 0; va_end(ap); no_error_ = no_error_ && success; return success; } bool Close() override { if (output_ != nullptr) { no_error_ = fclose(output_) == 0 && no_error_; output_ = nullptr; } return no_error_; } private: bool no_error_ = true; FILE* output_; bool close_on_destruction_; }; // class StringCodeWriter } // namespace CodeWriterPtr GetFileWriter(const std::string& output_file) { CodeWriterPtr result; FILE* to = nullptr; bool close_on_destruction = true; if (output_file == "-") { to = stdout; close_on_destruction = false; } else { // open file in binary mode to ensure that the tool produces the // same output on all platforms !! to = fopen(output_file.c_str(), "wb"); } if (to != nullptr) { result.reset(new FileCodeWriter(to, close_on_destruction)); } else { cerr << "unable to open " << output_file << " for write" << endl; } return result; } CodeWriterPtr GetStringWriter(std::string* output_buffer) { return CodeWriterPtr(new StringCodeWriter(output_buffer)); } } // namespace aidl } // namespace android code_writer.h0100644 0000000 0000000 00000002751 13277516055 012304 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_CODE_WRITER_H_ #define AIDL_CODE_WRITER_H_ #include #include #include #include namespace android { namespace aidl { class CodeWriter { public: // Write a formatted string to this writer in the usual printf sense. // Returns false on error. virtual bool Write(const char* format, ...) = 0; virtual bool Close() = 0; virtual ~CodeWriter() = default; }; // class CodeWriter using CodeWriterPtr = std::unique_ptr; // Get a CodeWriter that writes to |output_file|. CodeWriterPtr GetFileWriter(const std::string& output_file); // Get a CodeWriter that writes to a string buffer. // Caller retains ownership of the buffer. // The buffer must outlive the CodeWriter. CodeWriterPtr GetStringWriter(std::string* output_buffer); } // namespace aidl } // namespace android #endif // AIDL_CODE_WRITER_H_ docs/0040755 0000000 0000000 00000000000 13277516055 010553 5ustar000000000 0000000 docs/aidl-cpp.md0100644 0000000 0000000 00000027040 13277516055 012566 0ustar000000000 0000000 # Generating C++ Binder Interfaces with `aidl-cpp` ## Background “aidl” refers to several related but distinct concepts: - the AIDL interface [definition language](http://developer.android.com/guide/components/aidl.html) - .aidl files (which contain AIDL) - the aidl generator which transforms AIDL into client/server IPC interfaces The _aidl generator_ is a command line tool that generates client and server stubs for Binder interfaces from a specification in a file with the .aidl extension. For Java interfaces, the executable is called `aidl` while for C++ the binary is called `aidl-cpp`. In this document, we’ll use AIDL to describe the language of .aidl files and _aidl generator_ to refer to the code generation tool that takes an .aidl file, parses the AIDL, and outputs code. Previously, the _aidl generator_ only generated Java interface/stub/proxy objects. C++ Binder interfaces were handcrafted with various degrees of compatibility with the Java equivalents. The Brillo project added support for generating C++ with the _aidl generator_. This generated C++ is cross-language compatible (e.g. Java clients are tested to interoperate with native services). ## Overview This document describes how C++ generation works with attention to: - build interface - cross-language type mapping - implementing a generated interface - C++ parcelables - cross-language error reporting - cross-language null reference handling ## Detailed Design ### Build Interface Write AIDL in .aidl files and add them to `LOCAL_SRC_FILES` in your Android.mk. If your build target is a binary (e.g. you include `$(BUILD_SHARED_LIBRARY)`), then the generated code will be C++, not Java. AIDL definitions should be hosted from the same repository as the implementation. Any system that needs the definition will also need the implementation (for both parcelables and interface). If there are multiple implementations (i.e. one in Java and one in C++), keep the definition with the native implementation. Android [now has systems](https://developers.google.com/brillo/?hl=en) that run the native components of the system without the Java. If you use an import statement in your AIDL, even from the same package, you need to add a path to `LOCAL_AIDL_INCLUDES`. This path should be relative to the root of the Android tree. For instance, a file IFoo.aidl defining com.example.IFoo might sit in a folder hierarchy something/something-else/com/example/IFoo.aidl. Then we would write: ``` LOCAL_AIDL_INCLUDES := something/something-else ``` Generated C++ ends up in nested namespaces corresponding to the interface’s package. The generated header also corresponds to the interface package. So com.example.IFoo becomes ::com::example::IFoo in header “com/example/IFoo.h”. Similar to how Java works, the suffix of the path to a .aidl file must match the package. So if IFoo.aidl declares itself to be in package com.example, the folder structure (as given to `LOCAL_SRC_FILES`) must look like: `some/prefix/com/example/IFoo.aidl`. To generate code from .aidl files from another build target (e.g. another binary or java), just add a relative path to the .aidl files to `LOCAL_SRC_FILES`. Remember that importing AIDL works the same, even for code in other directory hierarchies: add the include root path relative to the checkout root to `LOCAL_AIDL_INCLUDES`. ### Type Mapping The following table summarizes the equivalent C++ types for common Java types and whether those types may be used as in/out/inout parameters in AIDL interfaces. | Java Type | C++ Type | inout | Notes | |-----------------------|---------------------|-------|-------------------------------------------------------| | boolean | bool | in | "These 8 types are all considered primitives. | | byte | int8\_t | in | | | char | char16\_t | in | | | int | int32\_t | in | | | long | int64\_t | in | | | float | float | in | | | double | double | in | | | String | String16 | in | Supports null references. | | @utf8InCpp String | std::string | in | @utf8InCpp causes UTF16 to UTF8 conversion in C++. | | android.os.Parcelable | android::Parcelable | inout | | | java.util.Map | android::binder::Map| inout | `std::map` | | T extends IBinder | sp | in | | | Arrays (T[]) | vector | inout | May contain only primitives, Strings and parcelables. | | List | vector | inout | | | PersistableBundle | PersistableBundle | inout | binder/PersistableBundle.h | | List | vector> | inout | | | FileDescriptor | unique_fd | inout | android-base/unique_fd.h from libbase | Note that annotations may be placed at the interface level, as well as on a type by type basis. Interface level annotations will be applied opportunistically and be overridden by per type annotations. For instance, an interface marked @nullable will still not allow null int parameters. ### Implementing a generated interface Given an interface declaration like: ``` package foo; import bar.IAnotherInterface; interface IFoo { IAnotherInterface DoSomething(int count, out List output); } ``` `aidl-cpp` will generate a C++ interface: ``` namespace foo { // Some headers have been omitted for clarity. #include #include #include #include // Some class members have been omitted for clarity. class IFoo : public android::IInterface { public: virtual android::binder::Status DoSomething( int32_t count, std::vector* output, android::sp* returned_value) = 0; }; ``` Note that `aidl-cpp` will import headers for types used in the interface. For imported types (e.g. parcelables and interfaces), it will import a header corresponding to the package/class name of the import. For instance, `import bar.IAnotherInterface` causes aidl-cpp to generate `#include `. When writing a service that implements this interface, write: ``` #include "foo/BnFoo.h" namespace unrelated_namespace { class MyFoo : public foo::BnFoo { public: android::binder::Status DoSomething( int32_t count, std::vector* output, android::sp* returned_value) override { for (int32_t i = 0; i < count; ++i) { output->push_back(String16("...")); } *returned_value = new InstanceOfAnotherInterface; return Status::ok(); } }; // class MyFoo } // namespace unrelated_namespace ``` Note that the output values, `output` and `returned_value` are passed by pointer, and that this pointer is always valid. #### Dependencies The generated C++ code will use symbols from libbinder as well as libutils. AIDL files using the FileDescriptor type will also explicitly require libnativehelper, although this is likely a transitive dependency of the other two, and should be included automatically within the Android build tree regardless. ### C++ Parcelables In Java, a parcelable should extend android.os.Parcelable and provide a static final CREATOR field that acts as a factory for new instances/arrays of instances of the parcelable. In addition, in order to be used as an out parameter, a parcelable class must define a readFromParcel method. In C++, parcelables must implement android::Parcelable from binder/Parcelable.h in libbinder. Parcelables must define a constructor that takes no arguments. In order to be used in arrays, a parcelable must implement a copy or move constructor (called implicitly in vector). The C++ generator needs to know what header defines the C++ parcelable. It learns this from the `cpp_header` directive shown below. The generator takes this string and uses it as the literal include statement in generated code. The idea here is that you generate your code once, link it into a library along with parcelable implementations, and export appropriate header paths. This header include must make sense in the context of the Android.mk that compiles this generated code. ``` // ExampleParcelable.aidl package com.example.android; // Native types must be aliased at their declaration in the appropriate .aidl // file. This allows multiple interfaces to use a parcelable and its C++ // equivalent without duplicating the mapping between the C++ and Java types. // Generator will assume bar/foo.h declares class // com::example::android::ExampleParcelable parcelable ExampleParcelable cpp_header "bar/foo.h"; ``` ### Null Reference Handling The aidl generator for both C++ and Java languages has been expanded to understand nullable annotations. Given an interface definition like: ``` interface IExample { void ReadStrings(String neverNull, in @nullable String maybeNull); }; ``` the generated C++ header code looks like: ``` class IExample { android::binder::Status ReadStrings( const android::String16& in_neverNull, const std::unique_ptr& in_maybeNull); }; ``` Note that by default, the generated C++ passes a const reference to the value of a parameter and rejects null references with a NullPointerException sent back the caller. Parameters marked with @nullable are passed by pointer, allowing native services to explicitly control whether they allow method overloading via null parameters. Java stubs and proxies currently do nothing with the @nullable annotation. Consider an AIDL type `in @nullable List bar`. This type indicates that the remote caller may pass in a list of strings, and that both the list and any string in the list may be null. This type will map to a C++ type `unique_ptr>>* bar`. In this case: - `bar` is never null - `*bar` might be null - `(*bar)->empty()` could be true - `(**bar)[0]` could be null (and so on) ### Exception Reporting C++ methods generated by the aidl generator return `android::binder::Status` objects, rather than `android::status_t`. This Status object allows generated C++ code to send and receive exceptions (an exception type and a String16 error message) since we do not use real exceptions in C++. More background on Status objects can be found here. For legacy support and migration ease, the Status object includes a mechanism to report a `android::status_t`. However, that return code is interpreted by a different code path and does not include a helpful String message. For situations where your native service needs to throw an error code specific to the service, use `Status::fromServiceSpecificError()`. This kind of exception comes with a helpful message and an integer error code. Make your error codes consistent across services by using interface constants (see below). docs/constants.md0100644 0000000 0000000 00000001460 13277516055 013107 0ustar000000000 0000000 # Defining constants as part of an interface AIDL has been enhanced to support defining integer and string constants as part of an interface. ## Integer constants ``` interface IMyInterface { const int CONST_A = 1; const int CONST_B = 2; const int CONST_C = 3; ... } ``` These map to appropriate 32 bit integer class constants in Java and C++ (e.g. `IMyInterface.CONST_A` and `IMyInterface::CONST_A` respectively). ## String constants ``` interface IMyInterface { const String CONST_A = "foo"; const String CONST_B = "bar"; ... } ``` These map to class level String constants in Java, and static getter functions that return a const android::String16& in C++. The constants are limited to contain printable ASCII characters < 0x10 and without backspaces (i.e. no '\' character). docs/making-changes.md0100644 0000000 0000000 00000001003 13277516055 013740 0ustar000000000 0000000 # Making changes ## Coding style This project was originally written in C, in the Android platform style. It has been substantially re-written in C++, in the Google C++ style. This style [is summarized here](https://google.github.io/styleguide/cppguide.html). When in doubt, clang-format -style=google is a good reference. ## Testing This codebase has both integration and unittests, all of which are expected to consistently pass against a device/emulator: ``` $ ./runtests.sh && echo "All tests pass" ``` generate_cpp.cpp0100644 0000000 0000000 00000075661 13277516055 012777 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "generate_cpp.h" #include #include #include #include #include #include #include #include "aidl_language.h" #include "ast_cpp.h" #include "code_writer.h" #include "logging.h" #include "os.h" using android::base::StringPrintf; using std::string; using std::unique_ptr; using std::vector; using std::set; namespace android { namespace aidl { namespace cpp { namespace internals { namespace { const char kAndroidStatusVarName[] = "_aidl_ret_status"; const char kCodeVarName[] = "_aidl_code"; const char kFlagsVarName[] = "_aidl_flags"; const char kDataVarName[] = "_aidl_data"; const char kErrorLabel[] = "_aidl_error"; const char kImplVarName[] = "_aidl_impl"; const char kReplyVarName[] = "_aidl_reply"; const char kReturnVarName[] = "_aidl_return"; const char kStatusVarName[] = "_aidl_status"; const char kAndroidParcelLiteral[] = "::android::Parcel"; const char kAndroidStatusLiteral[] = "::android::status_t"; const char kAndroidStatusOk[] = "::android::OK"; const char kBinderStatusLiteral[] = "::android::binder::Status"; const char kIBinderHeader[] = "binder/IBinder.h"; const char kIInterfaceHeader[] = "binder/IInterface.h"; const char kParcelHeader[] = "binder/Parcel.h"; const char kStatusHeader[] = "binder/Status.h"; const char kString16Header[] = "utils/String16.h"; const char kStrongPointerHeader[] = "utils/StrongPointer.h"; unique_ptr BreakOnStatusNotOk() { IfStatement* ret = new IfStatement(new Comparison( new LiteralExpression(kAndroidStatusVarName), "!=", new LiteralExpression(kAndroidStatusOk))); ret->OnTrue()->AddLiteral("break"); return unique_ptr(ret); } unique_ptr GotoErrorOnBadStatus() { IfStatement* ret = new IfStatement(new Comparison( new LiteralExpression(kAndroidStatusVarName), "!=", new LiteralExpression(kAndroidStatusOk))); ret->OnTrue()->AddLiteral(StringPrintf("goto %s", kErrorLabel)); return unique_ptr(ret); } unique_ptr ReturnOnStatusNotOk() { IfStatement* ret = new IfStatement(new Comparison( new LiteralExpression(kAndroidStatusVarName), "!=", new LiteralExpression(kAndroidStatusOk))); ret->OnTrue()->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName)); return unique_ptr(ret); } string UpperCase(const std::string& s) { string result = s; for (char& c : result) c = toupper(c); return result; } string BuildVarName(const AidlArgument& a) { string prefix = "out_"; if (a.GetDirection() & AidlArgument::IN_DIR) { prefix = "in_"; } return prefix + a.GetName(); } ArgList BuildArgList(const TypeNamespace& types, const AidlMethod& method, bool for_declaration) { // Build up the argument list for the server method call. vector method_arguments; for (const unique_ptr& a : method.GetArguments()) { string literal; if (for_declaration) { // Method declarations need types, pointers to out params, and variable // names that match the .aidl specification. const Type* type = a->GetType().GetLanguageType(); literal = type->CppType(); if (a->IsOut()) { literal = literal + "*"; } else { // We pass in parameters that are not primitives by const reference. // Arrays of primitives are not primitives. if (!type->IsCppPrimitive() || a->GetType().IsArray()) { literal = "const " + literal + "&"; } } literal += " " + a->GetName(); } else { if (a->IsOut()) { literal = "&"; } literal += BuildVarName(*a); } method_arguments.push_back(literal); } const Type* return_type = method.GetType().GetLanguageType(); if (return_type != types.VoidType()) { string literal; if (for_declaration) { literal = StringPrintf( "%s* %s", return_type->CppType().c_str(), kReturnVarName); } else { literal = string{"&"} + kReturnVarName; } method_arguments.push_back(literal); } return ArgList(method_arguments); } unique_ptr BuildMethodDecl(const AidlMethod& method, const TypeNamespace& types, bool for_interface) { uint32_t modifiers = 0; if (for_interface) { modifiers |= MethodDecl::IS_VIRTUAL; modifiers |= MethodDecl::IS_PURE_VIRTUAL; } else { modifiers |= MethodDecl::IS_OVERRIDE; } return unique_ptr{ new MethodDecl{kBinderStatusLiteral, method.GetName(), BuildArgList(types, method, true /* for method decl */), modifiers}}; } unique_ptr NestInNamespaces( vector> decls, const vector& package) { if (package.empty()) { // We should also be checking this before we get this far, but do it again // for the sake of unit tests and meaningful errors. LOG(FATAL) << "C++ generation requires a package declaration " "for namespacing"; } auto it = package.crbegin(); // Iterate over the namespaces inner to outer unique_ptr inner{new CppNamespace{*it, std::move(decls)}}; ++it; for (; it != package.crend(); ++it) { inner.reset(new CppNamespace{*it, std::move(inner)}); } return inner; } unique_ptr NestInNamespaces(unique_ptr decl, const vector& package) { vector> decls; decls.push_back(std::move(decl)); return NestInNamespaces(std::move(decls), package); } bool DeclareLocalVariable(const TypeNamespace& types, const AidlArgument& a, StatementBlock* b) { const Type* cpp_type = a.GetType().GetLanguageType(); if (!cpp_type) { return false; } string type = cpp_type->CppType(); b->AddLiteral(type + " " + BuildVarName(a)); return true; } string ClassName(const AidlInterface& interface, ClassNames type) { string c_name = interface.GetName(); if (c_name.length() >= 2 && c_name[0] == 'I' && isupper(c_name[1])) c_name = c_name.substr(1); switch (type) { case ClassNames::CLIENT: c_name = "Bp" + c_name; break; case ClassNames::SERVER: c_name = "Bn" + c_name; break; case ClassNames::INTERFACE: c_name = "I" + c_name; break; case ClassNames::BASE: break; } return c_name; } string BuildHeaderGuard(const AidlInterface& interface, ClassNames header_type) { string class_name = ClassName(interface, 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(), class_name.c_str()); for (char& c : ret) { if (c == '.') { c = '_'; } c = toupper(c); } return ret; } unique_ptr DefineClientTransaction(const TypeNamespace& types, const AidlInterface& interface, const AidlMethod& method) { const string i_name = ClassName(interface, ClassNames::INTERFACE); const string bp_name = ClassName(interface, ClassNames::CLIENT); unique_ptr ret{new MethodImpl{ kBinderStatusLiteral, bp_name, method.GetName(), ArgList{BuildArgList(types, method, true /* for method decl */)}}}; StatementBlock* b = ret->GetStatementBlock(); // Declare parcels to hold our query and the response. b->AddLiteral(StringPrintf("%s %s", kAndroidParcelLiteral, kDataVarName)); // Even if we're oneway, the transact method still takes a parcel. b->AddLiteral(StringPrintf("%s %s", kAndroidParcelLiteral, kReplyVarName)); // Declare the status_t variable we need for error handling. b->AddLiteral(StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk)); // We unconditionally return a Status object. b->AddLiteral(StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName)); // Add the name of the interface we're hoping to call. b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("%s.writeInterfaceToken", kDataVarName), "getInterfaceDescriptor()"))); b->AddStatement(GotoErrorOnBadStatus()); for (const auto& a: method.GetArguments()) { const Type* type = a->GetType().GetLanguageType(); string var_name = ((a->IsOut()) ? "*" : "") + a->GetName(); var_name = type->WriteCast(var_name); if (a->IsIn()) { // Serialization looks roughly like: // _aidl_ret_status = _aidl_data.WriteInt32(in_param_name); // if (_aidl_ret_status != ::android::OK) { goto error; } const string& method = type->WriteToParcelMethod(); b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("%s.%s", kDataVarName, method.c_str()), ArgList(var_name)))); b->AddStatement(GotoErrorOnBadStatus()); } else if (a->IsOut() && a->GetType().IsArray()) { // Special case, the length of the out array is written into the parcel. // _aidl_ret_status = _aidl_data.writeVectorSize(&out_param_name); // if (_aidl_ret_status != ::android::OK) { goto error; } b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("%s.writeVectorSize", kDataVarName), ArgList(var_name)))); b->AddStatement(GotoErrorOnBadStatus()); } } // Invoke the transaction on the remote binder and confirm status. string transaction_code = StringPrintf( "%s::%s", i_name.c_str(), UpperCase(method.GetName()).c_str()); vector args = {transaction_code, kDataVarName, StringPrintf("&%s", kReplyVarName)}; if (interface.IsOneway() || method.IsOneway()) { args.push_back("::android::IBinder::FLAG_ONEWAY"); } b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall("remote()->transact", ArgList(args)))); b->AddStatement(GotoErrorOnBadStatus()); if (!interface.IsOneway() && !method.IsOneway()) { // Strip off the exception header and fail if we see a remote exception. // _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); // if (_aidl_ret_status != ::android::OK) { goto error; } // if (!_aidl_status.isOk()) { return _aidl_ret_status; } b->AddStatement(new Assignment( kAndroidStatusVarName, StringPrintf("%s.readFromParcel(%s)", kStatusVarName, kReplyVarName))); b->AddStatement(GotoErrorOnBadStatus()); IfStatement* exception_check = new IfStatement( new LiteralExpression(StringPrintf("!%s.isOk()", kStatusVarName))); b->AddStatement(exception_check); exception_check->OnTrue()->AddLiteral( StringPrintf("return %s", kStatusVarName)); } // Type checking should guarantee that nothing below emits code until "return // status" if we are a oneway method, so no more fear of accessing reply. // If the method is expected to return something, read it first by convention. const Type* return_type = method.GetType().GetLanguageType(); if (return_type != types.VoidType()) { const string& method_call = return_type->ReadFromParcelMethod(); b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("%s.%s", kReplyVarName, method_call.c_str()), ArgList(kReturnVarName)))); b->AddStatement(GotoErrorOnBadStatus()); } for (const AidlArgument* a : method.GetOutArguments()) { // Deserialization looks roughly like: // _aidl_ret_status = _aidl_reply.ReadInt32(out_param_name); // if (_aidl_status != ::android::OK) { goto _aidl_error; } string method = a->GetType().GetLanguageType()->ReadFromParcelMethod(); b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("%s.%s", kReplyVarName, method.c_str()), ArgList(a->GetName())))); b->AddStatement(GotoErrorOnBadStatus()); } // If we've gotten to here, one of two things is true: // 1) We've read some bad status_t // 2) We've only read status_t == OK and there was no exception in the // response. // In both cases, we're free to set Status from the status_t and return. b->AddLiteral(StringPrintf("%s:\n", kErrorLabel), false /* no semicolon */); b->AddLiteral( StringPrintf("%s.setFromStatusT(%s)", kStatusVarName, kAndroidStatusVarName)); b->AddLiteral(StringPrintf("return %s", kStatusVarName)); return unique_ptr(ret.release()); } } // namespace unique_ptr BuildClientSource(const TypeNamespace& types, const AidlInterface& interface) { vector include_list = { HeaderFile(interface, ClassNames::CLIENT, false), kParcelHeader }; vector> file_decls; // The constructor just passes the IBinder instance up to the super // class. const string i_name = ClassName(interface, ClassNames::INTERFACE); file_decls.push_back(unique_ptr{new ConstructorImpl{ ClassName(interface, ClassNames::CLIENT), ArgList{StringPrintf("const ::android::sp<::android::IBinder>& %s", kImplVarName)}, { "BpInterface<" + i_name + ">(" + kImplVarName + ")" }}}); // Clients define a method per transaction. for (const auto& method : interface.GetMethods()) { unique_ptr m = DefineClientTransaction( types, interface, *method); if (!m) { return nullptr; } file_decls.push_back(std::move(m)); } return unique_ptr{new CppSource{ include_list, NestInNamespaces(std::move(file_decls), interface.GetSplitPackage())}}; } namespace { bool HandleServerTransaction(const TypeNamespace& types, const AidlMethod& method, StatementBlock* b) { // Declare all the parameters now. In the common case, we expect no errors // in serialization. for (const unique_ptr& a : method.GetArguments()) { if (!DeclareLocalVariable(types, *a, b)) { return false; } } // Declare a variable to hold the return value. const Type* return_type = method.GetType().GetLanguageType(); if (return_type != types.VoidType()) { b->AddLiteral(StringPrintf( "%s %s", return_type->CppType().c_str(), kReturnVarName)); } // Check that the client is calling the correct interface. IfStatement* interface_check = new IfStatement( new MethodCall(StringPrintf("%s.checkInterface", kDataVarName), "this"), true /* invert the check */); b->AddStatement(interface_check); interface_check->OnTrue()->AddStatement( new Assignment(kAndroidStatusVarName, "::android::BAD_TYPE")); interface_check->OnTrue()->AddLiteral("break"); // Deserialize each "in" parameter to the transaction. for (const auto& a: method.GetArguments()) { // Deserialization looks roughly like: // _aidl_ret_status = _aidl_data.ReadInt32(&in_param_name); // if (_aidl_ret_status != ::android::OK) { break; } const Type* type = a->GetType().GetLanguageType(); const string& readMethod = type->ReadFromParcelMethod(); if (a->IsIn()) { b->AddStatement(new Assignment{ kAndroidStatusVarName, new MethodCall{string(kDataVarName) + "." + readMethod, "&" + BuildVarName(*a)}}); b->AddStatement(BreakOnStatusNotOk()); } else if (a->IsOut() && a->GetType().IsArray()) { // Special case, the length of the out array is written into the parcel. // _aidl_ret_status = _aidl_data.resizeOutVector(&out_param_name); // if (_aidl_ret_status != ::android::OK) { break; } b->AddStatement(new Assignment{ kAndroidStatusVarName, new MethodCall{string(kDataVarName) + ".resizeOutVector", "&" + BuildVarName(*a)}}); b->AddStatement(BreakOnStatusNotOk()); } } // Call the actual method. This is implemented by the subclass. vector> status_args; status_args.emplace_back(new MethodCall( method.GetName(), BuildArgList(types, method, false /* not for method decl */))); b->AddStatement(new Statement(new MethodCall( StringPrintf("%s %s", kBinderStatusLiteral, kStatusVarName), ArgList(std::move(status_args))))); // Write exceptions during transaction handling to parcel. if (!method.IsOneway()) { b->AddStatement(new Assignment( kAndroidStatusVarName, StringPrintf("%s.writeToParcel(%s)", kStatusVarName, kReplyVarName))); b->AddStatement(BreakOnStatusNotOk()); IfStatement* exception_check = new IfStatement( new LiteralExpression(StringPrintf("!%s.isOk()", kStatusVarName))); b->AddStatement(exception_check); exception_check->OnTrue()->AddLiteral("break"); } // If we have a return value, write it first. if (return_type != types.VoidType()) { string writeMethod = string(kReplyVarName) + "->" + return_type->WriteToParcelMethod(); b->AddStatement(new Assignment{ kAndroidStatusVarName, new MethodCall{writeMethod, ArgList{return_type->WriteCast(kReturnVarName)}}}); b->AddStatement(BreakOnStatusNotOk()); } // Write each out parameter to the reply parcel. for (const AidlArgument* a : method.GetOutArguments()) { // Serialization looks roughly like: // _aidl_ret_status = data.WriteInt32(out_param_name); // if (_aidl_ret_status != ::android::OK) { break; } const Type* type = a->GetType().GetLanguageType(); const string& writeMethod = type->WriteToParcelMethod(); b->AddStatement(new Assignment{ kAndroidStatusVarName, new MethodCall{string(kReplyVarName) + "->" + writeMethod, type->WriteCast(BuildVarName(*a))}}); b->AddStatement(BreakOnStatusNotOk()); } return true; } } // namespace unique_ptr BuildServerSource(const TypeNamespace& types, const AidlInterface& interface) { const string bn_name = ClassName(interface, ClassNames::SERVER); vector include_list{ HeaderFile(interface, ClassNames::SERVER, false), kParcelHeader }; unique_ptr on_transact{new MethodImpl{ kAndroidStatusLiteral, bn_name, "onTransact", ArgList{{StringPrintf("uint32_t %s", kCodeVarName), StringPrintf("const %s& %s", kAndroidParcelLiteral, kDataVarName), StringPrintf("%s* %s", kAndroidParcelLiteral, kReplyVarName), StringPrintf("uint32_t %s", kFlagsVarName)}} }}; // Declare the status_t variable on_transact->GetStatementBlock()->AddLiteral( StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk)); // Add the all important switch statement, but retain a pointer to it. SwitchStatement* s = new SwitchStatement{kCodeVarName}; on_transact->GetStatementBlock()->AddStatement(s); // The switch statement has a case statement for each transaction code. for (const auto& method : interface.GetMethods()) { StatementBlock* b = s->AddCase("Call::" + UpperCase(method->GetName())); if (!b) { return nullptr; } if (!HandleServerTransaction(types, *method, b)) { return nullptr; } } // The switch statement has a default case which defers to the super class. // The superclass handles a few pre-defined transactions. StatementBlock* b = s->AddCase(""); b->AddLiteral(StringPrintf( "%s = ::android::BBinder::onTransact(%s, %s, " "%s, %s)", kAndroidStatusVarName, kCodeVarName, kDataVarName, kReplyVarName, kFlagsVarName)); // If we saw a null reference, we can map that to an appropriate exception. IfStatement* null_check = new IfStatement( new LiteralExpression(string(kAndroidStatusVarName) + " == ::android::UNEXPECTED_NULL")); on_transact->GetStatementBlock()->AddStatement(null_check); null_check->OnTrue()->AddStatement(new Assignment( kAndroidStatusVarName, StringPrintf("%s::fromExceptionCode(%s::EX_NULL_POINTER)" ".writeToParcel(%s)", kBinderStatusLiteral, kBinderStatusLiteral, kReplyVarName))); // Finally, the server's onTransact method just returns a status code. on_transact->GetStatementBlock()->AddLiteral( StringPrintf("return %s", kAndroidStatusVarName)); return unique_ptr{new CppSource{ include_list, NestInNamespaces(std::move(on_transact), interface.GetSplitPackage())}}; } unique_ptr BuildInterfaceSource(const TypeNamespace& /* types */, const AidlInterface& interface) { vector include_list{ HeaderFile(interface, ClassNames::INTERFACE, false), HeaderFile(interface, ClassNames::CLIENT, false), }; string fq_name = ClassName(interface, ClassNames::INTERFACE); if (!interface.GetPackage().empty()) { fq_name = interface.GetPackage() + "." + fq_name; } vector> decls; unique_ptr meta_if{new MacroDecl{ "IMPLEMENT_META_INTERFACE", ArgList{vector{ClassName(interface, ClassNames::BASE), '"' + fq_name + '"'}}}}; decls.push_back(std::move(meta_if)); for (const auto& constant: interface.GetStringConstants()) { unique_ptr getter(new MethodImpl( "const ::android::String16&", ClassName(interface, ClassNames::INTERFACE), constant->GetName(), {})); getter->GetStatementBlock()->AddLiteral( StringPrintf("static const ::android::String16 value(%s)", constant->GetValue().c_str())); getter->GetStatementBlock()->AddLiteral("return value"); decls.push_back(std::move(getter)); } return unique_ptr{new CppSource{ include_list, NestInNamespaces(std::move(decls), interface.GetSplitPackage())}}; } unique_ptr BuildClientHeader(const TypeNamespace& types, const AidlInterface& interface) { const string i_name = ClassName(interface, ClassNames::INTERFACE); const string bp_name = ClassName(interface, ClassNames::CLIENT); unique_ptr constructor{new ConstructorDecl{ bp_name, ArgList{StringPrintf("const ::android::sp<::android::IBinder>& %s", kImplVarName)}, ConstructorDecl::IS_EXPLICIT }}; unique_ptr destructor{new ConstructorDecl{ "~" + bp_name, ArgList{}, ConstructorDecl::IS_VIRTUAL | ConstructorDecl::IS_DEFAULT}}; vector> publics; publics.push_back(std::move(constructor)); publics.push_back(std::move(destructor)); for (const auto& method: interface.GetMethods()) { publics.push_back(BuildMethodDecl(*method, types, false)); } unique_ptr bp_class{ new ClassDecl{bp_name, "::android::BpInterface<" + i_name + ">", std::move(publics), {} }}; return unique_ptr{new CppHeader{ BuildHeaderGuard(interface, ClassNames::CLIENT), {kIBinderHeader, kIInterfaceHeader, "utils/Errors.h", HeaderFile(interface, ClassNames::INTERFACE, false)}, NestInNamespaces(std::move(bp_class), interface.GetSplitPackage())}}; } unique_ptr BuildServerHeader(const TypeNamespace& /* types */, const AidlInterface& interface) { const string i_name = ClassName(interface, ClassNames::INTERFACE); const string bn_name = ClassName(interface, ClassNames::SERVER); unique_ptr on_transact{new MethodDecl{ kAndroidStatusLiteral, "onTransact", ArgList{{StringPrintf("uint32_t %s", kCodeVarName), StringPrintf("const %s& %s", kAndroidParcelLiteral, kDataVarName), StringPrintf("%s* %s", kAndroidParcelLiteral, kReplyVarName), StringPrintf("uint32_t %s = 0", kFlagsVarName)}}, MethodDecl::IS_OVERRIDE }}; std::vector> publics; publics.push_back(std::move(on_transact)); unique_ptr bn_class{ new ClassDecl{bn_name, "::android::BnInterface<" + i_name + ">", std::move(publics), {} }}; return unique_ptr{new CppHeader{ BuildHeaderGuard(interface, ClassNames::SERVER), {"binder/IInterface.h", HeaderFile(interface, ClassNames::INTERFACE, false)}, NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}}; } unique_ptr BuildInterfaceHeader(const TypeNamespace& types, const AidlInterface& interface) { set includes = { kIBinderHeader, kIInterfaceHeader, kStatusHeader, kStrongPointerHeader }; for (const auto& method : interface.GetMethods()) { for (const auto& argument : method->GetArguments()) { const Type* type = argument->GetType().GetLanguageType(); type->GetHeaders(&includes); } const Type* return_type = method->GetType().GetLanguageType(); return_type->GetHeaders(&includes); } unique_ptr if_class{ new ClassDecl{ClassName(interface, ClassNames::INTERFACE), "::android::IInterface"}}; if_class->AddPublic(unique_ptr{new MacroDecl{ "DECLARE_META_INTERFACE", ArgList{vector{ClassName(interface, ClassNames::BASE)}}}}); unique_ptr constant_enum{new Enum{"", "int32_t"}}; for (const auto& constant : interface.GetIntConstants()) { constant_enum->AddValue( constant->GetName(), std::to_string(constant->GetValue())); } if (constant_enum->HasValues()) { if_class->AddPublic(std::move(constant_enum)); } if (!interface.GetStringConstants().empty()) { includes.insert(kString16Header); } for (const auto& constant : interface.GetStringConstants()) { unique_ptr getter(new MethodDecl( "const ::android::String16&", constant->GetName(), {}, MethodDecl::IS_STATIC)); if_class->AddPublic(std::move(getter)); } if (!interface.GetMethods().empty()) { unique_ptr call_enum{new Enum{"Call"}}; for (const auto& method : interface.GetMethods()) { // Each method gets an enum entry and pure virtual declaration. if_class->AddPublic(BuildMethodDecl(*method, types, true)); call_enum->AddValue( UpperCase(method->GetName()), StringPrintf("::android::IBinder::FIRST_CALL_TRANSACTION + %d", method->GetId())); } if_class->AddPublic(std::move(call_enum)); } return unique_ptr{new CppHeader{ BuildHeaderGuard(interface, ClassNames::INTERFACE), vector(includes.begin(), includes.end()), NestInNamespaces(std::move(if_class), interface.GetSplitPackage())}}; } bool WriteHeader(const CppOptions& options, const TypeNamespace& types, const AidlInterface& interface, const IoDelegate& io_delegate, ClassNames header_type) { unique_ptr header; switch (header_type) { case ClassNames::INTERFACE: header = BuildInterfaceHeader(types, interface); break; case ClassNames::CLIENT: header = BuildClientHeader(types, interface); break; case ClassNames::SERVER: header = BuildServerHeader(types, interface); break; default: LOG(FATAL) << "aidl internal error"; } if (!header) { LOG(ERROR) << "aidl internal error: Failed to generate header."; return false; } const string header_path = options.OutputHeaderDir() + OS_PATH_SEPARATOR + HeaderFile(interface, header_type); unique_ptr code_writer(io_delegate.GetCodeWriter(header_path)); header->Write(code_writer.get()); const bool success = code_writer->Close(); if (!success) { io_delegate.RemovePath(header_path); } return success; } } // namespace internals using namespace internals; string HeaderFile(const AidlInterface& interface, ClassNames class_type, bool use_os_sep) { string file_path = interface.GetPackage(); for (char& c: file_path) { if (c == '.') { c = (use_os_sep) ? OS_PATH_SEPARATOR : '/'; } } if (!file_path.empty()) { file_path += (use_os_sep) ? OS_PATH_SEPARATOR : '/'; } file_path += ClassName(interface, class_type); file_path += ".h"; return file_path; } bool GenerateCpp(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); if (!interface_src || !client_src || !server_src) { return false; } if (!io_delegate.CreatedNestedDirs(options.OutputHeaderDir(), interface.GetSplitPackage())) { LOG(ERROR) << "Failed to create directory structure for headers."; return false; } if (!WriteHeader(options, types, interface, io_delegate, ClassNames::INTERFACE) || !WriteHeader(options, types, interface, io_delegate, ClassNames::CLIENT) || !WriteHeader(options, types, interface, io_delegate, ClassNames::SERVER)) { return false; } unique_ptr writer = io_delegate.GetCodeWriter( options.OutputCppFilePath()); interface_src->Write(writer.get()); client_src->Write(writer.get()); server_src->Write(writer.get()); const bool success = writer->Close(); if (!success) { io_delegate.RemovePath(options.OutputCppFilePath()); } return success; } } // namespace cpp } // namespace aidl } // namespace android generate_cpp.h0100644 0000000 0000000 00000005126 13277516055 012431 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_GENERATE_CPP_H_ #define AIDL_GENERATE_CPP_H_ #include #include #include "aidl_language.h" #include "ast_cpp.h" #include "options.h" #include "type_cpp.h" namespace android { namespace aidl { namespace cpp { bool GenerateCpp(const CppOptions& options, const cpp::TypeNamespace& types, const AidlInterface& parsed_doc, const IoDelegate& io_delegate); // These roughly correspond to the various class names in the C++ hierarchy: enum class ClassNames { BASE, // Foo (not a real class, but useful in some circumstances). CLIENT, // BpFoo SERVER, // BnFoo INTERFACE, // IFoo }; // 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, bool use_os_sep = true); namespace internals { std::unique_ptr BuildClientSource(const TypeNamespace& types, const AidlInterface& parsed_doc); std::unique_ptr BuildServerSource(const TypeNamespace& types, const AidlInterface& parsed_doc); std::unique_ptr BuildInterfaceSource(const TypeNamespace& types, const AidlInterface& parsed_doc); std::unique_ptr BuildClientHeader(const TypeNamespace& types, const AidlInterface& parsed_doc); std::unique_ptr BuildServerHeader(const TypeNamespace& types, const AidlInterface& parsed_doc); std::unique_ptr BuildInterfaceHeader(const TypeNamespace& types, const AidlInterface& parsed_doc); } } // namespace cpp } // namespace aidl } // namespace android #endif // AIDL_GENERATE_CPP_H_ generate_cpp_unittest.cpp0100644 0000000 0000000 00000072225 13277516055 014727 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include #include "aidl.h" #include "aidl_language.h" #include "ast_cpp.h" #include "code_writer.h" #include "generate_cpp.h" #include "os.h" #include "tests/fake_io_delegate.h" #include "tests/test_util.h" #include "type_cpp.h" using ::android::aidl::test::FakeIoDelegate; using ::android::base::StringPrintf; using std::string; using std::unique_ptr; namespace android { namespace aidl { namespace cpp { namespace { const string kComplexTypeInterfaceAIDL = R"(package android.os; import foo.IFooType; interface IComplexTypeInterface { const int MY_CONSTANT = 3; int[] Send(in @nullable int[] goes_in, inout double[] goes_in_and_out, out boolean[] goes_out); oneway void Piff(int times); IFooType TakesABinder(IFooType f); @nullable IFooType NullableBinder(); List StringListMethod(in java.util.List input, out List output); List BinderListMethod(in java.util.List input, out List output); FileDescriptor TakesAFileDescriptor(in FileDescriptor f); FileDescriptor[] TakesAFileDescriptorArray(in FileDescriptor[] f); })"; const char kExpectedComplexTypeClientHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_BP_COMPLEX_TYPE_INTERFACE_H_ #define AIDL_GENERATED_ANDROID_OS_BP_COMPLEX_TYPE_INTERFACE_H_ #include #include #include #include namespace android { namespace os { class BpComplexTypeInterface : public ::android::BpInterface { public: explicit BpComplexTypeInterface(const ::android::sp<::android::IBinder>& _aidl_impl); virtual ~BpComplexTypeInterface() = default; ::android::binder::Status Send(const ::std::unique_ptr<::std::vector>& goes_in, ::std::vector* goes_in_and_out, ::std::vector* goes_out, ::std::vector* _aidl_return) override; ::android::binder::Status Piff(int32_t times) override; ::android::binder::Status TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) override; ::android::binder::Status NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) override; ::android::binder::Status StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) override; ::android::binder::Status BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) override; ::android::binder::Status TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) override; ::android::binder::Status TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) override; }; // class BpComplexTypeInterface } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_BP_COMPLEX_TYPE_INTERFACE_H_ )"; const char kExpectedComplexTypeClientSourceOutput[] = R"(#include #include namespace android { namespace os { BpComplexTypeInterface::BpComplexTypeInterface(const ::android::sp<::android::IBinder>& _aidl_impl) : BpInterface(_aidl_impl){ } ::android::binder::Status BpComplexTypeInterface::Send(const ::std::unique_ptr<::std::vector>& goes_in, ::std::vector* goes_in_and_out, ::std::vector* goes_out, ::std::vector* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeInt32Vector(goes_in); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeDoubleVector(*goes_in_and_out); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeVectorSize(*goes_out); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::SEND, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readInt32Vector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_reply.readDoubleVector(goes_in_and_out); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_reply.readBoolVector(goes_out); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::Piff(int32_t times) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeInt32(times); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::PIFF, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeStrongBinder(::foo::IFooType::asBinder(f)); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESABINDER, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::NULLABLEBINDER, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeString16Vector(input); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::STRINGLISTMETHOD, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readString16Vector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_reply.readString16Vector(output); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeStrongBinderVector(input); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::BINDERLISTMETHOD, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readStrongBinderVector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_reply.readStrongBinderVector(output); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeUniqueFileDescriptor(f); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESAFILEDESCRIPTOR, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readUniqueFileDescriptor(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpComplexTypeInterface::TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeUniqueFileDescriptorVector(f); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IComplexTypeInterface::TAKESAFILEDESCRIPTORARRAY, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readUniqueFileDescriptorVector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } } // namespace os } // namespace android )"; const char kExpectedComplexTypeServerHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_ #define AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_ #include #include namespace android { namespace os { class BnComplexTypeInterface : public ::android::BnInterface { public: ::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags = 0) override; }; // class BnComplexTypeInterface } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_BN_COMPLEX_TYPE_INTERFACE_H_ )"; const char kExpectedComplexTypeServerSourceOutput[] = R"(#include #include namespace android { namespace os { ::android::status_t BnComplexTypeInterface::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) { ::android::status_t _aidl_ret_status = ::android::OK; switch (_aidl_code) { case Call::SEND: { ::std::unique_ptr<::std::vector> in_goes_in; ::std::vector in_goes_in_and_out; ::std::vector out_goes_out; ::std::vector _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readInt32Vector(&in_goes_in); if (((_aidl_ret_status) != (::android::OK))) { break; } _aidl_ret_status = _aidl_data.readDoubleVector(&in_goes_in_and_out); if (((_aidl_ret_status) != (::android::OK))) { break; } _aidl_ret_status = _aidl_data.resizeOutVector(&out_goes_out); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(Send(in_goes_in, &in_goes_in_and_out, &out_goes_out, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeInt32Vector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } _aidl_ret_status = _aidl_reply->writeDoubleVector(in_goes_in_and_out); if (((_aidl_ret_status) != (::android::OK))) { break; } _aidl_ret_status = _aidl_reply->writeBoolVector(out_goes_out); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::PIFF: { int32_t in_times; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readInt32(&in_times); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(Piff(in_times)); } break; case Call::TAKESABINDER: { ::android::sp<::foo::IFooType> in_f; ::android::sp<::foo::IFooType> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readStrongBinder(&in_f); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(TakesABinder(in_f, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeStrongBinder(::foo::IFooType::asBinder(_aidl_return)); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::NULLABLEBINDER: { ::android::sp<::foo::IFooType> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } ::android::binder::Status _aidl_status(NullableBinder(&_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeStrongBinder(::foo::IFooType::asBinder(_aidl_return)); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::STRINGLISTMETHOD: { ::std::vector<::android::String16> in_input; ::std::vector<::android::String16> out_output; ::std::vector<::android::String16> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readString16Vector(&in_input); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(StringListMethod(in_input, &out_output, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeString16Vector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } _aidl_ret_status = _aidl_reply->writeString16Vector(out_output); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::BINDERLISTMETHOD: { ::std::vector<::android::sp<::android::IBinder>> in_input; ::std::vector<::android::sp<::android::IBinder>> out_output; ::std::vector<::android::sp<::android::IBinder>> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readStrongBinderVector(&in_input); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(BinderListMethod(in_input, &out_output, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeStrongBinderVector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } _aidl_ret_status = _aidl_reply->writeStrongBinderVector(out_output); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::TAKESAFILEDESCRIPTOR: { ::android::base::unique_fd in_f; ::android::base::unique_fd _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readUniqueFileDescriptor(&in_f); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(TakesAFileDescriptor(in_f, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeUniqueFileDescriptor(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::TAKESAFILEDESCRIPTORARRAY: { ::std::vector<::android::base::unique_fd> in_f; ::std::vector<::android::base::unique_fd> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readUniqueFileDescriptorVector(&in_f); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(TakesAFileDescriptorArray(in_f, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeUniqueFileDescriptorVector(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; default: { _aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags); } break; } if (_aidl_ret_status == ::android::UNEXPECTED_NULL) { _aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply); } return _aidl_ret_status; } } // namespace os } // namespace android )"; const char kExpectedComplexTypeInterfaceHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_ #define AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_ #include #include #include #include #include #include #include #include #include #include namespace android { namespace os { class IComplexTypeInterface : public ::android::IInterface { public: DECLARE_META_INTERFACE(ComplexTypeInterface) enum : int32_t { MY_CONSTANT = 3, }; virtual ::android::binder::Status Send(const ::std::unique_ptr<::std::vector>& goes_in, ::std::vector* goes_in_and_out, ::std::vector* goes_out, ::std::vector* _aidl_return) = 0; virtual ::android::binder::Status Piff(int32_t times) = 0; virtual ::android::binder::Status TakesABinder(const ::android::sp<::foo::IFooType>& f, ::android::sp<::foo::IFooType>* _aidl_return) = 0; virtual ::android::binder::Status NullableBinder(::android::sp<::foo::IFooType>* _aidl_return) = 0; virtual ::android::binder::Status StringListMethod(const ::std::vector<::android::String16>& input, ::std::vector<::android::String16>* output, ::std::vector<::android::String16>* _aidl_return) = 0; virtual ::android::binder::Status BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>& input, ::std::vector<::android::sp<::android::IBinder>>* output, ::std::vector<::android::sp<::android::IBinder>>* _aidl_return) = 0; virtual ::android::binder::Status TakesAFileDescriptor(const ::android::base::unique_fd& f, ::android::base::unique_fd* _aidl_return) = 0; virtual ::android::binder::Status TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>& f, ::std::vector<::android::base::unique_fd>* _aidl_return) = 0; enum Call { SEND = ::android::IBinder::FIRST_CALL_TRANSACTION + 0, PIFF = ::android::IBinder::FIRST_CALL_TRANSACTION + 1, TAKESABINDER = ::android::IBinder::FIRST_CALL_TRANSACTION + 2, NULLABLEBINDER = ::android::IBinder::FIRST_CALL_TRANSACTION + 3, STRINGLISTMETHOD = ::android::IBinder::FIRST_CALL_TRANSACTION + 4, BINDERLISTMETHOD = ::android::IBinder::FIRST_CALL_TRANSACTION + 5, TAKESAFILEDESCRIPTOR = ::android::IBinder::FIRST_CALL_TRANSACTION + 6, TAKESAFILEDESCRIPTORARRAY = ::android::IBinder::FIRST_CALL_TRANSACTION + 7, }; }; // class IComplexTypeInterface } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_I_COMPLEX_TYPE_INTERFACE_H_ )"; const char kExpectedComplexTypeInterfaceSourceOutput[] = R"(#include #include namespace android { namespace os { IMPLEMENT_META_INTERFACE(ComplexTypeInterface, "android.os.IComplexTypeInterface") } // namespace os } // namespace android )"; } // namespace class ASTTest : public ::testing::Test { protected: ASTTest(string file_path, string file_contents) : file_path_(file_path), file_contents_(file_contents) { types_.Init(); } unique_ptr Parse() { io_delegate_.SetFileContents(file_path_, file_contents_); unique_ptr ret; std::vector> imports; AidlError err = ::android::aidl::internals::load_and_validate_aidl( {}, // no preprocessed files {"."}, file_path_, io_delegate_, &types_, &ret, &imports); if (err != AidlError::OK) return nullptr; return ret; } void Compare(Document* doc, const char* expected) { string output; unique_ptr cw = GetStringWriter(&output); doc->Write(cw.get()); if (expected == output) { return; // Success } test::PrintDiff(expected, output); FAIL() << "Document contents did not match expected contents"; } const string file_path_; const string file_contents_; FakeIoDelegate io_delegate_; TypeNamespace types_; }; class ComplexTypeInterfaceASTTest : public ASTTest { public: ComplexTypeInterfaceASTTest() : ASTTest("android/os/IComplexTypeInterface.aidl", kComplexTypeInterfaceAIDL) { io_delegate_.SetFileContents("foo/IFooType.aidl", "package foo; interface IFooType {}"); } }; TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientHeader) { unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildClientHeader(types_, *interface); Compare(doc.get(), kExpectedComplexTypeClientHeaderOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSource) { unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildClientSource(types_, *interface); Compare(doc.get(), kExpectedComplexTypeClientSourceOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerHeader) { unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildServerHeader(types_, *interface); Compare(doc.get(), kExpectedComplexTypeServerHeaderOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSource) { unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildServerSource(types_, *interface); Compare(doc.get(), kExpectedComplexTypeServerSourceOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceHeader) { unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildInterfaceHeader(types_, *interface); Compare(doc.get(), kExpectedComplexTypeInterfaceHeaderOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceSource) { unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildInterfaceSource(types_, *interface); Compare(doc.get(), kExpectedComplexTypeInterfaceSourceOutput); } namespace test_io_handling { const char kInputPath[] = "a/IFoo.aidl"; const char kOutputPath[] = "output.cpp"; const char kHeaderDir[] = "headers"; const char kInterfaceHeaderRelPath[] = "a/IFoo.h"; } // namespace test_io_handling class IoErrorHandlingTest : public ASTTest { public: IoErrorHandlingTest () : ASTTest(test_io_handling::kInputPath, "package a; interface IFoo {}"), options_(GetOptions()) {} const unique_ptr options_; private: static unique_ptr GetOptions() { using namespace test_io_handling; const int argc = 4; const char* cmdline[argc] = { "aidl-cpp", kInputPath, kHeaderDir, kOutputPath }; return CppOptions::Parse(argc, cmdline); } }; TEST_F(IoErrorHandlingTest, GenerateCorrectlyAbsentErrors) { // Confirm that this is working correctly without I/O problems. const unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); ASSERT_TRUE(GenerateCpp(*options_, types_, *interface, io_delegate_)); } TEST_F(IoErrorHandlingTest, HandlesBadHeaderWrite) { using namespace test_io_handling; const unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); // Simulate issues closing the interface header. const string header_path = StringPrintf("%s%c%s", kHeaderDir, OS_PATH_SEPARATOR, kInterfaceHeaderRelPath); io_delegate_.AddBrokenFilePath(header_path); ASSERT_FALSE(GenerateCpp(*options_, types_, *interface, io_delegate_)); // We should never attempt to write the C++ file if we fail writing headers. ASSERT_FALSE(io_delegate_.GetWrittenContents(kOutputPath, nullptr)); // We should remove partial results. ASSERT_TRUE(io_delegate_.PathWasRemoved(header_path)); } TEST_F(IoErrorHandlingTest, HandlesBadCppWrite) { using test_io_handling::kOutputPath; const unique_ptr interface = Parse(); ASSERT_NE(interface, nullptr); // Simulate issues closing the cpp file. io_delegate_.AddBrokenFilePath(kOutputPath); ASSERT_FALSE(GenerateCpp(*options_, types_, *interface, io_delegate_)); // We should remove partial results. ASSERT_TRUE(io_delegate_.PathWasRemoved(kOutputPath)); } } // namespace cpp } // namespace aidl } // namespace android generate_java.cpp0100644 0000000 0000000 00000003727 13277516055 013130 0ustar000000000 0000000 /* * Copyright (C) 2016, 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 "generate_java.h" #include #include #include #include #include #include "code_writer.h" #include "type_java.h" using std::unique_ptr; using ::android::aidl::java::Variable; using std::string; using android::base::StringPrintf; namespace android { namespace aidl { // ================================================= VariableFactory::VariableFactory(const string& base) : base_(base), index_(0) { } Variable* VariableFactory::Get(const Type* type) { Variable* v = new Variable( type, StringPrintf("%s%d", base_.c_str(), index_)); vars_.push_back(v); index_++; return v; } Variable* VariableFactory::Get(int index) { return vars_[index]; } namespace java { int generate_java(const string& filename, const string& originalSrc, AidlInterface* iface, JavaTypeNamespace* types, const IoDelegate& io_delegate) { Class* cl = generate_binder_interface_class(iface, types); Document* document = new Document( "" /* no comment */, (!iface->GetPackage().empty()) ? iface->GetPackage() : "", originalSrc, unique_ptr(cl)); CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); document->Write(code_writer.get()); return 0; } } // namespace java } // namespace android } // namespace aidl generate_java.h0100644 0000000 0000000 00000003223 13277516055 012564 0ustar000000000 0000000 /* * Copyright (C) 2016, 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 AIDL_GENERATE_JAVA_H_ #define AIDL_GENERATE_JAVA_H_ #include #include "aidl_language.h" #include "ast_java.h" #include "io_delegate.h" namespace android { namespace aidl { namespace java { class JavaTypeNamespace; int generate_java(const std::string& filename, const std::string& originalSrc, AidlInterface* iface, java::JavaTypeNamespace* types, const IoDelegate& io_delegate); android::aidl::java::Class* generate_binder_interface_class( const AidlInterface* iface, java::JavaTypeNamespace* types); } // namespace java class VariableFactory { public: using Variable = ::android::aidl::java::Variable; using Type = ::android::aidl::java::Type; explicit VariableFactory(const std::string& base); // base must be short Variable* Get(const Type* type); Variable* Get(int index); private: std::vector vars_; std::string base_; int index_; DISALLOW_COPY_AND_ASSIGN(VariableFactory); }; } // namespace android } // namespace aidl #endif // AIDL_GENERATE_JAVA_H_ generate_java_binder.cpp0100644 0000000 0000000 00000047465 13277516055 014462 0ustar000000000 0000000 /* * Copyright (C) 2016, 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 "generate_java.h" #include #include #include #include #include #include "type_java.h" using std::string; namespace android { namespace aidl { namespace java { // ================================================= class StubClass : public Class { public: StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types); virtual ~StubClass() = default; Variable* transact_code; Variable* transact_data; Variable* transact_reply; Variable* transact_flags; SwitchStatement* transact_switch; private: void make_as_interface(const InterfaceType* interfaceType, JavaTypeNamespace* types); DISALLOW_COPY_AND_ASSIGN(StubClass); }; StubClass::StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types) : Class() { this->comment = "/** Local-side IPC implementation stub class. */"; this->modifiers = PUBLIC | ABSTRACT | STATIC; this->what = Class::CLASS; this->type = type; this->extends = types->BinderNativeType(); this->interfaces.push_back(interfaceType); // descriptor Field* descriptor = new Field(STATIC | FINAL | PRIVATE, new Variable(types->StringType(), "DESCRIPTOR")); descriptor->value = "\"" + interfaceType->JavaType() + "\""; this->elements.push_back(descriptor); // ctor Method* ctor = new Method; ctor->modifiers = PUBLIC; ctor->comment = "/** Construct the stub at attach it to the " "interface. */"; ctor->name = "Stub"; ctor->statements = new StatementBlock; MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface", 2, THIS_VALUE, new LiteralExpression("DESCRIPTOR")); ctor->statements->Add(attach); this->elements.push_back(ctor); // asInterface make_as_interface(interfaceType, types); // asBinder Method* asBinder = new Method; asBinder->modifiers = PUBLIC | OVERRIDE; asBinder->returnType = types->IBinderType(); asBinder->name = "asBinder"; asBinder->statements = new StatementBlock; asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); this->elements.push_back(asBinder); // onTransact this->transact_code = new Variable(types->IntType(), "code"); this->transact_data = new Variable(types->ParcelType(), "data"); this->transact_reply = new Variable(types->ParcelType(), "reply"); this->transact_flags = new Variable(types->IntType(), "flags"); Method* onTransact = new Method; onTransact->modifiers = PUBLIC | OVERRIDE; onTransact->returnType = types->BoolType(); onTransact->name = "onTransact"; onTransact->parameters.push_back(this->transact_code); onTransact->parameters.push_back(this->transact_data); onTransact->parameters.push_back(this->transact_reply); onTransact->parameters.push_back(this->transact_flags); onTransact->statements = new StatementBlock; onTransact->exceptions.push_back(types->RemoteExceptionType()); this->elements.push_back(onTransact); this->transact_switch = new SwitchStatement(this->transact_code); onTransact->statements->Add(this->transact_switch); MethodCall* superCall = new MethodCall( SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data, this->transact_reply, this->transact_flags); onTransact->statements->Add(new ReturnStatement(superCall)); } void StubClass::make_as_interface(const InterfaceType* interfaceType, JavaTypeNamespace* types) { Variable* obj = new Variable(types->IBinderType(), "obj"); Method* m = new Method; m->comment = "/**\n * Cast an IBinder object into an "; m->comment += interfaceType->JavaType(); m->comment += " interface,\n"; m->comment += " * generating a proxy if needed.\n */"; m->modifiers = PUBLIC | STATIC; m->returnType = interfaceType; m->name = "asInterface"; m->parameters.push_back(obj); m->statements = new StatementBlock; IfStatement* ifstatement = new IfStatement(); ifstatement->expression = new Comparison(obj, "==", NULL_VALUE); ifstatement->statements = new StatementBlock; ifstatement->statements->Add(new ReturnStatement(NULL_VALUE)); m->statements->Add(ifstatement); // IInterface iin = obj.queryLocalInterface(DESCRIPTOR) MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface"); queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR")); IInterfaceType* iinType = new IInterfaceType(types); Variable* iin = new Variable(iinType, "iin"); VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, NULL); m->statements->Add(iinVd); // Ensure the instance type of the local object is as expected. // One scenario where this is needed is if another package (with a // different class loader) runs in the same process as the service. // if (iin != null && iin instanceof ) return () // iin; Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE); Comparison* instOfCheck = new Comparison(iin, " instanceof ", new LiteralExpression(interfaceType->JavaType())); IfStatement* instOfStatement = new IfStatement(); instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck); instOfStatement->statements = new StatementBlock; instOfStatement->statements->Add( new ReturnStatement(new Cast(interfaceType, iin))); m->statements->Add(instOfStatement); NewExpression* ne = new NewExpression(interfaceType->GetProxy()); ne->arguments.push_back(obj); m->statements->Add(new ReturnStatement(ne)); this->elements.push_back(m); } // ================================================= class ProxyClass : public Class { public: ProxyClass(const JavaTypeNamespace* types, const Type* type, const InterfaceType* interfaceType); virtual ~ProxyClass(); Variable* mRemote; bool mOneWay; }; ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type, const InterfaceType* interfaceType) : Class() { this->modifiers = PRIVATE | STATIC; this->what = Class::CLASS; this->type = type; this->interfaces.push_back(interfaceType); mOneWay = interfaceType->OneWay(); // IBinder mRemote mRemote = new Variable(types->IBinderType(), "mRemote"); this->elements.push_back(new Field(PRIVATE, mRemote)); // Proxy() Variable* remote = new Variable(types->IBinderType(), "remote"); Method* ctor = new Method; ctor->name = "Proxy"; ctor->statements = new StatementBlock; ctor->parameters.push_back(remote); ctor->statements->Add(new Assignment(mRemote, remote)); this->elements.push_back(ctor); // IBinder asBinder() Method* asBinder = new Method; asBinder->modifiers = PUBLIC | OVERRIDE; asBinder->returnType = types->IBinderType(); asBinder->name = "asBinder"; asBinder->statements = new StatementBlock; asBinder->statements->Add(new ReturnStatement(mRemote)); this->elements.push_back(asBinder); } ProxyClass::~ProxyClass() {} // ================================================= static void generate_new_array(const Type* t, StatementBlock* addTo, Variable* v, Variable* parcel, JavaTypeNamespace* types) { Variable* len = new Variable(types->IntType(), v->name + "_length"); addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt"))); IfStatement* lencheck = new IfStatement(); lencheck->expression = new Comparison(len, "<", new LiteralExpression("0")); lencheck->statements->Add(new Assignment(v, NULL_VALUE)); lencheck->elseif = new IfStatement(); lencheck->elseif->statements->Add( new Assignment(v, new NewArrayExpression(t, len))); addTo->Add(lencheck); } static void generate_write_to_parcel(const Type* t, StatementBlock* addTo, Variable* v, Variable* parcel, int flags) { t->WriteToParcel(addTo, v, parcel, flags); } static void generate_create_from_parcel(const Type* t, StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) { t->CreateFromParcel(addTo, v, parcel, cl); } static void generate_int_constant(const AidlIntConstant& constant, Class* interface) { IntConstant* decl = new IntConstant(constant.GetName(), constant.GetValue()); interface->elements.push_back(decl); } static void generate_string_constant(const AidlStringConstant& constant, Class* interface) { StringConstant* decl = new StringConstant(constant.GetName(), constant.GetValue()); interface->elements.push_back(decl); } static void generate_method(const AidlMethod& method, Class* interface, StubClass* stubClass, ProxyClass* proxyClass, int index, JavaTypeNamespace* types) { int i; const bool oneway = proxyClass->mOneWay || method.IsOneway(); // == the TRANSACT_ constant ============================================= string transactCodeName = "TRANSACTION_"; transactCodeName += method.GetName(); char transactCodeValue[60]; sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index); Field* transactCode = new Field( STATIC | FINAL, new Variable(types->IntType(), transactCodeName)); transactCode->value = transactCodeValue; stubClass->elements.push_back(transactCode); // == the declaration in the interface =================================== Method* decl = new Method; decl->comment = method.GetComments(); decl->modifiers = PUBLIC; decl->returnType = method.GetType().GetLanguageType(); decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0; decl->name = method.GetName(); for (const std::unique_ptr& arg : method.GetArguments()) { decl->parameters.push_back( new Variable(arg->GetType().GetLanguageType(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0)); } decl->exceptions.push_back(types->RemoteExceptionType()); interface->elements.push_back(decl); // == the stub method ==================================================== Case* c = new Case(transactCodeName); MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName()); // interface token validation is the very first thing we do c->statements->Add(new MethodCall(stubClass->transact_data, "enforceInterface", 1, new LiteralExpression("DESCRIPTOR"))); // args Variable* cl = NULL; VariableFactory stubArgs("_arg"); for (const std::unique_ptr& arg : method.GetArguments()) { const Type* t = arg->GetType().GetLanguageType(); Variable* v = stubArgs.Get(t); v->dimension = arg->GetType().IsArray() ? 1 : 0; c->statements->Add(new VariableDeclaration(v)); if (arg->GetDirection() & AidlArgument::IN_DIR) { generate_create_from_parcel(t, c->statements, v, stubClass->transact_data, &cl); } else { if (!arg->GetType().IsArray()) { c->statements->Add(new Assignment(v, new NewExpression(v->type))); } else { generate_new_array(v->type, c->statements, v, stubClass->transact_data, types); } } realCall->arguments.push_back(v); } cl = NULL; // the real call Variable* _result = NULL; if (method.GetType().GetName() == "void") { c->statements->Add(realCall); if (!oneway) { // report that there were no exceptions MethodCall* ex = new MethodCall(stubClass->transact_reply, "writeNoException", 0); c->statements->Add(ex); } } else { _result = new Variable(decl->returnType, "_result", decl->returnTypeDimension); c->statements->Add(new VariableDeclaration(_result, realCall)); if (!oneway) { // report that there were no exceptions MethodCall* ex = new MethodCall(stubClass->transact_reply, "writeNoException", 0); c->statements->Add(ex); } // marshall the return value generate_write_to_parcel(decl->returnType, c->statements, _result, stubClass->transact_reply, Type::PARCELABLE_WRITE_RETURN_VALUE); } // out parameters i = 0; for (const std::unique_ptr& arg : method.GetArguments()) { const Type* t = arg->GetType().GetLanguageType(); Variable* v = stubArgs.Get(i++); if (arg->GetDirection() & AidlArgument::OUT_DIR) { generate_write_to_parcel(t, c->statements, v, stubClass->transact_reply, Type::PARCELABLE_WRITE_RETURN_VALUE); } } // return true c->statements->Add(new ReturnStatement(TRUE_VALUE)); stubClass->transact_switch->cases.push_back(c); // == the proxy method =================================================== Method* proxy = new Method; proxy->comment = method.GetComments(); proxy->modifiers = PUBLIC | OVERRIDE; proxy->returnType = method.GetType().GetLanguageType(); proxy->returnTypeDimension = method.GetType().IsArray() ? 1 : 0; proxy->name = method.GetName(); proxy->statements = new StatementBlock; for (const std::unique_ptr& arg : method.GetArguments()) { proxy->parameters.push_back( new Variable(arg->GetType().GetLanguageType(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0)); } proxy->exceptions.push_back(types->RemoteExceptionType()); proxyClass->elements.push_back(proxy); // the parcels Variable* _data = new Variable(types->ParcelType(), "_data"); proxy->statements->Add(new VariableDeclaration( _data, new MethodCall(types->ParcelType(), "obtain"))); Variable* _reply = NULL; if (!oneway) { _reply = new Variable(types->ParcelType(), "_reply"); proxy->statements->Add(new VariableDeclaration( _reply, new MethodCall(types->ParcelType(), "obtain"))); } // the return value _result = NULL; if (method.GetType().GetName() != "void") { _result = new Variable(proxy->returnType, "_result", method.GetType().IsArray() ? 1 : 0); proxy->statements->Add(new VariableDeclaration(_result)); } // try and finally TryStatement* tryStatement = new TryStatement(); proxy->statements->Add(tryStatement); FinallyStatement* finallyStatement = new FinallyStatement(); proxy->statements->Add(finallyStatement); // the interface identifier token: the DESCRIPTOR constant, marshalled as a // string tryStatement->statements->Add(new MethodCall( _data, "writeInterfaceToken", 1, new LiteralExpression("DESCRIPTOR"))); // the parameters for (const std::unique_ptr& arg : method.GetArguments()) { const Type* t = arg->GetType().GetLanguageType(); Variable* v = new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0); AidlArgument::Direction dir = arg->GetDirection(); if (dir == AidlArgument::OUT_DIR && arg->GetType().IsArray()) { IfStatement* checklen = new IfStatement(); checklen->expression = new Comparison(v, "==", NULL_VALUE); checklen->statements->Add( new MethodCall(_data, "writeInt", 1, new LiteralExpression("-1"))); checklen->elseif = new IfStatement(); checklen->elseif->statements->Add( new MethodCall(_data, "writeInt", 1, new FieldVariable(v, "length"))); tryStatement->statements->Add(checklen); } else if (dir & AidlArgument::IN_DIR) { generate_write_to_parcel(t, tryStatement->statements, v, _data, 0); } else { delete v; } } // the transact call MethodCall* call = new MethodCall( proxyClass->mRemote, "transact", 4, new LiteralExpression("Stub." + transactCodeName), _data, _reply ? _reply : NULL_VALUE, new LiteralExpression(oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0")); tryStatement->statements->Add(call); // throw back exceptions. if (_reply) { MethodCall* ex = new MethodCall(_reply, "readException", 0); tryStatement->statements->Add(ex); } // returning and cleanup if (_reply != NULL) { if (_result != NULL) { generate_create_from_parcel(proxy->returnType, tryStatement->statements, _result, _reply, &cl); } // the out/inout parameters for (const std::unique_ptr& arg : method.GetArguments()) { const Type* t = arg->GetType().GetLanguageType(); if (arg->GetDirection() & AidlArgument::OUT_DIR) { Variable* v = new Variable(t, arg->GetName(), arg->GetType().IsArray() ? 1 : 0); t->ReadFromParcel(tryStatement->statements, v, _reply, &cl); } } finallyStatement->statements->Add(new MethodCall(_reply, "recycle")); } finallyStatement->statements->Add(new MethodCall(_data, "recycle")); if (_result != NULL) { proxy->statements->Add(new ReturnStatement(_result)); } } static void generate_interface_descriptors(StubClass* stub, ProxyClass* proxy, const JavaTypeNamespace* types) { // the interface descriptor transaction handler Case* c = new Case("INTERFACE_TRANSACTION"); c->statements->Add(new MethodCall(stub->transact_reply, "writeString", 1, new LiteralExpression("DESCRIPTOR"))); c->statements->Add(new ReturnStatement(TRUE_VALUE)); stub->transact_switch->cases.push_back(c); // and the proxy-side method returning the descriptor directly Method* getDesc = new Method; getDesc->modifiers = PUBLIC; getDesc->returnType = types->StringType(); getDesc->returnTypeDimension = 0; getDesc->name = "getInterfaceDescriptor"; getDesc->statements = new StatementBlock; getDesc->statements->Add( new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); proxy->elements.push_back(getDesc); } Class* generate_binder_interface_class(const AidlInterface* iface, JavaTypeNamespace* types) { const InterfaceType* interfaceType = iface->GetLanguageType(); // the interface class Class* interface = new Class; interface->comment = iface->GetComments(); interface->modifiers = PUBLIC; interface->what = Class::INTERFACE; interface->type = interfaceType; interface->interfaces.push_back(types->IInterfaceType()); // the stub inner class StubClass* stub = new StubClass(interfaceType->GetStub(), interfaceType, types); interface->elements.push_back(stub); // the proxy inner class ProxyClass* proxy = new ProxyClass(types, interfaceType->GetProxy(), interfaceType); stub->elements.push_back(proxy); // stub and proxy support for getInterfaceDescriptor() generate_interface_descriptors(stub, proxy, types); // all the declared constants of the interface for (const auto& item : iface->GetIntConstants()) { generate_int_constant(*item, interface); } for (const auto& item : iface->GetStringConstants()) { generate_string_constant(*item, interface); } // all the declared methods of the interface for (const auto& item : iface->GetMethods()) { generate_method(*item, interface, stub, proxy, item->GetId(), types); } return interface; } } // namespace java } // namespace android } // namespace aidl import_resolver.cpp0100644 0000000 0000000 00000003344 13277516055 013563 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "import_resolver.h" #include #ifdef _WIN32 #include #endif #include "os.h" using std::string; using std::vector; namespace android { namespace aidl { ImportResolver::ImportResolver(const IoDelegate& io_delegate, const vector& import_paths) : io_delegate_(io_delegate) { for (string path : import_paths) { if (path.empty()) { path = "."; } if (path[path.size() - 1] != OS_PATH_SEPARATOR) { path += OS_PATH_SEPARATOR; } import_paths_.push_back(std::move(path)); } } string ImportResolver::FindImportFile(const string& canonical_name) const { // Convert the canonical name to a relative file path. string relative_path = canonical_name; for (char& c : relative_path) { if (c == '.') { c = OS_PATH_SEPARATOR; } } relative_path += ".aidl"; // Look for that relative path at each of our import roots. for (string path : import_paths_) { path = path + relative_path; if (io_delegate_.FileIsReadable(path)) { return path; } } return ""; } } // namespace android } // namespace aidl import_resolver.h0100644 0000000 0000000 00000002613 13277516055 013226 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_IMPORT_RESOLVER_H_ #define AIDL_IMPORT_RESOLVER_H_ #include #include #include #include "io_delegate.h" namespace android { namespace aidl { class ImportResolver { public: ImportResolver(const IoDelegate& io_delegate, const std::vector& import_paths); virtual ~ImportResolver() = default; // Resolve the canonical name for a class to a file that exists // in one of the import paths given to the ImportResolver. std::string FindImportFile(const std::string& canonical_name) const; private: const IoDelegate& io_delegate_; std::vector import_paths_; DISALLOW_COPY_AND_ASSIGN(ImportResolver); }; } // namespace android } // namespace aidl #endif // AIDL_IMPORT_RESOLVER_H_ io_delegate.cpp0100644 0000000 0000000 00000011557 13277516055 012576 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "io_delegate.h" #include #include #include #ifdef _WIN32 #include #else #include #include #endif #include #include "logging.h" #include "os.h" using std::string; using std::unique_ptr; using std::vector; using android::base::Split; namespace android { namespace aidl { bool IoDelegate::GetAbsolutePath(const string& path, string* absolute_path) { #ifdef _WIN32 char buf[4096]; DWORD path_len = GetFullPathName(path.c_str(), sizeof(buf), buf, nullptr); if (path_len <= 0 || path_len >= sizeof(buf)) { LOG(ERROR) << "Failed to GetFullPathName(" << path << ")"; return false; } *absolute_path = buf; return true; #else if (path.empty()) { LOG(ERROR) << "Giving up on finding an absolute path to represent the " "empty string."; return false; } if (path[0] == OS_PATH_SEPARATOR) { *absolute_path = path; return true; } char buf[4096]; if (getcwd(buf, sizeof(buf)) == nullptr) { LOG(ERROR) << "Path of current working directory does not fit in " << sizeof(buf) << " bytes"; return false; } *absolute_path = buf; *absolute_path += OS_PATH_SEPARATOR; *absolute_path += path; return true; #endif } unique_ptr IoDelegate::GetFileContents( const string& filename, const string& content_suffix) const { unique_ptr contents; std::ifstream in(filename, std::ios::in | std::ios::binary); if (!in) { return contents; } contents.reset(new string); in.seekg(0, std::ios::end); ssize_t file_size = in.tellg(); contents->resize(file_size + content_suffix.length()); in.seekg(0, std::ios::beg); // Read the file contents into the beginning of the string in.read(&(*contents)[0], file_size); // Drop the suffix in at the end. contents->replace(file_size, content_suffix.length(), content_suffix); in.close(); return contents; } unique_ptr IoDelegate::GetLineReader( const string& file_path) const { return LineReader::ReadFromFile(file_path); } bool IoDelegate::FileIsReadable(const string& path) const { #ifdef _WIN32 // check that the file exists and is not write-only return (0 == _access(path.c_str(), 0)) && // mode 0=exist (0 == _access(path.c_str(), 4)); // mode 4=readable #else return (0 == access(path.c_str(), R_OK)); #endif } bool IoDelegate::CreatedNestedDirs( const string& caller_base_dir, const vector& nested_subdirs) const { string base_dir = caller_base_dir; if (base_dir.empty()) { base_dir = "."; } for (const string& subdir : nested_subdirs) { if (base_dir[base_dir.size() - 1] != OS_PATH_SEPARATOR) { base_dir += OS_PATH_SEPARATOR; } base_dir += subdir; bool success; #ifdef _WIN32 success = _mkdir(base_dir.c_str()) == 0; #else success = mkdir(base_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0; #endif // On darwin when you try to mkdir("/", ...) we get EISDIR. if (!success && (errno != EEXIST && errno != EISDIR)) { LOG(ERROR) << "Error while creating " << base_dir << ": " << strerror(errno); return false; } } return true; } bool IoDelegate::CreatePathForFile(const string& path) const { if (path.empty()) { return true; } string absolute_path; if (!GetAbsolutePath(path, &absolute_path)) { return false; } auto directories = Split(absolute_path, string{1u, OS_PATH_SEPARATOR}); // The "base" directory is just the root of the file system. On Windows, // this will look like "C:\" but on Unix style file systems we get an empty // string after splitting "/foo" with "/" string base = directories[0]; if (base.empty()) { base = "/"; } directories.erase(directories.begin()); // Remove the actual file in question, we're just creating the directory path. directories.pop_back(); return CreatedNestedDirs(base, directories); } unique_ptr IoDelegate::GetCodeWriter( const string& file_path) const { return GetFileWriter(file_path); } void IoDelegate::RemovePath(const std::string& file_path) const { #ifdef _WIN32 _unlink(file_path.c_str()); #else unlink(file_path.c_str()); #endif } } // namespace android } // namespace aidl io_delegate.h0100644 0000000 0000000 00000004212 13277516055 012231 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_IO_DELEGATE_H_ #define AIDL_IO_DELEGATE_H_ #include #include #include #include #include "code_writer.h" #include "line_reader.h" namespace android { namespace aidl { class IoDelegate { public: IoDelegate() = default; virtual ~IoDelegate() = default; // Stores an absolute version of |path| to |*absolute_path|, // possibly prefixing it with the current working directory. // Returns false and does not set |*absolute_path| on error. static bool GetAbsolutePath(const std::string& path, std::string* absolute_path); // Returns a unique_ptr to the contents of |filename|. // Will append the optional |content_suffix| to the returned contents. virtual std::unique_ptr GetFileContents( const std::string& filename, const std::string& content_suffix = "") const; virtual std::unique_ptr GetLineReader( const std::string& file_path) const; virtual bool FileIsReadable(const std::string& path) const; virtual bool CreatedNestedDirs( const std::string& base_dir, const std::vector& nested_subdirs) const; bool CreatePathForFile(const std::string& path) const; virtual std::unique_ptr GetCodeWriter( const std::string& file_path) const; virtual void RemovePath(const std::string& file_path) const; private: DISALLOW_COPY_AND_ASSIGN(IoDelegate); }; // class IoDelegate } // namespace android } // namespace aidl #endif // AIDL_IO_DELEGATE_H_ io_delegate_unittest.cpp0100644 0000000 0000000 00000002725 13277516055 014532 0ustar000000000 0000000 /* * Copyright (C) 2016, 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 #include #include "io_delegate.h" using std::string; namespace android { namespace aidl { TEST(IoDelegateTest, CannotGetAbsolutePathFromEmptyString) { string absolute_path; EXPECT_FALSE(IoDelegate::GetAbsolutePath("", &absolute_path)); EXPECT_TRUE(absolute_path.empty()); } TEST(IoDelegateTest, CurrentlyInfersLinuxAbsolutePath) { string absolute_path; EXPECT_TRUE(IoDelegate::GetAbsolutePath("foo", &absolute_path)); ASSERT_FALSE(absolute_path.empty()); // Should find our desired file at the end of |absolute_path| // But we don't know the prefix, since it's the current working directory EXPECT_TRUE(absolute_path.rfind("/foo") == absolute_path.length() - 4); // Whatever our current working directory, the path is absolute. EXPECT_EQ(absolute_path[0], '/'); } } // namespace android } // namespace aidl line_reader.cpp0100644 0000000 0000000 00000004466 13277516055 012607 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "line_reader.h" #include #include using std::istringstream; using std::ifstream; using std::string; using std::unique_ptr; namespace android { namespace aidl { class FileLineReader : public LineReader { public: FileLineReader() = default; virtual ~FileLineReader() { input_stream_.close(); } bool Init(const std::string& file_path) { input_stream_.open(file_path, ifstream::in | ifstream::binary); return input_stream_.is_open() && input_stream_.good(); } bool ReadLine(string* line) override { if (!input_stream_.good()) { return false; } line->clear(); std::getline(input_stream_, *line); return true; } private: ifstream input_stream_; DISALLOW_COPY_AND_ASSIGN(FileLineReader); }; // class FileLineReader class MemoryLineReader : public LineReader { public: explicit MemoryLineReader(const string& contents) : input_stream_(contents) {} virtual ~MemoryLineReader() = default; bool ReadLine(string* line) override { if (!input_stream_.good()) { return false; } line->clear(); std::getline(input_stream_, *line); return true; } private: istringstream input_stream_; DISALLOW_COPY_AND_ASSIGN(MemoryLineReader); }; // class MemoryLineReader unique_ptr LineReader::ReadFromFile(const string& file_path) { unique_ptr file_reader(new FileLineReader()); unique_ptr ret; if (file_reader->Init(file_path)) { ret.reset(file_reader.release()); } return ret; } unique_ptr LineReader::ReadFromMemory(const string& contents) { return unique_ptr(new MemoryLineReader(contents)); } } // namespace android } // namespace aidl line_reader.h0100644 0000000 0000000 00000002346 13277516055 012247 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_LINE_READER_H_ #define AIDL_LINE_READER_H_ #include #include #include namespace android { namespace aidl { class LineReader { public: LineReader() = default; virtual ~LineReader() = default; virtual bool ReadLine(std::string* line) = 0; static std::unique_ptr ReadFromFile( const std::string& file_path); static std::unique_ptr ReadFromMemory( const std::string& contents); private: DISALLOW_COPY_AND_ASSIGN(LineReader); }; // class LineReader } // namespace android } // namespace aidl #endif // AIDL_LINE_READER_H_ logging.h0100644 0000000 0000000 00000001515 13277516055 011421 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_LOGGING_H_ #define AIDL_LOGGING_H_ // We must include windows.h before android-base/logging.h on Windows. #ifdef _WIN32 #include #endif #include #endif // AIDL_LOGGING_H_ main_cpp.cpp0100644 0000000 0000000 00000002315 13277516055 012113 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include "aidl.h" #include "io_delegate.h" #include "logging.h" #include "options.h" using android::aidl::CppOptions; // aidl is leaky. Turn off LeakSanitizer by default. b/37749857 extern "C" const char *__asan_default_options() { return "detect_leaks=0"; } int main(int argc, char** argv) { android::base::InitLogging(argv); LOG(DEBUG) << "aidl starting"; std::unique_ptr options = CppOptions::Parse(argc, argv); if (!options) { return 1; } android::aidl::IoDelegate io_delegate; return android::aidl::compile_aidl_to_cpp(*options, io_delegate); } main_java.cpp0100644 0000000 0000000 00000002775 13277516055 012264 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include "aidl.h" #include "io_delegate.h" #include "logging.h" #include "options.h" using android::aidl::JavaOptions; // aidl is leaky. Turn off LeakSanitizer by default. b/37749857 extern "C" const char *__asan_default_options() { return "detect_leaks=0"; } int main(int argc, char** argv) { android::base::InitLogging(argv); LOG(DEBUG) << "aidl starting"; std::unique_ptr options = JavaOptions::Parse(argc, argv); if (!options) { return 1; } android::aidl::IoDelegate io_delegate; switch (options->task) { case JavaOptions::COMPILE_AIDL_TO_JAVA: return android::aidl::compile_aidl_to_java(*options, io_delegate); case JavaOptions::PREPROCESS_AIDL: if (android::aidl::preprocess_aidl(*options, io_delegate)) return 0; return 1; } std::cerr << "aidl: internal error" << std::endl; return 1; } options.cpp0100644 0000000 0000000 00000017770 13277516055 012033 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "options.h" #include #include #include #include "logging.h" #include "os.h" using std::cerr; using std::endl; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace { unique_ptr java_usage() { fprintf(stderr, "usage: aidl OPTIONS INPUT [OUTPUT]\n" " aidl --preprocess OUTPUT INPUT...\n" "\n" "OPTIONS:\n" " -I search path for import statements.\n" " -d generate dependency file.\n" " -a generate dependency file next to the output file with " "the name based on the input file.\n" " -ninja generate dependency file in a format ninja " "understands.\n" " -p file created by --preprocess to import.\n" " -o base output folder for generated files.\n" " -b fail when trying to compile a parcelable.\n" "\n" "INPUT:\n" " An aidl interface file.\n" "\n" "OUTPUT:\n" " The generated interface files.\n" " If omitted and the -o option is not used, the input filename is " "used, with the .aidl extension changed to a .java extension.\n" " If the -o option is used, the generated files will be placed in " "the base output folder, under their package folder\n"); return unique_ptr(nullptr); } } // namespace unique_ptr JavaOptions::Parse(int argc, const char* const* argv) { unique_ptr options(new JavaOptions()); int i = 1; if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) { if (argc < 4) { return java_usage(); } options->output_file_name_ = argv[2]; for (int i = 3; i < argc; i++) { options->files_to_preprocess_.push_back(argv[i]); } options->task = PREPROCESS_AIDL; return options; } options->task = COMPILE_AIDL_TO_JAVA; // OPTIONS while (i < argc) { const char* s = argv[i]; const size_t len = strlen(s); if (s[0] != '-') { break; } if (len <= 1) { fprintf(stderr, "unknown option (%d): %s\n", i, s); return java_usage(); } // -I if (s[1] == 'I') { if (len > 2) { options->import_paths_.push_back(s + 2); } else { fprintf(stderr, "-I option (%d) requires a path.\n", i); return java_usage(); } } else if (s[1] == 'd') { if (len > 2) { options->dep_file_name_ = s + 2; } else { fprintf(stderr, "-d option (%d) requires a file.\n", i); return java_usage(); } } else if (strcmp(s, "-a") == 0) { options->auto_dep_file_ = true; } else if (s[1] == 'p') { if (len > 2) { options->preprocessed_files_.push_back(s + 2); } else { fprintf(stderr, "-p option (%d) requires a file.\n", i); return java_usage(); } } else if (s[1] == 'o') { if (len > 2) { options->output_base_folder_= s + 2; } else { fprintf(stderr, "-o option (%d) requires a path.\n", i); return java_usage(); } } else if (strcmp(s, "-b") == 0) { options->fail_on_parcelable_ = true; } else if (strcmp(s, "-ninja") == 0) { options->dep_file_ninja_ = true; } else { // s[1] is not known fprintf(stderr, "unknown option (%d): %s\n", i, s); return java_usage(); } i++; } // INPUT if (i < argc) { options->input_file_name_ = argv[i]; i++; } else { fprintf(stderr, "INPUT required\n"); return java_usage(); } if (!EndsWith(options->input_file_name_, ".aidl")) { cerr << "Expected .aidl file for input but got " << options->input_file_name_ << endl; return java_usage(); } // OUTPUT if (i < argc) { options->output_file_name_ = argv[i]; i++; } else if (options->output_base_folder_.empty()) { // copy input into output and change the extension from .aidl to .java options->output_file_name_= options->input_file_name_; if (!ReplaceSuffix(".aidl", ".java", &options->output_file_name_)) { // we should never get here since we validated the suffix. LOG(FATAL) << "Internal aidl error."; return java_usage(); } } // anything remaining? if (i != argc) { fprintf(stderr, "unknown option%s:", (i == argc - 1 ? (const char*)"" : (const char*)"s")); for (; i < argc - 1; i++) { fprintf(stderr, " %s", argv[i]); } fprintf(stderr, "\n"); return java_usage(); } return options; } string JavaOptions::DependencyFilePath() const { if (auto_dep_file_) { return output_file_name_ + ".d"; } return dep_file_name_; } namespace { unique_ptr cpp_usage() { cerr << "usage: aidl-cpp INPUT_FILE HEADER_DIR OUTPUT_FILE" << endl << endl << "OPTIONS:" << endl << " -I search path for import statements" << endl << " -d generate dependency file" << endl << " -ninja generate dependency file in a format ninja " "understands" << endl << endl << "INPUT_FILE:" << endl << " an aidl interface file" << endl << "HEADER_DIR:" << endl << " empty directory to put generated headers" << endl << "OUTPUT_FILE:" << endl << " path to write generated .cpp code" << endl; return unique_ptr(nullptr); } } // namespace unique_ptr CppOptions::Parse(int argc, const char* const* argv) { unique_ptr options(new CppOptions()); int i = 1; // Parse flags, all of which start with '-' for ( ; i < argc; ++i) { const size_t len = strlen(argv[i]); const char *s = argv[i]; if (s[0] != '-') { break; // On to the positional arguments. } if (len < 2) { cerr << "Invalid argument '" << s << "'." << endl; return cpp_usage(); } const string the_rest = s + 2; if (s[1] == 'I') { options->import_paths_.push_back(the_rest); } else if (s[1] == 'd') { options->dep_file_name_ = the_rest; } else if (strcmp(s, "-ninja") == 0) { options->dep_file_ninja_ = true; } else { cerr << "Invalid argument '" << s << "'." << endl; return cpp_usage(); } } // There are exactly three positional arguments. const int remaining_args = argc - i; if (remaining_args != 3) { cerr << "Expected 3 positional arguments but got " << remaining_args << "." << endl; return cpp_usage(); } options->input_file_name_ = argv[i]; options->output_header_dir_ = argv[i + 1]; options->output_file_name_ = argv[i + 2]; if (!EndsWith(options->input_file_name_, ".aidl")) { cerr << "Expected .aidl file for input but got " << options->input_file_name_ << endl; return cpp_usage(); } return options; } bool EndsWith(const string& str, const string& suffix) { if (str.length() < suffix.length()) { return false; } return std::equal(str.crbegin(), str.crbegin() + suffix.length(), suffix.crbegin()); } bool ReplaceSuffix(const string& old_suffix, const string& new_suffix, string* str) { if (!EndsWith(*str, old_suffix)) return false; str->replace(str->length() - old_suffix.length(), old_suffix.length(), new_suffix); return true; } } // namespace android } // namespace aidl options.h0100644 0000000 0000000 00000006712 13277516055 011472 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_OPTIONS_H_ #define AIDL_OPTIONS_H_ #include #include #include #include #include namespace android { namespace aidl { // This object represents the parsed options to the Java generating aidl. class JavaOptions final { public: enum { COMPILE_AIDL_TO_JAVA, PREPROCESS_AIDL, }; ~JavaOptions() = default; // Parses the command line and returns a non-null pointer to an JavaOptions // object on success. // Prints the usage statement on failure. static std::unique_ptr Parse(int argc, const char* const* argv); std::string DependencyFilePath() const; bool DependencyFileNinja() const { return dep_file_ninja_; } int task{COMPILE_AIDL_TO_JAVA}; bool fail_on_parcelable_{false}; std::vector import_paths_; std::vector preprocessed_files_; std::string input_file_name_; std::string output_file_name_; std::string output_base_folder_; std::string dep_file_name_; bool auto_dep_file_{false}; bool dep_file_ninja_{false}; std::vector files_to_preprocess_; private: JavaOptions() = default; FRIEND_TEST(EndToEndTest, IExampleInterface); FRIEND_TEST(AidlTest, FailOnParcelable); FRIEND_TEST(AidlTest, WritePreprocessedFile); FRIEND_TEST(AidlTest, WritesCorrectDependencyFile); FRIEND_TEST(AidlTest, WritesCorrectDependencyFileNinja); FRIEND_TEST(AidlTest, WritesTrivialDependencyFileForParcelable); DISALLOW_COPY_AND_ASSIGN(JavaOptions); }; class CppOptions final { public: ~CppOptions() = default; // Parses the command line and returns a non-null pointer to an CppOptions // object on success. // Prints the usage statement on failure. static std::unique_ptr Parse(int argc, const char* const* argv); std::string InputFileName() const { return input_file_name_; } std::string OutputHeaderDir() const { return output_header_dir_; } std::string OutputCppFilePath() const { return output_file_name_; } std::vector ImportPaths() const { return import_paths_; } std::string DependencyFilePath() const { return dep_file_name_; } bool DependencyFileNinja() const { return dep_file_ninja_; } private: CppOptions() = default; std::string input_file_name_; std::vector import_paths_; std::string output_header_dir_; std::string output_file_name_; std::string dep_file_name_; bool dep_file_ninja_{false}; FRIEND_TEST(CppOptionsTests, ParsesCompileCpp); FRIEND_TEST(CppOptionsTests, ParsesCompileCppNinja); DISALLOW_COPY_AND_ASSIGN(CppOptions); }; bool EndsWith(const std::string& str, const std::string& suffix); bool ReplaceSuffix(const std::string& old_suffix, const std::string& new_suffix, std::string* str); } // namespace android } // namespace aidl #endif // AIDL_OPTIONS_H_ options_unittest.cpp0100644 0000000 0000000 00000015521 13277516055 013762 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include #include #include "options.h" using std::cerr; using std::endl; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace { const char kPreprocessCommandOutputFile[] = "output_file_name"; const char kPreprocessCommandInput1[] = "input1"; const char kPreprocessCommandInput2[] = "input2"; const char kPreprocessCommandInput3[] = "input3"; const char* kPreprocessCommand[] = { "aidl", "--preprocess", kPreprocessCommandOutputFile, kPreprocessCommandInput1, kPreprocessCommandInput2, kPreprocessCommandInput3, nullptr, }; const char kCompileCommandInput[] = "directory/ITool.aidl"; const char kCompileCommandIncludePath[] = "-Iinclude_path"; const char* kCompileJavaCommand[] = { "aidl", "-b", kCompileCommandIncludePath, kCompileCommandInput, nullptr, }; const char kCompileCommandJavaOutput[] = "directory/ITool.java"; const char kCompileDepFileNinja[] = "-ninja"; const char* kCompileJavaCommandNinja[] = { "aidl", "-b", kCompileDepFileNinja, kCompileCommandIncludePath, kCompileCommandInput, nullptr, }; const char kCompileDepFile[] = "-doutput.deps"; const char kCompileCommandHeaderDir[] = "output/dir"; const char kCompileCommandCppOutput[] = "some/file.cpp"; const char* kCompileCppCommand[] = { "aidl-cpp", kCompileCommandIncludePath, kCompileDepFile, kCompileCommandInput, kCompileCommandHeaderDir, kCompileCommandCppOutput, nullptr, }; const char* kCompileCppCommandNinja[] = { "aidl-cpp", kCompileCommandIncludePath, kCompileDepFile, kCompileDepFileNinja, kCompileCommandInput, kCompileCommandHeaderDir, kCompileCommandCppOutput, nullptr, }; template unique_ptr GetOptions(const char* command[]) { int argc = 0; const char** command_part = command; for (; *command_part; ++argc, ++command_part) {} unique_ptr options(T::Parse(argc, command)); if (!options) { cerr << "Failed to parse command line:"; for (int i = 0; i < argc; ++i) { cerr << " " << command[i]; cerr << endl; } } EXPECT_NE(options, nullptr) << "Failed to parse options!"; return options; } } // namespace TEST(JavaOptionsTests, ParsesPreprocess) { unique_ptr options = GetOptions(kPreprocessCommand); EXPECT_EQ(JavaOptions::PREPROCESS_AIDL, options->task); EXPECT_EQ(false, options->fail_on_parcelable_); EXPECT_EQ(0u, options->import_paths_.size()); EXPECT_EQ(0u, options->preprocessed_files_.size()); EXPECT_EQ(string{}, options->input_file_name_); EXPECT_EQ(string{kPreprocessCommandOutputFile}, options->output_file_name_); EXPECT_EQ(false, options->auto_dep_file_); const vector expected_input{kPreprocessCommandInput1, kPreprocessCommandInput2, kPreprocessCommandInput3}; EXPECT_EQ(expected_input, options->files_to_preprocess_); } TEST(JavaOptionsTests, ParsesCompileJava) { unique_ptr options = GetOptions(kCompileJavaCommand); EXPECT_EQ(JavaOptions::COMPILE_AIDL_TO_JAVA, options->task); EXPECT_EQ(true, options->fail_on_parcelable_); EXPECT_EQ(1u, options->import_paths_.size()); EXPECT_EQ(0u, options->preprocessed_files_.size()); EXPECT_EQ(string{kCompileCommandInput}, options->input_file_name_); EXPECT_EQ(string{kCompileCommandJavaOutput}, options->output_file_name_); EXPECT_EQ(false, options->auto_dep_file_); EXPECT_EQ(false, options->DependencyFileNinja()); } TEST(JavaOptionsTests, ParsesCompileJavaNinja) { unique_ptr options = GetOptions(kCompileJavaCommandNinja); EXPECT_EQ(JavaOptions::COMPILE_AIDL_TO_JAVA, options->task); EXPECT_EQ(true, options->fail_on_parcelable_); EXPECT_EQ(1u, options->import_paths_.size()); EXPECT_EQ(0u, options->preprocessed_files_.size()); EXPECT_EQ(string{kCompileCommandInput}, options->input_file_name_); EXPECT_EQ(string{kCompileCommandJavaOutput}, options->output_file_name_); EXPECT_EQ(false, options->auto_dep_file_); EXPECT_EQ(true, options->DependencyFileNinja()); } TEST(CppOptionsTests, ParsesCompileCpp) { unique_ptr options = GetOptions(kCompileCppCommand); ASSERT_EQ(1u, options->import_paths_.size()); EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2), options->import_paths_[0]); EXPECT_EQ(string{kCompileDepFile}.substr(2), options->dep_file_name_); EXPECT_EQ(false, options->DependencyFileNinja()); EXPECT_EQ(kCompileCommandInput, options->InputFileName()); EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir()); EXPECT_EQ(kCompileCommandCppOutput, options->OutputCppFilePath()); } TEST(CppOptionsTests, ParsesCompileCppNinja) { unique_ptr options = GetOptions(kCompileCppCommandNinja); ASSERT_EQ(1u, options->import_paths_.size()); EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2), options->import_paths_[0]); EXPECT_EQ(string{kCompileDepFile}.substr(2), options->dep_file_name_); EXPECT_EQ(true, options->DependencyFileNinja()); EXPECT_EQ(kCompileCommandInput, options->InputFileName()); EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir()); EXPECT_EQ(kCompileCommandCppOutput, options->OutputCppFilePath()); } TEST(OptionsTests, EndsWith) { EXPECT_TRUE(EndsWith("foo", "")); EXPECT_TRUE(EndsWith("foo", "o")); EXPECT_TRUE(EndsWith("foo", "foo")); EXPECT_FALSE(EndsWith("foo", "fooo")); EXPECT_FALSE(EndsWith("", "o")); EXPECT_TRUE(EndsWith("", "")); } TEST(OptionsTests, ReplaceSuffix) { struct test_case_t { const char* input; const char* old_suffix; const char* new_suffix; const char* result; }; const size_t kNumCases = 3; test_case_t kTestInput[kNumCases] = { {"foo.bar", "bar", "foo", "foo.foo"}, {"whole", "whole", "new", "new"}, {"", "", "", ""}, }; for (const auto& test_case : kTestInput) { string mutated = test_case.input; EXPECT_TRUE(ReplaceSuffix(test_case.old_suffix, test_case.new_suffix, &mutated)); EXPECT_EQ(mutated, test_case.result); } } } // namespace android } // namespace aidl os.h0100644 0000000 0000000 00000001405 13277516055 010412 0ustar000000000 0000000 /* * Copyright 2015, 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 AIDL_OS_H_ #define AIDL_OS_H_ #if defined(_WIN32) #define OS_PATH_SEPARATOR '\\' #else #define OS_PATH_SEPARATOR '/' #endif #endif // AIDL_OS_H_ runtests.sh0100755 0000000 0000000 00000002527 13277516055 012054 0ustar000000000 0000000 #!/usr/bin/env bash # Copyright (C) 2016 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. if [ -z $ANDROID_BUILD_TOP ]; then echo "You need to source and lunch before you can use this script" exit 1 fi echo "Running tests" set -e # fail early # NOTE We can't actually run these commands, since they rely on functions added # by build/envsetup.sh to the bash shell environment. echo "+ mmma -j32 $ANDROID_BUILD_TOP/system/tools/aidl" make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \ MODULES-IN-system-tools-aidl set -x # print commands ${ANDROID_HOST_OUT}/nativetest64/aidl_unittests/aidl_unittests adb root adb wait-for-device adb remount adb sync adb install -r \ ${ANDROID_PRODUCT_OUT}/system/app/aidl_test_services/aidl_test_services.apk ${ANDROID_BUILD_TOP}/system/tools/aidl/tests/integration-test.py tests/0040755 0000000 0000000 00000000000 13277516055 010765 5ustar000000000 0000000 tests/aidl_test_client.cpp0100644 0000000 0000000 00000006042 13277516055 014776 0ustar000000000 0000000 /* * Copyright (C) 2015 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 #include #include #include #include #include "android/aidl/tests/ITestService.h" #include "aidl_test_client_file_descriptors.h" #include "aidl_test_client_nullables.h" #include "aidl_test_client_parcelables.h" #include "aidl_test_client_primitives.h" #include "aidl_test_client_service_exceptions.h" #include "aidl_test_client_utf8_strings.h" // libutils: using android::OK; using android::sp; using android::status_t; using android::String16; // libbinder: using android::getService; // generated using android::aidl::tests::ITestService; using std::cerr; using std::cout; using std::endl; namespace android { namespace aidl { namespace tests { namespace client { const char kServiceName[] = "android.aidl.tests.ITestService"; bool GetService(sp* service) { cout << "Retrieving test service binder" << endl; status_t status = getService(String16(kServiceName), service); if (status != OK) { cerr << "Failed to get service binder: '" << kServiceName << "' status=" << status << endl; return false; } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android /* Runs all the test cases in aidl_test_client_*.cpp files. */ int main(int /* argc */, char * argv []) { android::base::InitLogging(argv, android::base::StderrLogger); sp service; namespace client_tests = android::aidl::tests::client; if (!client_tests::GetService(&service)) return 1; if (!client_tests::ConfirmPrimitiveRepeat(service)) return 1; if (!client_tests::ConfirmReverseArrays(service)) return 1; if (!client_tests::ConfirmReverseLists(service)) return 1; if (!client_tests::ConfirmReverseBinderLists(service)) return 1; if (!client_tests::ConfirmSimpleParcelables(service)) return 1; if (!client_tests::ConfirmPersistableBundles(service)) return 1; if (!client_tests::ConfirmFileDescriptors(service)) return 1; if (!client_tests::ConfirmFileDescriptorArrays(service)) return 1; if (!client_tests::ConfirmServiceSpecificExceptions(service)) return 1; if (!client_tests::ConfirmNullables(service)) return 1; if (!client_tests::ConfirmUtf8InCppStringRepeat(service)) return 1; if (!client_tests::ConfirmUtf8InCppStringArrayReverse(service)) return 1; if (!client_tests::ConfirmUtf8InCppStringListReverse(service)) return 1; return 0; } tests/aidl_test_client_file_descriptors.cpp0100644 0000000 0000000 00000007757 13277516055 020434 0ustar000000000 0000000 /* * Copyright (C) 2015 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 "aidl_test_client_file_descriptors.h" #include #include #include #include #include #include // libbase using android::base::unique_fd; // libutils: using android::sp; // libbinder: using android::binder::Status; // generated using android::aidl::tests::ITestService; using std::cerr; using std::cout; using std::endl; using std::string; using std::vector; namespace android { namespace aidl { namespace tests { namespace client { #define FdByName(_fd) #_fd, _fd bool DoWrite(const string& name, const unique_fd& fd, const string& buf) { int wrote; while ((wrote = write(fd.get(), buf.data(), buf.size())) < 0 && errno == EINTR); if (wrote == (signed)buf.size()) { return true; } if (wrote < 0) { cerr << "Error writing to file descriptor '" << name << "': " << strerror(errno) << endl; } else { cerr << "File descriptor '" << name << "'accepted short data." << endl; } return false; } bool DoRead(const string& name, const unique_fd& fd, const string& expected) { size_t length = expected.size(); int got; string buf; buf.resize(length); while ((got = read(fd.get(), &buf[0], length)) < 0 && errno == EINTR); if (got < 0) { cerr << "Error reading from '" << name << "': " << strerror(errno) << endl; return false; } if (buf != expected) { cerr << "Expected '" << expected << "' got '" << buf << "'" << endl; return false; } return true; } bool DoPipe(unique_fd* read_side, unique_fd* write_side) { int fds[2]; unique_fd return_fd; if (pipe(fds)) { cout << "Error creating pipes: " << strerror(errno) << endl; return false; } read_side->reset(fds[0]); write_side->reset(fds[1]); return true; } bool ConfirmFileDescriptors(const sp& s) { Status status; cout << "Confirming passing and returning file descriptors works." << endl; unique_fd return_fd; unique_fd read_fd; unique_fd write_fd; if (!DoPipe(&read_fd, &write_fd)) { return false; } status = s->RepeatFileDescriptor(write_fd, &return_fd); if (!status.isOk()) { cerr << "Could not repeat file descriptors." << endl; return false; } /* A note on some of the spookier stuff going on here: IIUC writes to pipes * should be atomic and non-blocking so long as the total size doesn't exceed * PIPE_BUF. We thus play a bit fast and loose with failure modes here. */ bool ret = DoWrite(FdByName(return_fd), "ReturnString") && DoRead(FdByName(read_fd), "ReturnString"); return ret; } bool ConfirmFileDescriptorArrays(const sp& s) { Status status; cout << "Confirming passing and returning file descriptor arrays works." << endl; vector array; array.resize(2); if (!DoPipe(&array[0], &array[1])) { return false; } vector repeated; vector reversed; status = s->ReverseFileDescriptorArray(array, &repeated, &reversed); if (!status.isOk()) { cerr << "Could not reverse file descriptor array." << endl; return false; } bool ret = DoWrite(FdByName(array[1]), "First") && DoWrite(FdByName(repeated[1]), "Second") && DoWrite(FdByName(reversed[0]), "Third") && DoRead(FdByName(reversed[1]), "FirstSecondThird"); return ret; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_file_descriptors.h0100644 0000000 0000000 00000002261 13277516055 020062 0ustar000000000 0000000 /* * Copyright (C) 2015 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_AIDL_TESTS_CLIENT_FILE_DESCRIPTORS_H #define ANDROID_AIDL_TESTS_CLIENT_FILE_DESCRIPTORS_H #include #include "android/aidl/tests/ITestService.h" // Tests for passing and returning file descriptors. namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmFileDescriptors(const sp& s); bool ConfirmFileDescriptorArrays(const sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_FILE_DESCRIPTORS_H tests/aidl_test_client_nullables.cpp0100644 0000000 0000000 00000016775 13277516055 017055 0ustar000000000 0000000 /* * Copyright (C) 2015 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 "aidl_test_client_nullables.h" #include #include #include #include #include // libutils: using android::sp; using android::String16; // libbinder: using android::binder::Status; // generated using android::aidl::tests::ITestService; using android::aidl::tests::SimpleParcelable; using std::string; using std::unique_ptr; using std::vector; using std::cout; using std::cerr; using std::endl; namespace android { namespace aidl { namespace tests { namespace client { namespace { template bool ValuesEqual(const unique_ptr& in, const unique_ptr& out) { return *in == *out; } template<> bool ValuesEqual>>( const unique_ptr>>& in, const unique_ptr>>& out) { if (!in) { return !out; } if (!out) { return false; } if (in->size() != out->size()) { return false; } for (size_t i = 0; i < in->size(); i++) { const unique_ptr& a = (*in)[i]; const unique_ptr& b = (*out)[i]; if (!(a || b)) { continue; } if (!(a && b)) { return false; } if (*a != *b) { return false; } } return true; } template bool ConfirmNullableType(const sp& s, const string& type_name, unique_ptr in, Status(ITestService::*func)(const unique_ptr&, unique_ptr*)) { cout << "... Confirming nullables for " << type_name << " ..." << endl; Status status; unique_ptr out; status = (*s.*func)(in, &out); if (!status.isOk()) { cerr << "Could not repeat nullable " << type_name << "." << endl; return false; } if (!out) { cerr << "Got back null when repeating " << type_name << "." << endl; return false; } if (!ValuesEqual(in, out)) { cerr << "Got back a non-matching value when repeating " << type_name << "." << endl; return false; } in.reset(); status = (*s.*func)(in, &out); if (!status.isOk()) { cerr << "Could not repeat null as " << type_name << "." << endl; return false; } if (out) { cerr << "Got back a value when sent null for " << type_name << "." << endl; return false; } return true; } bool CheckAppropriateIBinderHandling(const sp& s) { Status status; sp binder = new BBinder(); sp null_binder = nullptr; unique_ptr>> list_with_nulls( new vector>{binder, null_binder}); unique_ptr>> list_without_nulls( new vector>{binder, binder}); // Methods without @nullable throw up when given null binders if (s->TakesAnIBinder(null_binder).exceptionCode() != binder::Status::EX_NULL_POINTER) { cerr << "Did not receive expected null exception on line: " << __LINE__ << endl; return false; } if (s->TakesAnIBinderList(*list_with_nulls).exceptionCode() != binder::Status::EX_NULL_POINTER) { cerr << "Did not receive expected null exception on line: " << __LINE__ << endl; return false; } // But those same methods are fine with valid binders if (!s->TakesAnIBinder(binder).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } if (!s->TakesAnIBinderList(*list_without_nulls).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } // And methods with @nullable don't care. if (!s->TakesANullableIBinder(null_binder).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } if (!s->TakesANullableIBinder(binder).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } if (!s->TakesANullableIBinderList(list_with_nulls).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } if (!s->TakesANullableIBinderList(list_without_nulls).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } return true; } bool CheckAppropriateIInterfaceHandling(const sp& s) { sp callback; if (!s->GetCallback(false, &callback).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } if (callback.get() == nullptr) { cerr << "Expected to receive a non-null binder on line: " << __LINE__ << endl; return false; } if (!s->GetCallback(true, &callback).isOk()) { cerr << "Received unexpected exception on line " << __LINE__ << endl; return false; } if (callback.get() != nullptr) { cerr << "Expected to receive a null binder on line: " << __LINE__ << endl; return false; } return true; } } // namespace bool ConfirmNullables(const sp& s) { Status status; cout << "Confirming passing and returning nullable values works." << endl; if (!ConfirmNullableType(s, "integer array", unique_ptr>( new vector({1,2,3})), &ITestService::RepeatNullableIntArray)) { return false; } if (!ConfirmNullableType(s, "string", unique_ptr(new String16("Blooob")), &ITestService::RepeatNullableString)) { return false; } unique_ptr>> test_string_array( new vector>()); test_string_array->push_back(unique_ptr(new String16("Wat"))); test_string_array->push_back(unique_ptr( new String16("Blooob"))); test_string_array->push_back(unique_ptr(new String16("Wat"))); test_string_array->push_back(unique_ptr(nullptr)); test_string_array->push_back(unique_ptr(new String16("YEAH"))); test_string_array->push_back(unique_ptr( new String16("OKAAAAY"))); if (!ConfirmNullableType(s, "string array", std::move(test_string_array), &ITestService::RepeatNullableStringList)) { return false; } if (!ConfirmNullableType(s, "parcelable", unique_ptr( new SimpleParcelable("Booya", 42)), &ITestService::RepeatNullableParcelable)) { return false; } if (!CheckAppropriateIBinderHandling(s)) { cerr << "Handled null IBinders poorly." << endl; return false; } if (!CheckAppropriateIInterfaceHandling(s)) { cerr << "Handled nullable IInterface instances poorly." << endl; return false; } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_nullables.h0100644 0000000 0000000 00000002131 13277516055 016477 0ustar000000000 0000000 /* * Copyright (C) 2015 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_AIDL_TESTS_CLIENT_NULLABLES_H #define ANDROID_AIDL_TESTS_CLIENT_NULLABLES_H #include #include "android/aidl/tests/ITestService.h" // Tests for passing and returning file descriptors. namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmNullables(const sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_NULLABLES_H tests/aidl_test_client_parcelables.cpp0100644 0000000 0000000 00000012124 13277516055 017331 0ustar000000000 0000000 /* * Copyright (C) 2015 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 "aidl_test_client_parcelables.h" #include #include // libutils: using android::sp; // libbinder: using android::binder::Status; // generated using android::aidl::tests::ITestService; using android::aidl::tests::SimpleParcelable; using android::os::PersistableBundle; using std::cout; using std::endl; using std::vector; namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmSimpleParcelables(const sp& s) { cout << "Confirming passing and returning SimpleParcelable objects works." << endl; SimpleParcelable input("Booya", 42); SimpleParcelable out_param, returned; Status status = s->RepeatSimpleParcelable(input, &out_param, &returned); if (!status.isOk()) { cout << "Binder call failed." << endl; return false; } if (input != out_param || input != returned) { cout << "Failed to repeat SimpleParcelable objects." << endl; return false; } cout << "Attempting to reverse an array of SimpleParcelable objects." << endl; const vector original{SimpleParcelable("first", 0), SimpleParcelable("second", 1), SimpleParcelable("third", 2)}; vector repeated; vector reversed; status = s->ReverseSimpleParcelables(original, &repeated, &reversed); if (!status.isOk()) { cout << "Binder call failed." << endl; return false; } std::reverse(reversed.begin(), reversed.end()); if (repeated != original || reversed != original) { cout << "Failed to reverse an array of SimpleParcelable objects." << endl; return false; } return true; } bool ConfirmPersistableBundles(const sp& s) { cout << "Confirming passing and returning PersistableBundle objects works." << endl; PersistableBundle empty_bundle, returned; Status status = s->RepeatPersistableBundle(empty_bundle, &returned); if (!status.isOk()) { cout << "Binder call failed for empty PersistableBundle." << endl; return false; } if (empty_bundle != returned) { cout << "Failed to repeat empty PersistableBundle." << endl; return false; } PersistableBundle non_empty_bundle; non_empty_bundle.putBoolean(String16("test_bool"), false); non_empty_bundle.putInt(String16("test_int"), 33); non_empty_bundle.putLong(String16("test_long"), 34359738368l); non_empty_bundle.putDouble(String16("test_double"), 1.1); non_empty_bundle.putString(String16("test_string"), String16("Woot!")); non_empty_bundle.putBooleanVector(String16("test_bool_vector"), {true, false, true}); non_empty_bundle.putIntVector(String16("test_int_vector"), {33, 44, 55, 142}); non_empty_bundle.putLongVector(String16("test_long_vector"), {34l, 8371l, 34359738375l}); non_empty_bundle.putDoubleVector(String16("test_double_vector"), {2.2, 5.4}); non_empty_bundle.putStringVector(String16("test_string_vector"), {String16("hello"), String16("world!")}); PersistableBundle nested_bundle; nested_bundle.putInt(String16("test_nested_int"), 345); non_empty_bundle.putPersistableBundle(String16("test_persistable_bundle"), nested_bundle); status = s->RepeatPersistableBundle(non_empty_bundle, &returned); if (!status.isOk()) { cout << "Binder call failed. " << endl; return false; } if (non_empty_bundle != returned) { cout << "Failed to repeat PersistableBundle object." << endl; return false; } cout << "Attempting to reverse an array of PersistableBundle objects." << endl; PersistableBundle first; PersistableBundle second; PersistableBundle third; first.putInt(String16("test_int"), 1231); second.putLong(String16("test_long"), 222222l); third.putDouble(String16("test_double"), 10.8); const vector original{first, second, third}; vector repeated; vector reversed; status = s->ReversePersistableBundles(original, &repeated, &reversed); if (!status.isOk()) { cout << "Binder call failed." << endl; return false; } std::reverse(reversed.begin(), reversed.end()); if (repeated != original || reversed != original) { cout << "Failed to reverse an array of PersistableBundle objects." << endl; return false; } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_parcelables.h0100644 0000000 0000000 00000002242 13277516055 016776 0ustar000000000 0000000 /* * Copyright (C) 2015 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_AIDL_TESTS_CLIENT_PARCELABLES_H #define ANDROID_AIDL_TESTS_CLIENT_PARCELABLES_H #include #include "android/aidl/tests/ITestService.h" // Tests for passing and returning parcelable types. namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmSimpleParcelables(const sp& s); bool ConfirmPersistableBundles(const sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_PARCELABLES_H tests/aidl_test_client_primitives.cpp0100644 0000000 0000000 00000016511 13277516055 017253 0ustar000000000 0000000 /* * Copyright (C) 2015 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 "aidl_test_client_primitives.h" #include #include #include #include #include #include #include "android/aidl/tests/INamedCallback.h" #include "test_helpers.h" // libutils: using android::sp; using android::String16; using android::String8; // libbinder: using android::binder::Status; using android::binder::Value; using android::binder::Map; // generated using android::aidl::tests::ITestService; using android::aidl::tests::INamedCallback; using std::cerr; using std::cout; using std::endl; using std::vector; namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmPrimitiveRepeat(const sp& s) { cout << "Confirming passing and returning primitives works." << endl; Map test_map; test_map["first_val"] = int8_t{-128}; test_map["second_val"] = int32_t{1 << 30}; test_map["third_val"] = String16("OHAI"); if (!RepeatPrimitive(s, &ITestService::RepeatBoolean, true) || !RepeatPrimitive(s, &ITestService::RepeatByte, int8_t{-128}) || !RepeatPrimitive(s, &ITestService::RepeatChar, char16_t{'A'}) || !RepeatPrimitive(s, &ITestService::RepeatInt, int32_t{1 << 30}) || !RepeatPrimitive(s, &ITestService::RepeatLong, int64_t{1ll << 60}) || !RepeatPrimitive(s, &ITestService::RepeatFloat, float{1.0f/3.0f}) || !RepeatPrimitive(s, &ITestService::RepeatDouble, double{1.0/3.0}) || !RepeatPrimitive(s, &ITestService::RepeatMap, test_map) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT2) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT3) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT4) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT5) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT6) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT7) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT8) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT9) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT10) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT11) || !RepeatPrimitive( s, &ITestService::RepeatInt, ITestService::TEST_CONSTANT12) ) { return false; } vector inputs = { String16("Deliver us from evil."), String16(), String16("\0\0", 2), // This is actually two unicode code points: // U+10437: The 'small letter yee' character in the deseret alphabet // U+20AC: A euro sign String16("\xD8\x01\xDC\x37\x20\xAC"), ITestService::STRING_TEST_CONSTANT(), ITestService::STRING_TEST_CONSTANT2(), }; for (const auto& input : inputs) { String16 reply; Status status = s->RepeatString(input, &reply); if (!status.isOk() || input != reply) { cerr << "Failed while requesting service to repeat String16=\"" << String8(input).string() << "\". Got status=" << status.toString8() << endl; return false; } } return true; } bool ConfirmReverseArrays(const sp& s) { cout << "Confirming passing and returning arrays works." << endl; if (!ReverseArray(s, &ITestService::ReverseBoolean, {true, false, false}) || !ReverseArray(s, &ITestService::ReverseByte, {uint8_t{255}, uint8_t{0}, uint8_t{127}}) || !ReverseArray(s, &ITestService::ReverseChar, {char16_t{'A'}, char16_t{'B'}, char16_t{'C'}}) || !ReverseArray(s, &ITestService::ReverseInt, {1, 2, 3}) || !ReverseArray(s, &ITestService::ReverseLong, {-1ll, 0ll, int64_t{1ll << 60}}) || !ReverseArray(s, &ITestService::ReverseFloat, {-0.3f, -0.7f, 8.0f}) || !ReverseArray(s, &ITestService::ReverseDouble, {1.0/3.0, 1.0/7.0, 42.0}) || !ReverseArray(s, &ITestService::ReverseString, {String16{"f"}, String16{"a"}, String16{"b"}})) { return false; } return true; } bool ConfirmReverseLists(const sp& s) { cout << "Confirming passing and returning List works." << endl; if (!ReverseArray(s, &ITestService::ReverseStringList, {String16{"f"}, String16{"a"}, String16{"b"}})) { return false; } return true; } bool ConfirmReverseBinderLists(const sp& s) { Status status; cout << "Confirming passing and returning List works with binders." << endl; vector names = { String16{"Larry"}, String16{"Curly"}, String16{"Moe"} }; vector> input; for (int i = 0; i < 3; i++) { sp got; status = s->GetOtherTestService(names[i], &got); if (!status.isOk()) { cerr << "Could not retrieve service for test." << endl; return false; } input.push_back(INamedCallback::asBinder(got)); } vector> output; vector> reversed; status = s->ReverseNamedCallbackList(input, &output, &reversed); if (!status.isOk()) { cerr << "Failed to reverse named callback list." << endl; } if (output.size() != 3) { cerr << "ReverseNamedCallbackList gave repetition with wrong length." << endl; return false; } if (reversed.size() != 3) { cerr << "ReverseNamedCallbackList gave reversal with wrong length." << endl; return false; } for (int i = 0; i < 3; i++) { String16 ret; sp named_callback = android::interface_cast(output[i]); status = named_callback->GetName(&ret); if (!status.isOk()) { cerr << "Could not query INamedCallback from output" << endl; return false; } if (ret != names[i]) { cerr << "Output had wrong INamedCallback" << endl; return false; } } for (int i = 0; i < 3; i++) { String16 ret; sp named_callback = android::interface_cast(reversed[i]); status = named_callback->GetName(&ret); if (!status.isOk()) { cerr << "Could not query INamedCallback from reversed output" << endl; return false; } if (ret != names[2 - i]) { cerr << "Reversed output had wrong INamedCallback" << endl; return false; } } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_primitives.h0100644 0000000 0000000 00000002473 13277516055 016722 0ustar000000000 0000000 /* * Copyright (C) 2015 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_AIDL_TESTS_CLIENT_PRIMITIVES_H #define ANDROID_AIDL_TESTS_CLIENT_PRIMITIVES_H #include #include "android/aidl/tests/ITestService.h" // Tests for passing and returning primitive types defined in the AIDL docs. namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmPrimitiveRepeat(const sp& s); bool ConfirmReverseArrays(const android::sp& s); bool ConfirmReverseLists(const android::sp& s); bool ConfirmReverseBinderLists(const android::sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_PRIMITIVES_H tests/aidl_test_client_service_exceptions.cpp0100644 0000000 0000000 00000002461 13277516055 020760 0ustar000000000 0000000 /* * Copyright (C) 2015 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 "aidl_test_client_service_exceptions.h" #include #include "binder/Status.h" using android::binder::Status; using std::cout; using std::endl; namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmServiceSpecificExceptions(const sp& s) { cout << "Confirming application exceptions work" << endl; for (int32_t i = -1; i < 2; ++i) { Status status = s->ThrowServiceException(i); if (status.exceptionCode() != Status::EX_SERVICE_SPECIFIC || status.serviceSpecificErrorCode() != i) { return false; } } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_service_exceptions.h0100644 0000000 0000000 00000002200 13277516055 020414 0ustar000000000 0000000 /* * Copyright (C) 2015 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_AIDL_TESTS_CLIENT_SERVICE_EXCEPTIONS_H #define ANDROID_AIDL_TESTS_CLIENT_SERVICE_EXCEPTIONS_H #include #include "android/aidl/tests/ITestService.h" namespace android { namespace aidl { namespace tests { namespace client { // Tests for service specific exception support. bool ConfirmServiceSpecificExceptions(const sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_SERVICE_EXCEPTIONS_H tests/aidl_test_client_utf8_strings.cpp0100644 0000000 0000000 00000012162 13277516055 017515 0ustar000000000 0000000 /* * Copyright (C) 2016 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 "aidl_test_client_utf8_strings.h" #include #include #include #include #include #include #include "android/aidl/tests/ITestService.h" #include "test_helpers.h" // libutils: using android::sp; // libbinder: using android::binder::Status; // generated using android::aidl::tests::ITestService; using std::unique_ptr; using std::string; using std::vector; namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmUtf8InCppStringRepeat(const sp& s) { const vector utf8_inputs = { string("Deliver us from evil."), string(), string("\0\0", 2), // Similarly, the utf8 encodings of the small letter yee and euro sign. string("\xF0\x90\x90\xB7\xE2\x82\xAC"), }; LOG(INFO) << "Confirming repeating utf8 strings works."; for (const auto& input : utf8_inputs) { string reply; Status status = s->RepeatUtf8CppString(input, &reply); if (!status.isOk() || input != reply) { LOG(ERROR) << "Failed while requesting service to repeat utf8 string=\"" << input << "\". Got status=" << status.toString8() << " and output=" << reply; return false; } } unique_ptr ret; Status repeat_null_status = s->RepeatNullableUtf8CppString(nullptr, &ret); if (!repeat_null_status.isOk() || ret) { LOG(ERROR) << "RepeatNullableUtf8CppString(null) did not return null"; return false; } for (const auto& input : utf8_inputs) { unique_ptr reply; Status status = s->RepeatNullableUtf8CppString( unique_ptr(new string(input)), &reply); if (!status.isOk()) { LOG(ERROR) << "Got status=" << status.toString8() << " while repeating " "nullable utf8 string " << input; return false; } if (!reply) { LOG(ERROR) << "Got null reply while repeating nullable utf8 string " << input; return false; } if (input != *reply) { LOG(ERROR) << "Failed while requesting service to repeat utf8 string=\"" << input << "\". Got status=" << status.toString8() << " and output=" << *reply; return false; } } return true; } bool ConfirmUtf8InCppStringArrayReverse(const sp& s) { LOG(INFO) << "Confirming passing and returning utf8 string arrays works."; if (!ReverseArray(s, &ITestService::ReverseUtf8CppString, {string{"a"}, string{}, string{"\xc3\xb8"}})) { return false; } return true; } bool ConfirmUtf8InCppStringListReverse(const sp& s) { LOG(INFO) << "Confirming reversing a list of utf8 strings works"; unique_ptr>> input, reversed, repeated; Status status = s->ReverseUtf8CppStringList(input, &reversed, &repeated); if (!status.isOk() || reversed || repeated) { LOG(ERROR) << "Reversing null list of utf8 strings failed."; return false; } input.reset(new vector>); input->emplace_back(new string("Deliver us from evil.")); input->emplace_back(nullptr); input->emplace_back(new string("\xF0\x90\x90\xB7\xE2\x82\xAC")); status = s->ReverseUtf8CppStringList(input, &repeated, &reversed); if (!status.isOk() || !reversed || !repeated) { LOG(ERROR) << "Reversing list of utf8 strings failed."; return false; } if (reversed->size() != input->size() || repeated->size() != input->size()) { LOG(ERROR) << "Bad output sizes."; return false; } for (size_t i = 0; i < input->size(); ++i) { const string* input_str = (*input)[i].get(); const string* repeated_str = (*repeated)[i].get(); const string* reversed_str = (*reversed)[(reversed->size() - 1) - i].get(); if (!input_str) { if(repeated_str || reversed_str) { LOG(ERROR) << "Expected null values, but got non-null."; return false; } // 3 nullptrs to strings. No need to compare values. continue; } if (!repeated_str || !reversed_str) { LOG(ERROR) << "Expected non-null values, but got null."; return false; } if (*input_str != *repeated_str || *input_str != *reversed_str) { LOG(ERROR) << "Expected '" << *input_str << "' but got " << "repeated='" << *repeated_str << "' and " << "reversed='" << *reversed_str; return false; } } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_utf8_strings.h0100644 0000000 0000000 00000002536 13277516055 017166 0ustar000000000 0000000 /* * Copyright (C) 2016 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_AIDL_TESTS_CLIENT_UTF8_STRINGS_H #define ANDROID_AIDL_TESTS_CLIENT_UTF8_STRINGS_H #include #include "android/aidl/tests/ITestService.h" // Tests for passing and returning utf8 strings. namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmUtf8InCppStringRepeat( const android::sp& s); bool ConfirmUtf8InCppStringArrayReverse( const android::sp& s); bool ConfirmUtf8InCppStringListReverse( const android::sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_UTF8_STRINGS_H tests/aidl_test_sentinel_searcher.cpp0100644 0000000 0000000 00000005520 13277516055 017215 0ustar000000000 0000000 /* * Copyright (C) 2015 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 #include #include #include #include #include #include using std::cerr; using std::cout; using std::endl; using std::getline; using std::ifstream; using std::string; using std::vector; namespace { bool ReadLines(const string& input_file_path, vector* lines) { ifstream watched_file(input_file_path); if (!watched_file.is_open()) { cerr << "Unable to open input file: " << input_file_path << endl; return false; } string line; while (getline(watched_file, line)) { lines->push_back(line); } watched_file.close(); return true; } bool HasSentinel(const vector& lines, const string& sentinel) { for (const auto& line : lines) { if (line.find(sentinel) != string::npos) { return true; } } return false; } } // namespace int main(int argc, const char* argv[]) { if (argc != 5) { cerr << "Invalid usage." << endl; cerr << argv[0] << " " << " " << " " << " " << endl; return -EINVAL; } const string timeout_as_str = argv[1]; const string input_file_path = argv[2]; const string success_sentinel = argv[3]; const string failure_sentinel = argv[4]; const int timeout_seconds = atoi(timeout_as_str.c_str()); if (timeout_seconds <= 0) { cerr << "Invalid timeout value (in seconds): " << timeout_as_str << endl; return -EINVAL; } int exit_code = 1; const time_t start_time = time(nullptr); vector lines; while (true) { sleep(1); if (time(nullptr) - start_time > timeout_seconds) { cerr << "Timed out waiting for success/failure sentinel." << endl; break; } // Ignore errors when reading lines. The file may not immediately exist // because it takes the Java process some time to create it. lines.clear(); ReadLines(input_file_path, &lines); if (HasSentinel(lines, success_sentinel)) { exit_code = 0; break; } if (HasSentinel(lines, failure_sentinel)) { break; } } cout << "Found output:" << endl; for (const auto& line : lines) { cout << " " << line << endl; } return exit_code; } tests/aidl_test_service.cpp0100644 0000000 0000000 00000034624 13277516055 015167 0ustar000000000 0000000 /* * Copyright (C) 2015 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "android/aidl/tests/BnTestService.h" #include "android/aidl/tests/ITestService.h" #include "android/aidl/tests/BnNamedCallback.h" #include "android/aidl/tests/INamedCallback.h" // Used implicitly. #undef LOG_TAG #define LOG_TAG "aidl_native_service" // libbase using android::base::unique_fd; // libutils: using android::Looper; using android::LooperCallback; using android::OK; using android::sp; using android::String16; // libbinder: using android::BnInterface; using android::defaultServiceManager; using android::IInterface; using android::IPCThreadState; using android::Parcel; using android::ProcessState; using android::binder::Status; // Generated code: using android::aidl::tests::BnNamedCallback; using android::aidl::tests::BnTestService; using android::aidl::tests::INamedCallback; using android::aidl::tests::SimpleParcelable; using android::os::PersistableBundle; using android::binder::Map; // Standard library using std::map; using std::string; using std::unique_ptr; using std::vector; namespace { class BinderCallback : public LooperCallback { public: BinderCallback() {} ~BinderCallback() override {} int handleEvent(int /* fd */, int /* events */, void* /* data */) override { IPCThreadState::self()->handlePolledCommands(); return 1; // Continue receiving callbacks. } }; class NamedCallback : public BnNamedCallback { public: explicit NamedCallback(String16 name) : name_(name) {} Status GetName(String16* ret) { *ret = name_; return Status::ok(); } private: String16 name_; }; class NativeService : public BnTestService { public: NativeService() {} virtual ~NativeService() = default; void LogRepeatedStringToken(const String16& token) { ALOGI("Repeating '%s' of length=%zu", android::String8(token).string(), token.size()); } template void LogRepeatedToken(const T& token) { std::ostringstream token_str; token_str << token; ALOGI("Repeating token %s", token_str.str().c_str()); } void LogRepeatedMapToken(const Map& token) { ALOGI("Repeating Map with %d elements", (int)token.size()); } Status RepeatBoolean(bool token, bool* _aidl_return) override { LogRepeatedToken(token ? 1 : 0); *_aidl_return = token; return Status::ok(); } Status RepeatByte(int8_t token, int8_t* _aidl_return) override { LogRepeatedToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatChar(char16_t token, char16_t* _aidl_return) override { LogRepeatedStringToken(String16(&token, 1)); *_aidl_return = token; return Status::ok(); } Status RepeatInt(int32_t token, int32_t* _aidl_return) override { LogRepeatedToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatLong(int64_t token, int64_t* _aidl_return) override { LogRepeatedToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatFloat(float token, float* _aidl_return) override { LogRepeatedToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatDouble(double token, double* _aidl_return) override { LogRepeatedToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatString(const String16& token, String16* _aidl_return) override { LogRepeatedStringToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatMap(const Map& token, Map* _aidl_return) override { LogRepeatedMapToken(token); *_aidl_return = token; return Status::ok(); } Status RepeatSimpleParcelable(const SimpleParcelable& input, SimpleParcelable* repeat, SimpleParcelable* _aidl_return) override { ALOGI("Repeated a SimpleParcelable %s", input.toString().c_str()); *repeat = input; *_aidl_return = input; return Status::ok(); } Status RepeatPersistableBundle(const PersistableBundle& input, PersistableBundle* _aidl_return) override { ALOGI("Repeated a PersistableBundle"); *_aidl_return = input; return Status::ok(); } template Status ReverseArray(const vector& input, vector* repeated, vector* _aidl_return) { ALOGI("Reversing array of length %zu", input.size()); *repeated = input; *_aidl_return = input; std::reverse(_aidl_return->begin(), _aidl_return->end()); return Status::ok(); } template Status RepeatNullable(const unique_ptr& input, unique_ptr* _aidl_return) { ALOGI("Repeating nullable value"); _aidl_return->reset(); if (input) { _aidl_return->reset(new T(*input)); } return Status::ok(); } Status ReverseBoolean(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseByte(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseChar(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseInt(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseLong(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseFloat(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseDouble(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseString(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseSimpleParcelables( const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReversePersistableBundles( const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status GetOtherTestService(const String16& name, sp* returned_service) override { if (service_map_.find(name) == service_map_.end()) { sp new_item(new NamedCallback(name)); service_map_[name] = new_item; } *returned_service = service_map_[name]; return Status::ok(); } Status VerifyName(const sp& service, const String16& name, bool* returned_value) override { String16 foundName; Status status = service->GetName(&foundName); if (status.isOk()) { *returned_value = foundName == name; } return status; } Status ReverseStringList(const vector& input, vector* repeated, vector* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status ReverseNamedCallbackList(const vector>& input, vector>* repeated, vector>* _aidl_return) override { return ReverseArray(input, repeated, _aidl_return); } Status RepeatFileDescriptor(const unique_fd& read, unique_fd* _aidl_return) override { ALOGE("Repeating file descriptor"); *_aidl_return = unique_fd(dup(read.get())); return Status::ok(); } Status ReverseFileDescriptorArray(const vector& input, vector* repeated, vector* _aidl_return) override { ALOGI("Reversing descriptor array of length %zu", input.size()); for (const auto& item : input) { repeated->push_back(unique_fd(dup(item.get()))); _aidl_return->push_back(unique_fd(dup(item.get()))); } std::reverse(_aidl_return->begin(), _aidl_return->end()); return Status::ok(); } Status ThrowServiceException(int code) override { return Status::fromServiceSpecificError(code); } Status RepeatNullableIntArray(const unique_ptr>& input, unique_ptr>* _aidl_return) { return RepeatNullable(input, _aidl_return); } Status RepeatNullableStringList( const unique_ptr>>& input, unique_ptr>>* _aidl_return) { ALOGI("Repeating nullable string list"); if (!input) { _aidl_return->reset(); return Status::ok(); } _aidl_return->reset(new vector>); for (const auto& item : *input) { if (!item) { (*_aidl_return)->emplace_back(nullptr); } else { (*_aidl_return)->emplace_back(new String16(*item)); } } return Status::ok(); } Status RepeatNullableString(const unique_ptr& input, unique_ptr* _aidl_return) { return RepeatNullable(input, _aidl_return); } Status RepeatNullableParcelable(const unique_ptr& input, unique_ptr* _aidl_return) { return RepeatNullable(input, _aidl_return); } Status TakesAnIBinder(const sp& input) override { (void)input; return Status::ok(); } Status TakesAnIBinderList(const vector>& input) override { (void)input; return Status::ok(); } Status TakesANullableIBinder(const sp& input) { (void)input; return Status::ok(); } Status TakesANullableIBinderList(const unique_ptr>>& input) { (void)input; return Status::ok(); } Status RepeatUtf8CppString(const string& token, string* _aidl_return) override { ALOGI("Repeating utf8 string '%s' of length=%zu", token.c_str(), token.size()); *_aidl_return = token; return Status::ok(); } Status RepeatNullableUtf8CppString( const unique_ptr& token, unique_ptr* _aidl_return) override { if (!token) { ALOGI("Received null @utf8InCpp string"); return Status::ok(); } ALOGI("Repeating utf8 string '%s' of length=%zu", token->c_str(), token->size()); _aidl_return->reset(new string(*token)); return Status::ok(); } Status ReverseUtf8CppString(const vector& input, vector* repeated, vector* _aidl_return) { return ReverseArray(input, repeated, _aidl_return); } Status ReverseUtf8CppStringList( const unique_ptr>>& input, unique_ptr>>* repeated, unique_ptr>>* _aidl_return) { if (!input) { ALOGI("Received null list of utf8 strings"); return Status::ok(); } _aidl_return->reset(new vector>); repeated->reset(new vector>); for (const auto& item : *input) { (*repeated)->emplace_back(nullptr); (*_aidl_return)->emplace_back(nullptr); if (item) { (*repeated)->back().reset(new string(*item)); (*_aidl_return)->back().reset(new string(*item)); } } std::reverse((*_aidl_return)->begin(), (*_aidl_return)->end()); return Status::ok(); } Status GetCallback(bool return_null, sp* ret) { if (!return_null) { return GetOtherTestService(String16("ABT: always be testing"), ret); } return Status::ok(); } private: map> service_map_; }; int Run() { android::sp service = new NativeService; sp looper(Looper::prepare(0 /* opts */)); int binder_fd = -1; ProcessState::self()->setThreadPoolMaxThreadCount(0); IPCThreadState::self()->disableBackgroundScheduling(true); IPCThreadState::self()->setupPolling(&binder_fd); ALOGI("Got binder FD %d", binder_fd); if (binder_fd < 0) return -1; sp cb(new BinderCallback); if (looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb, nullptr) != 1) { ALOGE("Failed to add binder FD to Looper"); return -1; } defaultServiceManager()->addService(service->getInterfaceDescriptor(), service); ALOGI("Entering loop"); while (true) { const int result = looper->pollAll(-1 /* timeoutMillis */); ALOGI("Looper returned %d", result); } return 0; } } // namespace int main(int /* argc */, char* /* argv */ []) { return Run(); } tests/android/0040755 0000000 0000000 00000000000 13277516055 012405 5ustar000000000 0000000 tests/android/aidl/0040755 0000000 0000000 00000000000 13277516055 013316 5ustar000000000 0000000 tests/android/aidl/tests/0040755 0000000 0000000 00000000000 13277516055 014460 5ustar000000000 0000000 tests/android/aidl/tests/INamedCallback.aidl0100644 0000000 0000000 00000001273 13277516055 020065 0ustar000000000 0000000 /* * Copyright (C) 2015 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; interface INamedCallback { String GetName(); } tests/android/aidl/tests/ITestService.aidl0100644 0000000 0000000 00000011243 13277516055 017662 0ustar000000000 0000000 /* * Copyright (C) 2015 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; import android.aidl.tests.INamedCallback; import android.aidl.tests.SimpleParcelable; import android.os.PersistableBundle; interface ITestService { // Test that constants are accessible const int TEST_CONSTANT = 42; const int TEST_CONSTANT2 = -42; const int TEST_CONSTANT3 = +42; const int TEST_CONSTANT4 = +4; const int TEST_CONSTANT5 = -4; const int TEST_CONSTANT6 = -0; const int TEST_CONSTANT7 = +0; const int TEST_CONSTANT8 = 0; const int TEST_CONSTANT9 = 0x56; const int TEST_CONSTANT10 = 0xa5; const int TEST_CONSTANT11 = 0xFA; const int TEST_CONSTANT12 = 0xffffffff; const String STRING_TEST_CONSTANT = "foo"; const String STRING_TEST_CONSTANT2 = "bar"; // Test that primitives work as parameters and return types. boolean RepeatBoolean(boolean token); byte RepeatByte(byte token); char RepeatChar(char token); int RepeatInt(int token); long RepeatLong(long token); float RepeatFloat(float token); double RepeatDouble(double token); String RepeatString(String token); Map RepeatMap(in Map token); SimpleParcelable RepeatSimpleParcelable(in SimpleParcelable input, out SimpleParcelable repeat); PersistableBundle RepeatPersistableBundle(in PersistableBundle input); // Test that arrays work as parameters and return types. boolean[] ReverseBoolean(in boolean[] input, out boolean[] repeated); byte[] ReverseByte (in byte[] input, out byte[] repeated); char[] ReverseChar (in char[] input, out char[] repeated); int[] ReverseInt (in int[] input, out int[] repeated); long[] ReverseLong (in long[] input, out long[] repeated); float[] ReverseFloat (in float[] input, out float[] repeated); double[] ReverseDouble (in double[] input, out double[] repeated); String[] ReverseString (in String[] input, out String[] repeated); SimpleParcelable[] ReverseSimpleParcelables(in SimpleParcelable[] input, out SimpleParcelable[] repeated); PersistableBundle[] ReversePersistableBundles( in PersistableBundle[] input, out PersistableBundle[] repeated); // Test that clients can send and receive Binders. INamedCallback GetOtherTestService(String name); boolean VerifyName(INamedCallback service, String name); // Test that List types work correctly. List ReverseStringList(in List input, out List repeated); List ReverseNamedCallbackList(in List input, out List repeated); FileDescriptor RepeatFileDescriptor(in FileDescriptor read); FileDescriptor[] ReverseFileDescriptorArray(in FileDescriptor[] input, out FileDescriptor[] repeated); // Test that service specific exceptions work correctly. void ThrowServiceException(int code); // Test nullability @nullable int[] RepeatNullableIntArray(in @nullable int[] input); @nullable String RepeatNullableString(in @nullable String input); @nullable List RepeatNullableStringList(in @nullable List input); @nullable SimpleParcelable RepeatNullableParcelable(in @nullable SimpleParcelable input); void TakesAnIBinder(in IBinder input); void TakesAnIBinderList(in List input); void TakesANullableIBinder(in @nullable IBinder input); void TakesANullableIBinderList(in @nullable List input); // Test utf8 decoding from utf16 wire format @utf8InCpp String RepeatUtf8CppString(@utf8InCpp String token); @nullable @utf8InCpp String RepeatNullableUtf8CppString( @nullable @utf8InCpp String token); @utf8InCpp String[] ReverseUtf8CppString (in @utf8InCpp String[] input, out @utf8InCpp String[] repeated); @nullable @utf8InCpp List ReverseUtf8CppStringList( in @nullable @utf8InCpp List input, out @nullable @utf8InCpp List repeated); @nullable INamedCallback GetCallback(boolean return_null); } tests/android/aidl/tests/SimpleParcelable.aidl0100644 0000000 0000000 00000001316 13277516055 020515 0ustar000000000 0000000 /* * Copyright (C) 2015 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 SimpleParcelable cpp_header "tests/simple_parcelable.h"; tests/end_to_end_tests.cpp0100644 0000000 0000000 00000013060 13277516055 015006 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include #include #include #include "aidl.h" #include "options.h" #include "tests/fake_io_delegate.h" #include "tests/test_data.h" #include "tests/test_util.h" using android::aidl::test::CanonicalNameToPath; using android::aidl::test::FakeIoDelegate; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { class EndToEndTest : public ::testing::Test { protected: virtual void SetUp() { } void AddStubAidls(const char** parcelables, const char** interfaces, const char* cpp_header=nullptr) { for ( ; *parcelables; ++parcelables) { io_delegate_.AddStubParcelable( *parcelables, (cpp_header) ? cpp_header : ""); } for ( ; *interfaces; ++interfaces) { io_delegate_.AddStubInterface(*interfaces); } } void CheckFileContents(const string& rel_path, const string& expected_content) { string actual_content; ASSERT_TRUE(io_delegate_.GetWrittenContents(rel_path, &actual_content)) << "Expected aidl to write to " << rel_path << " but it did not."; if (actual_content == expected_content) { return; // success! } test::PrintDiff(expected_content, actual_content); FAIL() << "Actual contents of " << rel_path << " did not match expected content"; } FakeIoDelegate io_delegate_; }; TEST_F(EndToEndTest, IExampleInterface) { using namespace ::android::aidl::test_data::example_interface; JavaOptions options; options.fail_on_parcelable_ = true; options.import_paths_.push_back(""); options.input_file_name_ = CanonicalNameToPath(kCanonicalName, ".aidl"); options.output_file_name_ = kJavaOutputPath; options.dep_file_name_ = "an/arbitrary/path/to/deps.P"; // Load up our fake file system with data. io_delegate_.SetFileContents(options.input_file_name_, kInterfaceDefinition); io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable", {"Subclass1", "Subclass2"}); AddStubAidls(kImportedParcelables, kImportedInterfaces); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl_to_java(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutput); CheckFileContents(options.DependencyFilePath(), kExpectedJavaDepsOutput); } TEST_F(EndToEndTest, IPingResponderCpp) { using namespace ::android::aidl::test_data::ping_responder; const string input_path = CanonicalNameToPath(kCanonicalName, ".aidl"); const string output_file = kCppOutputPath; const size_t argc = 6; const char* cmdline[argc + 1] = { "aidl-cpp", "-ddeps.P", "-I.", input_path.c_str(), kGenHeaderDir, output_file.c_str(), nullptr }; auto options = CppOptions::Parse(argc, cmdline); // Set up input paths. io_delegate_.SetFileContents(input_path, kInterfaceDefinition); AddStubAidls(kImportedParcelables, kImportedInterfaces, kCppParcelableHeader); // Check that we parse and generate code correctly. EXPECT_EQ(android::aidl::compile_aidl_to_cpp(*options, io_delegate_), 0); CheckFileContents(output_file, kExpectedCppOutput); CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput); CheckFileContents(kGenClientHeaderPath, kExpectedBpHeaderOutput); CheckFileContents(kGenServerHeaderPath, kExpectedBnHeaderOutput); CheckFileContents(options->DependencyFilePath(), kExpectedCppDepsOutput); } TEST_F(EndToEndTest, StringConstantsInCpp) { using namespace ::android::aidl::test_data::string_constants; const string input_path = CanonicalNameToPath(kCanonicalName, ".aidl"); const string output_file = kCppOutputPath; const size_t argc = 4; const char* cmdline[argc + 1] = { "aidl-cpp", input_path.c_str(), kGenHeaderDir, output_file.c_str(), nullptr }; auto options = CppOptions::Parse(argc, cmdline); // Set up input paths. io_delegate_.SetFileContents(input_path, kInterfaceDefinition); // Check that we parse and generate code correctly. EXPECT_EQ(android::aidl::compile_aidl_to_cpp(*options, io_delegate_), 0); CheckFileContents(output_file, kExpectedCppOutput); CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput); } TEST_F(EndToEndTest, StringConstantsInJava) { using namespace ::android::aidl::test_data::string_constants; const string input_path = CanonicalNameToPath(kCanonicalName, ".aidl"); const string output_file = kJavaOutputPath; const size_t argc = 4; const char* cmdline[argc + 1] = { "aidl", "-b", input_path.c_str(), output_file.c_str(), nullptr, }; auto options = JavaOptions::Parse(argc, cmdline); // Load up our fake file system with data. io_delegate_.SetFileContents(input_path, kInterfaceDefinition); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl_to_java(*options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutput); } } // namespace android } // namespace aidl tests/fake_io_delegate.cpp0100644 0000000 0000000 00000012337 13277516055 014723 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "fake_io_delegate.h" #include #include "logging.h" #include "os.h" #include "tests/test_util.h" using android::base::StringAppendF; using android::base::StringPrintf; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace test { // Claims to always write successfully, but can't close the file. class BrokenCodeWriter : public CodeWriter { bool Write(const char* /* format */, ...) override { return true; } bool Close() override { return false; } virtual ~BrokenCodeWriter() = default; }; // class BrokenCodeWriter unique_ptr FakeIoDelegate::GetFileContents( const string& relative_filename, const string& content_suffix) const { string filename = CleanPath(relative_filename); unique_ptr contents; auto it = file_contents_.find(filename); if (it == file_contents_.end()) { return contents; } contents.reset(new string); *contents = it->second; contents->append(content_suffix); return contents; } unique_ptr FakeIoDelegate::GetLineReader( const string& file_path) const { unique_ptr ret; const auto& it = file_contents_.find(CleanPath(file_path)); if (it != file_contents_.cend()) { ret = LineReader::ReadFromMemory(it->second); } return ret; } bool FakeIoDelegate::FileIsReadable(const string& path) const { return file_contents_.find(CleanPath(path)) != file_contents_.end(); } bool FakeIoDelegate::CreatedNestedDirs( const std::string& /* base_dir */, const std::vector& /* nested_subdirs */) const { // We don't test directory creation explicitly. return true; } std::unique_ptr FakeIoDelegate::GetCodeWriter( const std::string& file_path) const { if (broken_files_.count(file_path) > 0) { return unique_ptr(new BrokenCodeWriter); } removed_files_.erase(file_path); written_file_contents_[file_path] = ""; return GetStringWriter(&written_file_contents_[file_path]); } void FakeIoDelegate::RemovePath(const std::string& file_path) const { removed_files_.insert(file_path); } void FakeIoDelegate::SetFileContents(const string& filename, const string& contents) { file_contents_[filename] = contents; } void FakeIoDelegate::AddStubParcelable(const string& canonical_name, const string& cpp_header) { string package, class_name, rel_path; SplitPackageClass(canonical_name, &rel_path, &package, &class_name); string contents; if (cpp_header.empty()) { contents = StringPrintf("package %s;\nparcelable %s;", package.c_str(), class_name.c_str()); } else { contents = StringPrintf("package %s;\nparcelable %s cpp_header \"%s\";", package.c_str(), class_name.c_str(), cpp_header.c_str()); } SetFileContents(rel_path, contents); } void FakeIoDelegate::AddStubInterface(const string& canonical_name) { string package, class_name, rel_path; SplitPackageClass(canonical_name, &rel_path, &package, &class_name); string contents = StringPrintf("package %s;\ninterface %s { }", package.c_str(), class_name.c_str()); SetFileContents(rel_path, contents); } void FakeIoDelegate::AddCompoundParcelable(const string& canonical_name, const vector& subclasses) { string package, class_name, rel_path; SplitPackageClass(canonical_name, &rel_path, &package, &class_name); string contents = StringPrintf("package %s;\n", package.c_str()); for (const string& subclass : subclasses) { StringAppendF(&contents, "parcelable %s.%s;\n", class_name.c_str(), subclass.c_str()); } SetFileContents(rel_path, contents); } void FakeIoDelegate::AddBrokenFilePath(const std::string& path) { broken_files_.insert(path); } bool FakeIoDelegate::GetWrittenContents(const string& path, string* content) { const auto it = written_file_contents_.find(path); if (it == written_file_contents_.end()) { return false; } if (content) { *content = it->second; } return true; } bool FakeIoDelegate::PathWasRemoved(const std::string& path) { if (removed_files_.count(path) > 0) { return true; } return false; } string FakeIoDelegate::CleanPath(const string& path) const { string clean_path = path; while (clean_path.length() >= 2 && clean_path[0] == '.' && clean_path[1] == OS_PATH_SEPARATOR) { clean_path = clean_path.substr(2); } return clean_path; } } // namespace test } // namespace android } // namespace aidl tests/fake_io_delegate.h0100644 0000000 0000000 00000006254 13277516055 014371 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_TESTS_FAKE_IO_DELEGATE_H_ #define AIDL_TESTS_FAKE_IO_DELEGATE_H_ #include #include #include #include #include #include #include "io_delegate.h" namespace android { namespace aidl { namespace test { class FakeIoDelegate : public IoDelegate { public: FakeIoDelegate() = default; virtual ~FakeIoDelegate() = default; // Overrides from the real IoDelegate std::unique_ptr GetFileContents( const std::string& filename, const std::string& append_content_suffix = "") const override; std::unique_ptr GetLineReader( const std::string& file_path) const override; bool FileIsReadable(const std::string& path) const override; bool CreatedNestedDirs( const std::string& base_dir, const std::vector& nested_subdirs) const override; std::unique_ptr GetCodeWriter( const std::string& file_path) const override; void RemovePath(const std::string& file_path) const override; // Methods added to facilitate testing. void SetFileContents(const std::string& filename, const std::string& contents); void AddStubParcelable(const std::string& canonical_name, const std::string& cpp_header); void AddStubInterface(const std::string& canonical_name); void AddCompoundParcelable(const std::string& canonical_name, const std::vector& subclasses); void AddBrokenFilePath(const std::string& path); // Returns true iff we've previously written to |path|. // When we return true, we'll set *contents to the written string. bool GetWrittenContents(const std::string& path, std::string* content); bool PathWasRemoved(const std::string& path); private: // Remove leading "./" from |path|. std::string CleanPath(const std::string& path) const; std::map file_contents_; // Normally, writing to files leaves the IoDelegate unchanged, so // GetCodeWriter is a const method. However, for tests, we break this // intentionally by storing the written strings. mutable std::map written_file_contents_; // We normally just write to strings in |written_file_contents_| but for // files in this list, we simulate I/O errors. std::set broken_files_; mutable std::set removed_files_; DISALLOW_COPY_AND_ASSIGN(FakeIoDelegate); }; // class FakeIoDelegate } // namespace test } // namespace android } // namespace aidl #endif // AIDL_TESTS_FAKE_IO_DELEGATE_H_ tests/integration-test.py0100755 0000000 0000000 00000014353 13277516055 014645 0ustar000000000 0000000 #!/usr/bin/env python """ Test that aidl generates functional code by running it on an Android device. """ import argparse import pipes import subprocess import shlex JAVA_OUTPUT_READER = 'aidl_test_sentinel_searcher' NATIVE_TEST_CLIENT = 'aidl_test_client' NATIVE_TEST_SERVICE = 'aidl_test_service' TEST_FILTER_ALL = 'all' TEST_FILTER_JAVA = 'java' TEST_FILTER_NATIVE = 'native' JAVA_CLIENT_TIMEOUT_SECONDS = 30 JAVA_LOG_FILE = '/data/data/android.aidl.tests/files/test-client.log' JAVA_SUCCESS_SENTINEL = '>>> Java Client Success <<<' JAVA_FAILURE_SENTINEL = '>>> Java Client Failure <<<' class TestFail(Exception): """Raised on test failures.""" pass class ShellResult(object): """Represents the result of running a shell command.""" def __init__(self, exit_status, stdout, stderr): """Construct an instance. Args: exit_status: integer exit code of shell command stdout: string stdout of shell command stderr: string stderr of shell command """ self.stdout = stdout self.stderr = stderr self.exit_status = exit_status def printable_string(self): """Get a string we could print to the logs and understand.""" output = [] output.append('stdout:') for line in self.stdout.splitlines(): output.append(' > %s' % line) output.append('stderr:') for line in self.stderr.splitlines(): output.append(' > %s' % line) return '\n'.join(output) class AdbHost(object): """Represents a device connected via ADB.""" def __init__(self, device_serial=None, verbose=None): """Construct an instance. Args: device_serial: options string serial number of attached device. verbose: True iff we should print out ADB commands we run. """ self._device_serial = device_serial self._verbose = verbose def run(self, command, background=False, ignore_status=False): """Run a command on the device via adb shell. Args: command: string containing a shell command to run. background: True iff we should run this command in the background. ignore_status: True iff we should ignore the command's exit code. Returns: instance of ShellResult. Raises: subprocess.CalledProcessError on command exit != 0. """ if background: command = '( %s ) /dev/null 2>&1 &' % command return self.adb('shell %s' % pipes.quote(command), ignore_status=ignore_status) def mktemp(self): """Make a temp file on the device. Returns: path to created file as a string Raises: subprocess.CalledProcessError on failure. """ # Work around b/19635681 result = self.run('source /system/etc/mkshrc && mktemp') return result.stdout.strip() def adb(self, command, ignore_status=False): """Run an ADB command (e.g. `adb sync`). Args: command: string containing command to run ignore_status: True iff we should ignore the command's exit code. Returns: instance of ShellResult. Raises: subprocess.CalledProcessError on command exit != 0. """ command = 'adb %s' % command if self._verbose: print(command) p = subprocess.Popen(command, shell=True, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) stdout, stderr = p.communicate() if not ignore_status and p.returncode: raise subprocess.CalledProcessError(p.returncode, command) return ShellResult(p.returncode, stdout, stderr) def run_test(host, test_native, test_java): """Body of the test. Args: host: AdbHost object to run tests on test_native: True iff we should test native Binder clients. test_java: True iff we shoudl test Java Binder clients. """ print('Starting aidl integration testing...') # Kill any previous test context host.run('rm -f %s' % JAVA_LOG_FILE, ignore_status=True) host.run('pkill %s' % NATIVE_TEST_SERVICE, ignore_status=True) # Start up a native server host.run(NATIVE_TEST_SERVICE, background=True) # Start up clients if test_native: host.run('pkill %s' % NATIVE_TEST_CLIENT, ignore_status=True) result = host.run(NATIVE_TEST_CLIENT, ignore_status=True) if result.exit_status: print(result.printable_string()) raise TestFail('%s returned status code %d' % (NATIVE_TEST_CLIENT, result.exit_status)) if test_java: host.run('am start -S -a android.intent.action.MAIN ' '-n android.aidl.tests/.TestServiceClient ' '--es sentinel.success "%s" ' '--es sentinel.failure "%s"' % (JAVA_SUCCESS_SENTINEL, JAVA_FAILURE_SENTINEL)) result = host.run('%s %d %s "%s" "%s"' % (JAVA_OUTPUT_READER, JAVA_CLIENT_TIMEOUT_SECONDS, JAVA_LOG_FILE, JAVA_SUCCESS_SENTINEL, JAVA_FAILURE_SENTINEL), ignore_status=True) if result.exit_status: print(result.printable_string()) raise TestFail('Java client did not complete successfully.') print('Success!') def main(): """Main entry point.""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( '--test-filter', default=TEST_FILTER_ALL, choices=[TEST_FILTER_ALL, TEST_FILTER_JAVA, TEST_FILTER_NATIVE]) parser.add_argument('--verbose', '-v', action='store_true', default=False) args = parser.parse_args() host = AdbHost(verbose=args.verbose) try: # Tragically, SELinux interferes with our testing host.run('setenforce 0') run_test(host, args.test_filter in (TEST_FILTER_ALL, TEST_FILTER_NATIVE), args.test_filter in (TEST_FILTER_ALL, TEST_FILTER_JAVA)) finally: host.run('setenforce 1') if __name__ == '__main__': main() tests/java_app/0040755 0000000 0000000 00000000000 13277516055 012546 5ustar000000000 0000000 tests/java_app/AndroidManifest.xml0100644 0000000 0000000 00000000755 13277516055 016343 0ustar000000000 0000000 tests/java_app/README0100644 0000000 0000000 00000001104 13277516055 013417 0ustar000000000 0000000 To use this APK do something like: 1) Build your favorite AOSP flavor. 2) Start an emulator: $ emulator 3) Push over hellod binary: $ adb remount && adb sync 4) Install the Java client: $ adb install -r 5) Put selinux in permissive mode. 6) Start hellod: $ adb shell "(hellod ) /dev/null 2>&1 &" 7) Start Java client: $ adb shell am start -S -a android.intent.action.MAIN \ -n "android.aidl.tests/.TestServiceClient" 8) Watch output on logcat: $ adb logcat -s TestServiceClient hellod tests/java_app/resources/0040755 0000000 0000000 00000000000 13277516055 014560 5ustar000000000 0000000 tests/java_app/resources/values/0040755 0000000 0000000 00000000000 13277516055 016057 5ustar000000000 0000000 tests/java_app/resources/values/strings.xml0100644 0000000 0000000 00000000613 13277516055 020267 0ustar000000000 0000000 AIDL Test Services tests/java_app/src/0040755 0000000 0000000 00000000000 13277516055 013335 5ustar000000000 0000000 tests/java_app/src/android/0040755 0000000 0000000 00000000000 13277516055 014755 5ustar000000000 0000000 tests/java_app/src/android/aidl/0040755 0000000 0000000 00000000000 13277516055 015666 5ustar000000000 0000000 tests/java_app/src/android/aidl/tests/0040755 0000000 0000000 00000000000 13277516055 017030 5ustar000000000 0000000 tests/java_app/src/android/aidl/tests/NullableTests.java0100644 0000000 0000000 00000010444 13277516055 022454 0ustar000000000 0000000 /* * Copyright (C) 2016, 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; import android.aidl.tests.TestFailException; import android.os.IBinder; import java.util.ArrayList; import java.util.List; class NullableTests { private static final String TAG = "TestServiceClient"; private ITestService mService; private TestLogger mLog; public NullableTests(ITestService service, TestLogger logger) { mService = service; mLog = logger; } public void checkNullHandling() throws TestFailException { mLog.log("Checking that sending null strings reports an error..."); try { String response = mService.RepeatString(null); mLog.logAndThrow("Expected to fail on null string input!"); } catch (NullPointerException ex) { mLog.log("Caught an exception on null string parameter (expected)"); mLog.log("null strings behave as expected"); return; } catch (Exception ex) { mLog.logAndThrow("Expected to receive NullPointerException on " + "null parameter, but got " + ex.toString()); } mLog.logAndThrow("Expected to receive NullPointerException on " + "null parameter, but nothing was thrown??"); } public void checkNullBinderDetection() throws TestFailException { mLog.log("Checking that service handles @nullable IBinder..."); try { mService.TakesAnIBinder(null); mLog.logAndThrow("Expected to fail on null Binder!"); } catch (NullPointerException ex) { mLog.log("Caught an exception on null Binder parameter (expected)"); return; } catch (Exception ex) { mLog.logAndThrow("Expected to receive NullPointerException," + "but got " + ex.toString()); } mLog.logAndThrow("Expected to receive NullPointerException on " + "null parameter, but nothing was thrown??"); } public void checkNullBinderInListDetection() throws TestFailException { List listWithNulls = new ArrayList(); listWithNulls.add(null); try { mService.TakesAnIBinderList(listWithNulls); mLog.logAndThrow("Expected to fail on list with null Binder!"); } catch (NullPointerException ex) { mLog.log("Caught an exception on list with null Binder (expected)"); return; } catch (Exception ex) { mLog.logAndThrow("Expected to receive NullPointerException," + "but got " + ex.toString()); } mLog.logAndThrow("Expected to receive NullPointerException on " + "null parameter, but nothing was thrown??"); } public void checkNullInterfaceHandling() throws TestFailException { mLog.log("Checking @nullable IInterface handling..."); try { INamedCallback callback = mService.GetCallback(false); if (callback == null) { mLog.logAndThrow("Expected to get non-null INamedCallback."); } callback = mService.GetCallback(true); if (callback != null) { mLog.logAndThrow("Expected to get null INamedCallback."); } } catch (Exception ex) { mLog.logAndThrow("Unexpected exception during @nullable IInterface test: " + ex.toString()); } mLog.log("@nullable IInterface handling works as expected."); } public void runTests() throws TestFailException { checkNullHandling(); checkNullBinderDetection(); checkNullBinderInListDetection(); checkNullInterfaceHandling(); } } tests/java_app/src/android/aidl/tests/SimpleParcelable.java0100644 0000000 0000000 00000004303 13277516055 023074 0ustar000000000 0000000 /* * Copyright (C) 2015, 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; import android.os.Parcel; import android.os.Parcelable; public class SimpleParcelable implements Parcelable { private String mName; private int mNumber; SimpleParcelable() {} SimpleParcelable(String name, int number) { mName = name; mNumber = number; } public int describeContents() { return 0; } public void writeToParcel(Parcel dest, int flags) { dest.writeString(mName); dest.writeInt(mNumber); } public void readFromParcel(Parcel source) { mName = source.readString(); mNumber = source.readInt(); } public boolean equals(Object o) { if (o == null) { return false; } if (!(o instanceof SimpleParcelable)) { return false; } SimpleParcelable p = (SimpleParcelable)o; if ((mName == null && p.mName != null) || (mName != null && !mName.equals(p.mName))) { return false; } return mNumber == p.mNumber; } public String toString() { return "SimpleParcelable(" + mName + ", " + mNumber + ")"; } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public SimpleParcelable createFromParcel(Parcel source) { String name = source.readString(); int number = source.readInt(); return new SimpleParcelable(name, number); } public SimpleParcelable[] newArray(int size) { return new SimpleParcelable[size]; } }; } tests/java_app/src/android/aidl/tests/TestFailException.java0100644 0000000 0000000 00000001415 13277516055 023263 0ustar000000000 0000000 /* * Copyright (C) 2016, 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; public class TestFailException extends Exception { public TestFailException(String message) { super(message); } } tests/java_app/src/android/aidl/tests/TestLogger.java0100644 0000000 0000000 00000003053 13277516055 021750 0ustar000000000 0000000 /* * Copyright (C) 2016, 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; import android.util.Log; import java.io.PrintWriter; import java.io.IOException; import android.content.Context; public class TestLogger { private static final String TAG = "TestServiceClient"; private PrintWriter mLogFile; public TestLogger(Context context) { try { mLogFile = new PrintWriter(context.openFileOutput( "test-client.log", Context.MODE_PRIVATE)); } catch (IOException ex) { throw new RuntimeException("Failed to open log file for writing."); } } public void log(String line) { Log.i(TAG, line); mLogFile.println(line); } public void logAndThrow(String line) throws TestFailException { Log.e(TAG, line); mLogFile.println(line); throw new TestFailException(line); } public void close() { if (mLogFile != null) { mLogFile.close(); } } } tests/java_app/src/android/aidl/tests/TestServiceClient.java0100644 0000000 0000000 00000077356 13277516055 023311 0ustar000000000 0000000 /* * Copyright (C) 2015, 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; import android.aidl.tests.SimpleParcelable; import android.aidl.tests.TestFailException; import android.aidl.tests.TestLogger; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.ServiceSpecificException; import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.HashMap; // Generated import android.aidl.tests.INamedCallback; import android.aidl.tests.ITestService; public class TestServiceClient extends Activity { private static final String TAG = "TestServiceClient"; private TestLogger mLog; private String mSuccessSentinel; private String mFailureSentinel; private void init() { Intent intent = getIntent(); mLog = new TestLogger(this); mLog.log("Reading sentinels from intent..."); mSuccessSentinel = intent.getStringExtra("sentinel.success"); mFailureSentinel = intent.getStringExtra("sentinel.failure"); if (mSuccessSentinel == null || mFailureSentinel == null) { String message = "Failed to read intent extra input."; Log.e(TAG, message); mLog.close(); throw new RuntimeException(message); } } private ITestService getService() throws TestFailException { IBinder service = new ServiceManager().getService( ITestService.class.getName()); if (service == null) { mLog.logAndThrow("Failed to obtain binder..."); } ITestService ret = ITestService.Stub.asInterface(service); if (ret == null) { mLog.logAndThrow("Failed to cast IBinder instance."); } return ret; } private void checkPrimitiveRepeat(ITestService service) throws TestFailException { mLog.log("Checking that service can repeat primitives back..."); try { { boolean query = true; boolean response = service.RepeatBoolean(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { char query = 'A'; char response = service.RepeatChar(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { byte query = -128; byte response = service.RepeatByte(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { int query = 1 << 30; int response = service.RepeatInt(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { int query[] = {ITestService.TEST_CONSTANT, ITestService.TEST_CONSTANT2, ITestService.TEST_CONSTANT3, ITestService.TEST_CONSTANT4, ITestService.TEST_CONSTANT5, ITestService.TEST_CONSTANT6, ITestService.TEST_CONSTANT7, ITestService.TEST_CONSTANT8}; for (int i = 0; i < query.length; i++) { int response = service.RepeatInt(query[i]); if (query[i] != response) { mLog.logAndThrow("Repeat with " + query[i] + " responded " + response); } } } { long query = 1L << 60; long response = service.RepeatLong(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { float query = 1.0f/3.0f; float response = service.RepeatFloat(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { double query = 1.0/3.0; double response = service.RepeatDouble(query); if (query != response) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } { Map query = new HashMap(); query.put("first_val", new Byte((byte)-128)); query.put("second_val", new Integer(1<<30)); query.put("third_val", "OHAI"); Object response = service.RepeatMap(query); if (!query.equals(response)) { mLog.logAndThrow("Repeat with " + query + " responded " + response); } } List queries = Arrays.asList( "not empty", "", "\0", ITestService.STRING_TEST_CONSTANT, ITestService.STRING_TEST_CONSTANT2); for (String query : queries) { String response = service.RepeatString(query); if (!query.equals(response)) { mLog.logAndThrow("Repeat request with '" + query + "'" + " of length " + query.length() + " responded with '" + response + "'" + " of length " + response.length()); } } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to repeat a primitive back."); } mLog.log("...Basic primitive repeating works."); } private void checkArrayReversal(ITestService service) throws TestFailException { mLog.log("Checking that service can reverse and return arrays..."); try { { boolean[] input = {true, false, false, false}; boolean echoed[] = new boolean[input.length]; boolean[] reversed = service.ReverseBoolean(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { byte[] input = {0, 1, 2}; byte echoed[] = new byte[input.length]; byte[] reversed = service.ReverseByte(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { char[] input = {'A', 'B', 'C', 'D', 'E'}; char echoed[] = new char[input.length]; char[] reversed = service.ReverseChar(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { int[] input = {-1, 0, 1, 2, 3, 4, 5, 6}; int echoed[] = new int[input.length]; int[] reversed = service.ReverseInt(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { long[] input = {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8}; long echoed[] = new long[input.length]; long[] reversed = service.ReverseLong(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { float[] input = {0.0f, 1.0f, -0.3f}; float echoed[] = new float[input.length]; float[] reversed = service.ReverseFloat(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { double[] input = {-1.0, -4.0, -2.0}; double echoed[] = new double[input.length]; double[] reversed = service.ReverseDouble(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (input[i] != reversed[j]) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } { String[] input = {"For", "relaxing", "times"}; String echoed[] = new String[input.length]; String[] reversed = service.ReverseString(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (!input[i].equals(reversed[j])) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to reverse an array."); } mLog.log("...service can reverse and return arrays."); } private void checkBinderExchange( ITestService service) throws TestFailException { mLog.log("Checking exchange of binders..."); try { INamedCallback got = service.GetOtherTestService("Smythe"); mLog.log("Received test service"); String name = got.GetName(); if (!name.equals("Smythe")) { mLog.logAndThrow("Tried to get service with name 'Smythe'" + " and found service with name '" + name + "'"); } if (!service.VerifyName(got, "Smythe")) { mLog.logAndThrow("Test service could not verify name of 'Smythe'"); } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to exchange binders."); } mLog.log("...Exchange of binders works"); } private void checkListReversal(ITestService service) throws TestFailException { mLog.log("Checking that service can reverse and return lists..."); try { { List input = Arrays.asList("Walk", "into", "Córdoba"); List echoed = new ArrayList(); List reversed = service.ReverseStringList(input, echoed); if (!input.equals(echoed)) { mLog.logAndThrow("Failed to echo input List back."); } Collections.reverse(input); if (!input.equals(reversed)) { mLog.logAndThrow("Reversed list is not correct."); } } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to reverse an List."); } mLog.log("...service can reverse and return lists."); } private void checkSimpleParcelables(ITestService service) throws TestFailException { mLog.log("Checking that service can repeat and reverse SimpleParcelable objects..."); try { { SimpleParcelable input = new SimpleParcelable("foo", 42); SimpleParcelable out_param = new SimpleParcelable(); SimpleParcelable returned = service.RepeatSimpleParcelable(input, out_param); if (!input.equals(out_param)) { mLog.log(input.toString() + " != " + out_param.toString()); mLog.logAndThrow("out param SimpleParcelable was not equivalent"); } if (!input.equals(returned)) { mLog.log(input.toString() + " != " + returned.toString()); mLog.logAndThrow("returned SimpleParcelable was not equivalent"); } } { SimpleParcelable[] input = new SimpleParcelable[3]; input[0] = new SimpleParcelable("a", 1); input[1] = new SimpleParcelable("b", 2); input[2] = new SimpleParcelable("c", 3); SimpleParcelable[] repeated = new SimpleParcelable[3]; SimpleParcelable[] reversed = service.ReverseSimpleParcelables( input, repeated); if (!Arrays.equals(input, repeated)) { mLog.logAndThrow( "Repeated list of SimpleParcelable objects did not match."); } if (input.length != reversed.length) { mLog.logAndThrow( "Reversed list of SimpleParcelable objects had wrong length."); } for (int i = 0, k = input.length - 1; i < input.length; ++i, --k) { if (!input[i].equals(reversed[k])) { mLog.log(input[i].toString() + " != " + reversed[k].toString()); mLog.logAndThrow("reversed SimpleParcelable was not equivalent"); } } } } catch (Exception ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to handle SimpleParcelable objects."); } mLog.log("...service can manipulate SimpleParcelable objects."); } private void checkPersistableBundles(ITestService service) throws TestFailException { mLog.log("Checking that service can repeat and reverse PersistableBundle objects..."); try { { PersistableBundle emptyBundle = new PersistableBundle(); PersistableBundle returned = service.RepeatPersistableBundle(emptyBundle); if (emptyBundle.size() != 0 || returned.size() != 0) { mLog.log(emptyBundle.toString() + " != " + returned.toString()); mLog.logAndThrow("returned empty PersistableBundle object was not equivalent"); } mLog.log("...service can repeat and reverse empty PersistableBundle objects..."); } { final String testBoolKey = new String("testBool"); final String testIntKey = new String("testInt"); final String testNestedIntKey = new String("testNestedInt"); final String testLongKey = new String("testLong"); final String testDoubleKey = new String("testDouble"); final String testStringKey = new String("testString"); final String testBoolArrayKey = new String("testBoolArray"); final String testIntArrayKey = new String("testIntArray"); final String testLongArrayKey = new String("testLongArray"); final String testDoubleArrayKey = new String("testDoubleArray"); final String testStringArrayKey = new String("testStringArray"); final String testPersistableBundleKey = new String("testPersistableBundle"); PersistableBundle nonEmptyBundle = new PersistableBundle(); nonEmptyBundle.putBoolean(testBoolKey, false); nonEmptyBundle.putInt(testIntKey, 33); nonEmptyBundle.putLong(testLongKey, 34359738368L); nonEmptyBundle.putDouble(testDoubleKey, 1.1); nonEmptyBundle.putString(testStringKey, new String("Woot!")); nonEmptyBundle.putBooleanArray(testBoolArrayKey, new boolean[] {true, false, true}); nonEmptyBundle.putIntArray(testIntArrayKey, new int[] {33, 44, 55, 142}); nonEmptyBundle.putLongArray( testLongArrayKey, new long[] {34L, 8371L, 34359738375L}); nonEmptyBundle.putDoubleArray(testDoubleArrayKey, new double[] {2.2, 5.4}); nonEmptyBundle.putStringArray(testStringArrayKey, new String[] {"hello", "world!"}); PersistableBundle testNestedPersistableBundle = new PersistableBundle(); testNestedPersistableBundle.putInt(testNestedIntKey, 345); nonEmptyBundle.putPersistableBundle( testPersistableBundleKey, testNestedPersistableBundle); PersistableBundle returned = service.RepeatPersistableBundle(nonEmptyBundle); if (returned.size() != nonEmptyBundle.size() || returned.getBoolean(testBoolKey) != nonEmptyBundle.getBoolean(testBoolKey) || returned.getInt(testIntKey) != nonEmptyBundle.getInt(testIntKey) || returned.getLong(testLongKey) != nonEmptyBundle.getLong(testLongKey) || returned.getDouble(testDoubleKey) != nonEmptyBundle.getDouble(testDoubleKey) || !returned.getString(testStringKey) .equals(nonEmptyBundle.getString(testStringKey)) || !Arrays.equals(nonEmptyBundle.getBooleanArray(testBoolArrayKey), returned.getBooleanArray(testBoolArrayKey)) || !Arrays.equals(nonEmptyBundle.getIntArray(testIntArrayKey), returned.getIntArray(testIntArrayKey)) || !Arrays.equals(nonEmptyBundle.getLongArray(testLongArrayKey), returned.getLongArray(testLongArrayKey)) || !Arrays.equals(nonEmptyBundle.getDoubleArray(testDoubleArrayKey), returned.getDoubleArray(testDoubleArrayKey)) || !Arrays.equals(nonEmptyBundle.getStringArray(testStringArrayKey), returned.getStringArray(testStringArrayKey))) { PersistableBundle temp = returned.getPersistableBundle(testPersistableBundleKey); if (temp == null || temp.getInt(testNestedIntKey) != testNestedPersistableBundle.getInt(testNestedIntKey)) { mLog.log(nonEmptyBundle.toString() + " != " + returned.toString()); mLog.logAndThrow("returned non-empty PersistableBundle " + "object was not equivalent"); } } mLog.log("...service can repeat and reverse non-empty " + "PersistableBundle objects..."); } { PersistableBundle[] input = new PersistableBundle[3]; PersistableBundle first = new PersistableBundle(); PersistableBundle second = new PersistableBundle(); PersistableBundle third = new PersistableBundle(); final String testIntKey = new String("testInt"); final String testLongKey = new String("testLong"); final String testDoubleKey = new String("testDouble"); first.putInt(testIntKey, 1231); second.putLong(testLongKey, 222222L); third.putDouble(testDoubleKey, 10.8); input[0] = first; input[1] = second; input[2] = third; final int original_input_size = input.length; PersistableBundle[] repeated = new PersistableBundle[input.length]; PersistableBundle[] reversed = service.ReversePersistableBundles(input, repeated); if (input.length != repeated.length || input.length != original_input_size) { mLog.logAndThrow("Repeated list of PersistableBundle objects had " + "wrong length."); } if (input[0].getInt(testIntKey) != repeated[0].getInt(testIntKey) || input[1].getLong(testLongKey) != repeated[1].getLong(testLongKey) || input[2].getDouble(testDoubleKey) != repeated[2].getDouble(testDoubleKey)) { mLog.logAndThrow("Repeated list of PersistableBundle objects did not match."); } if (input.length != reversed.length || input.length != original_input_size) { mLog.logAndThrow("Reversed list of PersistableBundle objects had " + "wrong length."); } if (input[0].getInt(testIntKey) != reversed[2].getInt(testIntKey) || input[1].getLong(testLongKey) != reversed[1].getLong(testLongKey) || input[2].getDouble(testDoubleKey) != reversed[0].getDouble(testDoubleKey)) { mLog.logAndThrow("reversed PersistableBundle objects were not equivalent"); } mLog.log("...service can repeat and reverse arrays of " + "non-empty PersistableBundle objects..."); } } catch (Exception ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to handle PersistableBundle objects."); } mLog.log("...service can manipulate PersistableBundle objects."); } private void checkFileDescriptorPassing(ITestService service) throws TestFailException { mLog.log("Checking that service can receive and return file descriptors..."); try { FileOutputStream fileOutputStream = openFileOutput("test-dummy", Context.MODE_PRIVATE); FileDescriptor descriptor = fileOutputStream.getFD(); FileDescriptor journeyed = service.RepeatFileDescriptor(descriptor); fileOutputStream.close(); FileOutputStream journeyedStream = new FileOutputStream(journeyed); String testData = "FrazzleSnazzleFlimFlamFlibbityGumboChops"; byte[] output = testData.getBytes(); journeyedStream.write(output); journeyedStream.close(); FileInputStream fileInputStream = openFileInput("test-dummy"); byte[] input = new byte[output.length]; if (fileInputStream.read(input) != input.length) { mLog.logAndThrow("Read short count from file"); } if (!Arrays.equals(input, output)) { mLog.logAndThrow("Read incorrect data"); } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to repeat a file descriptor."); } catch (IOException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Exception while operating on temporary file"); } mLog.log("...service can receive and return file descriptors."); } private void checkServiceSpecificExceptions( ITestService service) throws TestFailException { mLog.log("Checking application exceptions..."); for (int i = -1; i < 2; ++i) { try { service.ThrowServiceException(i); } catch (RemoteException ex) { mLog.logAndThrow("Service threw RemoteException: " + ex.toString()); } catch (ServiceSpecificException ex) { if (ex.errorCode != i) { mLog.logAndThrow("Service threw wrong error code: " + i); } } } mLog.log("...application exceptions work"); } private void checkUtf8Strings(ITestService service) throws TestFailException { mLog.log("Checking that service can work with UTF8 strings..."); // Note that Java's underlying encoding is UTF16. final List utf8_queries = Arrays.asList( "typical string", "", "\0\0\0", // Java doesn't handle unicode code points above U+FFFF well. new String(Character.toChars(0x1F701)) + "\u03A9"); try { for (String query : utf8_queries) { String response = service.RepeatUtf8CppString(query); if (!query.equals(response)) { mLog.logAndThrow("Repeat request with '" + query + "'" + " of length " + query.length() + " responded with '" + response + "'" + " of length " + response.length()); } } { String[] input = (String[])utf8_queries.toArray(); String echoed[] = new String[input.length]; String[] reversed = service.ReverseUtf8CppString(input, echoed); if (!Arrays.equals(input, echoed)) { mLog.logAndThrow("Failed to echo utf8 input array back."); } if (input.length != reversed.length) { mLog.logAndThrow("Reversed utf8 array is the wrong size."); } for (int i = 0; i < input.length; ++i) { int j = reversed.length - (1 + i); if (!input[i].equals(reversed[j])) { mLog.logAndThrow( "input[" + i + "] = " + input[i] + " but reversed value = " + reversed[j]); } } } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to handle utf8 strings."); } mLog.log("...UTF8 annotations work."); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAG, "Starting!"); try { init(); ITestService service = getService(); checkPrimitiveRepeat(service); checkArrayReversal(service); checkBinderExchange(service); checkListReversal(service); checkSimpleParcelables(service); checkPersistableBundles(service); checkFileDescriptorPassing(service); checkServiceSpecificExceptions(service); checkUtf8Strings(service); new NullableTests(service, mLog).runTests(); mLog.log(mSuccessSentinel); } catch (TestFailException e) { mLog.log(mFailureSentinel); throw new RuntimeException(e); } finally { if (mLog != null) { mLog.close(); } } } } tests/main.cpp0100644 0000000 0000000 00000000202 13277516055 012404 0ustar000000000 0000000 #include int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } tests/simple_parcelable.cpp0100644 0000000 0000000 00000003077 13277516055 015140 0ustar000000000 0000000 /* * Copyright (C) 2015 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 "tests/simple_parcelable.h" #include #include #include using android::base::StringPrintf; namespace android { namespace aidl { namespace tests { SimpleParcelable::SimpleParcelable(const std::string& name, int32_t number) : name_(name.c_str(), name.length()), number_(number) {} status_t SimpleParcelable::writeToParcel(Parcel* parcel) const { status_t status = parcel->writeString16(name_); if (status != OK) { return status; } status = parcel->writeInt32(number_); return status; } status_t SimpleParcelable::readFromParcel(const Parcel* parcel) { status_t status = parcel->readString16(&name_); if (status != OK) { return status; } return parcel->readInt32(&number_); } std::string SimpleParcelable::toString() const { return StringPrintf("%s(%d)", String8(name_).string(), number_); } } // namespace tests } // namespace aidl } // namespace android tests/simple_parcelable.h0100644 0000000 0000000 00000004355 13277516055 014605 0ustar000000000 0000000 /* * Copyright (C) 2015 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 AIDL_TESTS_SIMPLE_PARCELABLE_H_ #define AIDL_TESTS_SIMPLE_PARCELABLE_H_ #include #include #include #include #include namespace android { namespace aidl { namespace tests { class SimpleParcelable : public Parcelable { public: SimpleParcelable() = default; SimpleParcelable(const std::string& name, int32_t number); virtual ~SimpleParcelable() = default; // Write |this| parcelable to the given |parcel|. Keep in mind that // implementations of writeToParcel must be manually kept in sync // with readFromParcel and the Java equivalent versions of these methods. // // Returns android::OK on success and an appropriate error otherwise. status_t writeToParcel(Parcel* parcel) const override; // Read data from the given |parcel| into |this|. After readFromParcel // completes, |this| should have equivalent state to the object that // wrote itself to the parcel. // // Returns android::OK on success and an appropriate error otherwise. status_t readFromParcel(const Parcel* parcel) override; std::string toString() const; friend bool operator==(const SimpleParcelable& lhs, const SimpleParcelable& rhs) { return (lhs.name_ == rhs.name_) && (lhs.number_ == rhs.number_); } friend bool operator!=(const SimpleParcelable& lhs, const SimpleParcelable& rhs) { return !(lhs == rhs); } private: String16 name_; int32_t number_ = 0; }; // class SimpleParcelable } // namespace tests } // namespace aidl } // namespace android #endif // AIDL_TESTS_SIMPLE_PARCELABLE_H_ tests/test_data.h0100644 0000000 0000000 00000004415 13277516055 013107 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_TESTS_TEST_DATA_H_ #define AIDL_TESTS_TEST_DATA_H_ namespace android { namespace aidl { namespace test_data { namespace example_interface { extern const char kCanonicalName[]; extern const char kJavaOutputPath[]; extern const char kInterfaceDefinition[]; extern const char* kImportedParcelables[]; extern const char* kImportedInterfaces[]; extern const char kExpectedJavaDepsOutput[]; extern const char kExpectedJavaOutput[]; } // namespace example_interface namespace ping_responder { extern const char kCanonicalName[]; extern const char kInterfaceDefinition[]; extern const char kCppOutputPath[]; extern const char kCppParcelableHeader[]; extern const char* kImportedParcelables[]; extern const char* kImportedInterfaces[]; extern const char kGenHeaderDir[]; extern const char kGenInterfaceHeaderPath[]; extern const char kGenClientHeaderPath[]; extern const char kGenServerHeaderPath[]; extern const char kExpectedCppDepsOutput[]; extern const char kExpectedCppOutput[]; extern const char kExpectedIHeaderOutput[]; extern const char kExpectedBpHeaderOutput[]; extern const char kExpectedBnHeaderOutput[]; } // namespace ping_responder namespace string_constants { extern const char kCanonicalName[]; extern const char kInterfaceDefinition[]; extern const char kJavaOutputPath[]; extern const char kExpectedJavaOutput[]; extern const char kCppOutputPath[]; extern const char kGenHeaderDir[]; extern const char kGenInterfaceHeaderPath[]; extern const char kExpectedIHeaderOutput[]; extern const char kExpectedCppOutput[]; } // namespace string_constants } // namespace test_data } // namespace aidl } // namespace android #endif // AIDL_TESTS_TEST_DATA_H_ tests/test_data_example_interface.cpp0100644 0000000 0000000 00000031765 13277516055 017205 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "tests/test_data.h" namespace android { namespace aidl { namespace test_data { namespace example_interface { const char kCanonicalName[] = "android.test.IExampleInterface"; const char kJavaOutputPath[] = "some/path/to/output.java"; const char* kImportedParcelables[] = { "android.foo.ExampleParcelable", nullptr, }; const char* kImportedInterfaces[] = { "android.bar.IAuxInterface", "android.test.IAuxInterface2", nullptr, }; const char kInterfaceDefinition[] = R"( package android.test; import android.foo.ExampleParcelable; import android.test.CompoundParcelable; import android.bar.IAuxInterface; import android.test.IAuxInterface2; interface IExampleInterface { const int EXAMPLE_CONSTANT = 3; boolean isEnabled(); int getState(); String getAddress(); /* Test long comment */ ExampleParcelable[] getParcelables(); // Test short comment boolean setScanMode(int mode, int duration); /* Test long comment */ // And short comment void registerBinder(IAuxInterface foo); IExampleInterface getRecursiveBinder(); int takesAnInterface(in IAuxInterface2 arg); int takesAParcelable(in CompoundParcelable.Subclass1 arg, inout CompoundParcelable.Subclass2 arg2); } )"; const char kExpectedJavaDepsOutput[] = R"(some/path/to/output.java : \ android/test/IExampleInterface.aidl \ ./android/foo/ExampleParcelable.aidl \ ./android/test/CompoundParcelable.aidl \ ./android/bar/IAuxInterface.aidl \ ./android/test/IAuxInterface2.aidl android/test/IExampleInterface.aidl : ./android/foo/ExampleParcelable.aidl : ./android/test/CompoundParcelable.aidl : ./android/bar/IAuxInterface.aidl : ./android/test/IAuxInterface2.aidl : )"; const char kExpectedJavaOutput[] = R"(/* * This file is auto-generated. DO NOT MODIFY. * Original file: android/test/IExampleInterface.aidl */ package android.test; public interface IExampleInterface extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface { private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an android.test.IExampleInterface interface, * generating a proxy if needed. */ public static android.test.IExampleInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) { return ((android.test.IExampleInterface)iin); } return new android.test.IExampleInterface.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_isEnabled: { data.enforceInterface(DESCRIPTOR); boolean _result = this.isEnabled(); reply.writeNoException(); reply.writeInt(((_result)?(1):(0))); return true; } case TRANSACTION_getState: { data.enforceInterface(DESCRIPTOR); int _result = this.getState(); reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_getAddress: { data.enforceInterface(DESCRIPTOR); java.lang.String _result = this.getAddress(); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_getParcelables: { data.enforceInterface(DESCRIPTOR); android.foo.ExampleParcelable[] _result = this.getParcelables(); reply.writeNoException(); reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return true; } case TRANSACTION_setScanMode: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); boolean _result = this.setScanMode(_arg0, _arg1); reply.writeNoException(); reply.writeInt(((_result)?(1):(0))); return true; } case TRANSACTION_registerBinder: { data.enforceInterface(DESCRIPTOR); android.bar.IAuxInterface _arg0; _arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder()); this.registerBinder(_arg0); reply.writeNoException(); return true; } case TRANSACTION_getRecursiveBinder: { data.enforceInterface(DESCRIPTOR); android.test.IExampleInterface _result = this.getRecursiveBinder(); reply.writeNoException(); reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null))); return true; } case TRANSACTION_takesAnInterface: { data.enforceInterface(DESCRIPTOR); android.test.IAuxInterface2 _arg0; _arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder()); int _result = this.takesAnInterface(_arg0); reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_takesAParcelable: { data.enforceInterface(DESCRIPTOR); android.test.CompoundParcelable.Subclass1 _arg0; if ((0!=data.readInt())) { _arg0 = android.test.CompoundParcelable.Subclass1.CREATOR.createFromParcel(data); } else { _arg0 = null; } android.test.CompoundParcelable.Subclass2 _arg1; if ((0!=data.readInt())) { _arg1 = android.test.CompoundParcelable.Subclass2.CREATOR.createFromParcel(data); } else { _arg1 = null; } int _result = this.takesAParcelable(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); if ((_arg1!=null)) { reply.writeInt(1); _arg1.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements android.test.IExampleInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public boolean isEnabled() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int getState() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public java.lang.String getAddress() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } /* Test long comment */ @Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); android.foo.ExampleParcelable[] _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } // Test short comment @Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(mode); _data.writeInt(duration); mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } /* Test long comment */// And short comment @Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null))); mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); android.test.IExampleInterface _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); _reply.readException(); _result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null))); mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); if ((arg!=null)) { _data.writeInt(1); arg.writeToParcel(_data, 0); } else { _data.writeInt(0); } if ((arg2!=null)) { _data.writeInt(1); arg2.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); if ((0!=_reply.readInt())) { arg2.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); } public static final int EXAMPLE_CONSTANT = 3; public boolean isEnabled() throws android.os.RemoteException; public int getState() throws android.os.RemoteException; public java.lang.String getAddress() throws android.os.RemoteException; /* Test long comment */ public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException; // Test short comment public boolean setScanMode(int mode, int duration) throws android.os.RemoteException; /* Test long comment */// And short comment public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException; public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException; public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException; public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException; } )"; } // namespace example_interface } // namespace test_data } // namespace aidl } // namespace android tests/test_data_ping_responder.cpp0100644 0000000 0000000 00000032631 13277516055 016541 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "tests/test_data.h" namespace android { namespace aidl { namespace test_data { namespace ping_responder { const char kCanonicalName[] = "android.os.IPingResponder"; const char kInterfaceDefinition[] = R"( package android.os; import bar.Unused; interface IPingResponder { String Ping(String input); @nullable String NullablePing(@nullable String input); @utf8InCpp String Utf8Ping(@utf8InCpp String input); @utf8InCpp @nullable String NullableUtf8Ping(@utf8InCpp @nullable String input); } )"; const char kCppOutputPath[] = "some/path/to/output.cpp"; const char kCppParcelableHeader[] = "cpp-header-str"; const char* kImportedParcelables[] = { "bar.Unused", nullptr, }; const char* kImportedInterfaces[] = { nullptr, }; const char kGenHeaderDir[] = "some/path"; const char kGenInterfaceHeaderPath[] = "some/path/android/os/IPingResponder.h"; const char kGenClientHeaderPath[] = "some/path/android/os/BpPingResponder.h"; const char kGenServerHeaderPath[] = "some/path/android/os/BnPingResponder.h"; const char kExpectedCppDepsOutput[] = R"(some/path/to/output.cpp : \ android/os/IPingResponder.aidl \ ./bar/Unused.aidl android/os/IPingResponder.aidl : ./bar/Unused.aidl : some/path/android/os/BpPingResponder.h \ some/path/android/os/BnPingResponder.h \ some/path/android/os/IPingResponder.h : \ android/os/IPingResponder.aidl \ ./bar/Unused.aidl )"; const char kExpectedCppOutput[] = R"(#include #include namespace android { namespace os { IMPLEMENT_META_INTERFACE(PingResponder, "android.os.IPingResponder") } // namespace os } // namespace android #include #include namespace android { namespace os { BpPingResponder::BpPingResponder(const ::android::sp<::android::IBinder>& _aidl_impl) : BpInterface(_aidl_impl){ } ::android::binder::Status BpPingResponder::Ping(const ::android::String16& input, ::android::String16* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeString16(input); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IPingResponder::PING, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readString16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpPingResponder::NullablePing(const ::std::unique_ptr<::android::String16>& input, ::std::unique_ptr<::android::String16>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeString16(input); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IPingResponder::NULLABLEPING, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readString16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpPingResponder::Utf8Ping(const ::std::string& input, ::std::string* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(input); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IPingResponder::UTF8PING, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readUtf8FromUtf16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } ::android::binder::Status BpPingResponder::NullableUtf8Ping(const ::std::unique_ptr<::std::string>& input, ::std::unique_ptr<::std::string>* _aidl_return) { ::android::Parcel _aidl_data; ::android::Parcel _aidl_reply; ::android::status_t _aidl_ret_status = ::android::OK; ::android::binder::Status _aidl_status; _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(input); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(IPingResponder::NULLABLEUTF8PING, _aidl_data, &_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } if (!_aidl_status.isOk()) { return _aidl_status; } _aidl_ret_status = _aidl_reply.readUtf8FromUtf16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_error: _aidl_status.setFromStatusT(_aidl_ret_status); return _aidl_status; } } // namespace os } // namespace android #include #include namespace android { namespace os { ::android::status_t BnPingResponder::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) { ::android::status_t _aidl_ret_status = ::android::OK; switch (_aidl_code) { case Call::PING: { ::android::String16 in_input; ::android::String16 _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readString16(&in_input); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(Ping(in_input, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeString16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::NULLABLEPING: { ::std::unique_ptr<::android::String16> in_input; ::std::unique_ptr<::android::String16> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readString16(&in_input); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(NullablePing(in_input, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeString16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::UTF8PING: { ::std::string in_input; ::std::string _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_input); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(Utf8Ping(in_input, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeUtf8AsUtf16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; case Call::NULLABLEUTF8PING: { ::std::unique_ptr<::std::string> in_input; ::std::unique_ptr<::std::string> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_input); if (((_aidl_ret_status) != (::android::OK))) { break; } ::android::binder::Status _aidl_status(NullableUtf8Ping(in_input, &_aidl_return)); _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply); if (((_aidl_ret_status) != (::android::OK))) { break; } if (!_aidl_status.isOk()) { break; } _aidl_ret_status = _aidl_reply->writeUtf8AsUtf16(_aidl_return); if (((_aidl_ret_status) != (::android::OK))) { break; } } break; default: { _aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags); } break; } if (_aidl_ret_status == ::android::UNEXPECTED_NULL) { _aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply); } return _aidl_ret_status; } } // namespace os } // namespace android )"; const char kExpectedIHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_ #define AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_ #include #include #include #include #include #include #include namespace android { namespace os { class IPingResponder : public ::android::IInterface { public: DECLARE_META_INTERFACE(PingResponder) virtual ::android::binder::Status Ping(const ::android::String16& input, ::android::String16* _aidl_return) = 0; virtual ::android::binder::Status NullablePing(const ::std::unique_ptr<::android::String16>& input, ::std::unique_ptr<::android::String16>* _aidl_return) = 0; virtual ::android::binder::Status Utf8Ping(const ::std::string& input, ::std::string* _aidl_return) = 0; virtual ::android::binder::Status NullableUtf8Ping(const ::std::unique_ptr<::std::string>& input, ::std::unique_ptr<::std::string>* _aidl_return) = 0; enum Call { PING = ::android::IBinder::FIRST_CALL_TRANSACTION + 0, NULLABLEPING = ::android::IBinder::FIRST_CALL_TRANSACTION + 1, UTF8PING = ::android::IBinder::FIRST_CALL_TRANSACTION + 2, NULLABLEUTF8PING = ::android::IBinder::FIRST_CALL_TRANSACTION + 3, }; }; // class IPingResponder } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_ )"; const char kExpectedBpHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_ #define AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_ #include #include #include #include namespace android { namespace os { class BpPingResponder : public ::android::BpInterface { public: explicit BpPingResponder(const ::android::sp<::android::IBinder>& _aidl_impl); virtual ~BpPingResponder() = default; ::android::binder::Status Ping(const ::android::String16& input, ::android::String16* _aidl_return) override; ::android::binder::Status NullablePing(const ::std::unique_ptr<::android::String16>& input, ::std::unique_ptr<::android::String16>* _aidl_return) override; ::android::binder::Status Utf8Ping(const ::std::string& input, ::std::string* _aidl_return) override; ::android::binder::Status NullableUtf8Ping(const ::std::unique_ptr<::std::string>& input, ::std::unique_ptr<::std::string>* _aidl_return) override; }; // class BpPingResponder } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_ )"; const char kExpectedBnHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_ #define AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_ #include #include namespace android { namespace os { class BnPingResponder : public ::android::BnInterface { public: ::android::status_t onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags = 0) override; }; // class BnPingResponder } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_ )"; } // namespace ping_responder } // namespace test_data } // namespace aidl } // namespace android tests/test_data_string_constants.cpp0100644 0000000 0000000 00000011763 13277516055 017130 0ustar000000000 0000000 /* * Copyright (C) 2016, 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 "tests/test_data.h" namespace android { namespace aidl { namespace test_data { namespace string_constants { const char kCanonicalName[] = "android.os.IStringConstants"; const char kInterfaceDefinition[] = R"( package android.os; interface IStringConstants { const String EXAMPLE_CONSTANT = "foo"; } )"; const char kJavaOutputPath[] = "some/path/to/output.java"; const char kExpectedJavaOutput[] = R"(/* * This file is auto-generated. DO NOT MODIFY. * Original file: android/os/IStringConstants.aidl */ package android.os; public interface IStringConstants extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements android.os.IStringConstants { private static final java.lang.String DESCRIPTOR = "android.os.IStringConstants"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an android.os.IStringConstants interface, * generating a proxy if needed. */ public static android.os.IStringConstants asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof android.os.IStringConstants))) { return ((android.os.IStringConstants)iin); } return new android.os.IStringConstants.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements android.os.IStringConstants { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } } } public static final String EXAMPLE_CONSTANT = "foo"; } )"; const char kCppOutputPath[] = "some/path/to/output.cpp"; const char kGenHeaderDir[] = "output"; const char kGenInterfaceHeaderPath[] = "output/android/os/IStringConstants.h"; const char kExpectedIHeaderOutput[] = R"(#ifndef AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_ #define AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_ #include #include #include #include #include namespace android { namespace os { class IStringConstants : public ::android::IInterface { public: DECLARE_META_INTERFACE(StringConstants) static const ::android::String16& EXAMPLE_CONSTANT(); }; // class IStringConstants } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_ )"; const char kExpectedCppOutput[] = R"(#include #include namespace android { namespace os { IMPLEMENT_META_INTERFACE(StringConstants, "android.os.IStringConstants") const ::android::String16& IStringConstants::EXAMPLE_CONSTANT() { static const ::android::String16 value("foo"); return value; } } // namespace os } // namespace android #include #include namespace android { namespace os { BpStringConstants::BpStringConstants(const ::android::sp<::android::IBinder>& _aidl_impl) : BpInterface(_aidl_impl){ } } // namespace os } // namespace android #include #include namespace android { namespace os { ::android::status_t BnStringConstants::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) { ::android::status_t _aidl_ret_status = ::android::OK; switch (_aidl_code) { default: { _aidl_ret_status = ::android::BBinder::onTransact(_aidl_code, _aidl_data, _aidl_reply, _aidl_flags); } break; } if (_aidl_ret_status == ::android::UNEXPECTED_NULL) { _aidl_ret_status = ::android::binder::Status::fromExceptionCode(::android::binder::Status::EX_NULL_POINTER).writeToParcel(_aidl_reply); } return _aidl_ret_status; } } // namespace os } // namespace android )"; } // namespace string_constants } // namespace test_data } // namespace aidl } // namespace android tests/test_helpers.h0100644 0000000 0000000 00000004637 13277516055 013646 0ustar000000000 0000000 /* * Copyright (C) 2016 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 #include #include #include #include #include "android/aidl/tests/ITestService.h" namespace android { namespace aidl { namespace tests { namespace client { template bool RepeatPrimitive( const android::sp& service, android::binder::Status(android::aidl::tests::ITestService::*func)(T, V*), U input) { V reply; android::binder::Status status = (*service.*func)(input, &reply); if (!status.isOk() || input != reply) { LOG(ERROR) << "Failed to repeat primitive. status=" << status.toString8() << "."; return false; } return true; } template bool ReverseArray( const android::sp& service, android::binder::Status(android::aidl::tests::ITestService::*func)( const std::vector&, std::vector*, std::vector*), std::vector input) { std::vector actual_reversed; std::vector actual_repeated; android::binder::Status status = (*service.*func)( input, &actual_repeated, &actual_reversed); if (!status.isOk()) { LOG(ERROR) << "Failed to repeat array. status=" << status.toString8() << "."; return false; } if (input != actual_repeated) { LOG(ERROR) << "Repeated version of array did not match"; LOG(ERROR) << "input.size()=" << input.size() << " repeated.size()=" << actual_repeated.size(); return false; } std::reverse(input.begin(), input.end()); if (input != actual_reversed) { LOG(ERROR) << "Reversed version of array did not match"; return false; } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/test_util.cpp0100644 0000000 0000000 00000010370 13277516055 013503 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include #include #include "os.h" #include "tests/test_util.h" using android::base::Split; using android::base::Join; using std::string; using std::vector; using std::cout; using std::endl; using std::distance; namespace android { namespace aidl { namespace test { string CanonicalNameToPath(const char* package_class, const char* extension) { string rel_path{package_class}; for (char& c : rel_path) { if (c == '.') { c = OS_PATH_SEPARATOR; } } rel_path += extension; return rel_path; } void SplitPackageClass(const string& package_class, string* rel_path, string* package, string* class_name) { *package = string{package_class, 0, package_class.rfind('.')}; *class_name = string{package_class, package_class.rfind('.') + 1}; *rel_path = CanonicalNameToPath(package_class.c_str(), ".aidl"); } void PrintDiff(const string& a, const string& b) { const int LEFT = 1; const int UP = 2; const int UP_LEFT = 4; auto a_lines = Split(a, "\n"); auto b_lines = Split(b, "\n"); struct diff_table_entry { size_t longest_common_subsequence_length; int propagation_directions; }; diff_table_entry table[a_lines.size() + 1][b_lines.size() + 1]; for (size_t i = 0; i < a_lines.size() + 1; ++i) { for (size_t j = 0; j < b_lines.size() + 1; ++j) { if (i == 0 || j == 0) { int directions = 0; if (i) { directions |= UP; } if (j) { directions |= LEFT; } table[i][j].longest_common_subsequence_length = 0; table[i][j].propagation_directions = directions; } else if (a_lines[i-1] == b_lines[j-1]) { table[i][j].longest_common_subsequence_length = table[i-1][j-1].longest_common_subsequence_length + 1; table[i][j].propagation_directions = UP_LEFT; } else { size_t length_up = table[i-1][j].longest_common_subsequence_length; size_t length_left = table[i][j-1].longest_common_subsequence_length; int directions = 0; size_t length; if (length_up >= length_left) { directions |= UP; length = length_up; } if (length_left >= length_up) { directions |= LEFT; length = length_left; } table[i][j].longest_common_subsequence_length = length; table[i][j].propagation_directions = directions; } } } size_t i = a_lines.size(); size_t j = b_lines.size(); vector output; while (table[i][j].propagation_directions) { if (table[i][j].propagation_directions & UP_LEFT) { output.push_back(" " + a_lines[i-1]); i--; j--; } else if (table[i][j].propagation_directions & UP) { output.push_back("-" + a_lines[i-1]); i--; } else { output.push_back("+" + b_lines[j-1]); j--; } } int print_mask = 0; bool printed_last = false; size_t line_number = 0; for (auto it = output.crbegin(), frontier = output.crbegin(); it != output.crend(); ++it) { while (frontier != output.crend() && distance(it, frontier) <= 3) { print_mask <<= 1; print_mask &= 0x7f; if ((*frontier)[0] != ' ') { print_mask |= 1; } frontier++; } if ((*it)[0] != '-') { line_number++; } if (print_mask) { if (!printed_last) { cout << "Line: " << line_number << endl; } cout << *it << endl; printed_last = true; } else { printed_last = false; } } } } // namespace test } // namespace android } // namespace aidl tests/test_util.h0100644 0000000 0000000 00000002324 13277516055 013150 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_TESTS_TEST_UTIL_H_ #define AIDL_TESTS_TEST_UTIL_H_ #include namespace android { namespace aidl { namespace test { std::string CanonicalNameToPath(const char* package_class, const char* extension); void SplitPackageClass(const std::string& package_class, std::string* rel_path, std::string* package, std::string* class_name); void PrintDiff(const std::string& a, const std::string& b); } // namespace test } // namespace android } // namespace aidl #endif // AIDL_TESTS_TEST_UTIL_H_ type_cpp.cpp0100644 0000000 0000000 00000052223 13277516055 012153 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "type_cpp.h" #include #include #include #include #include #include "logging.h" using std::cerr; using std::endl; using std::set; using std::string; using std::unique_ptr; using std::vector; using android::base::Split; using android::base::Join; using android::base::StringPrintf; namespace android { namespace aidl { namespace cpp { namespace { const char kNoPackage[] = ""; const char kNoHeader[] = ""; const char kNoValidMethod[] = ""; Type* const kNoArrayType = nullptr; Type* const kNoNullableType = nullptr; bool is_cpp_keyword(const std::string& str) { static const std::vector kCppKeywords{ "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "requires", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq", }; return std::find(kCppKeywords.begin(), kCppKeywords.end(), str) != kCppKeywords.end(); } class VoidType : public Type { public: VoidType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "void", {}, "void", kNoValidMethod, kNoValidMethod) {} virtual ~VoidType() = default; bool CanBeOutParameter() const override { return false; } bool CanWriteToParcel() const override { return false; } }; // class VoidType class CppArrayType : public Type { public: CppArrayType(int kind, // from ValidatableType const std::string& package, const string& underlying_aidl_type, const string& cpp_header, const string& underlying_cpp_type, const string& read_method, const string& write_method, bool is_nullable, const string& src_file_name = "") : Type(kind, package, underlying_aidl_type + "[]", GetHeaders(is_nullable, cpp_header), GetCppType(is_nullable, underlying_cpp_type), read_method, write_method, kNoArrayType, (is_nullable) ? kNoNullableType // All arrays are nullable. : new CppArrayType(kind, package, underlying_aidl_type, cpp_header, underlying_cpp_type, read_method, write_method, true), src_file_name) {} bool CanBeOutParameter() const override { return true; } private: static vector GetHeaders(bool is_nullable, const string& cpp_header) { vector result = {"vector"}; if (is_nullable) { result.push_back("memory"); } if (!cpp_header.empty()) { result.push_back(cpp_header); } return result; } static string GetCppType(bool is_nullable, const string& underlying_cpp_type) { if (is_nullable) return StringPrintf("::std::unique_ptr<::std::vector<%s>>", underlying_cpp_type.c_str()); return StringPrintf("::std::vector<%s>", underlying_cpp_type.c_str()); } DISALLOW_COPY_AND_ASSIGN(CppArrayType); }; // class CppArrayType class PrimitiveType : public Type { public: PrimitiveType(const std::string& aidl_type, const std::string& header, const std::string& cpp_type, const std::string& read_method, const std::string& write_method, const std::string& read_array_method, const std::string& write_array_method) : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, aidl_type, {header}, cpp_type, read_method, write_method, new CppArrayType(ValidatableType::KIND_BUILT_IN, kNoPackage, aidl_type, header, cpp_type, read_array_method, write_array_method, false)) {} virtual ~PrimitiveType() = default; bool IsCppPrimitive() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(PrimitiveType); }; // class PrimitiveType // Unfortunately, bytes in Java are signed. However, most C authors would // say that a byte is not in fact signed. Compromise: customize this otherwise // normal primitive to use signed single bytes, but unsigned byte arrays. class ByteType : public Type { public: ByteType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "byte", {"cstdint"}, "int8_t", "readByte", "writeByte", new CppArrayType(ValidatableType::KIND_BUILT_IN, kNoPackage, "byte", "cstdint", "uint8_t", "readByteVector", "writeByteVector", false)) {} virtual ~ByteType() = default; bool IsCppPrimitive() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(ByteType); }; // class PrimitiveType class BinderType : public Type { public: BinderType(const AidlInterface& interface, const std::string& src_file_name) : BinderType(interface, src_file_name, new BinderType(interface, src_file_name, kNoNullableType, "readNullableStrongBinder"), "readStrongBinder") {} virtual ~BinderType() = default; string WriteCast(const string& val) const override { return write_cast_ + "(" + val + ")"; } private: BinderType(const AidlInterface& interface, const std::string& src_file_name, Type* nullable_type, const std::string& read) : Type(ValidatableType::KIND_GENERATED, interface.GetPackage(), interface.GetName(), {GetCppHeader(interface)}, GetCppName(interface), read, "writeStrongBinder", kNoArrayType, nullable_type, src_file_name, interface.GetLine()), write_cast_(GetRawCppName(interface) + "::asBinder") {} static string GetCppName(const AidlInterface& interface) { return "::android::sp<" + GetRawCppName(interface) + ">"; } static string GetRawCppName(const AidlInterface& interface) { vector name = interface.GetSplitPackage(); string ret; name.push_back(interface.GetName()); for (const auto& term : name) { ret += "::" + term; } return ret; } static string GetCppHeader(const AidlInterface& interface) { vector 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, 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()) {} virtual ~NullableParcelableType() = default; bool CanBeOutParameter() const override { return true; } private: static string GetCppName(const AidlParcelable& parcelable) { return "::std::unique_ptr<::" + Join(parcelable.GetSplitPackage(), "::") + "::" + parcelable.GetCppName() + ">"; } }; class ParcelableType : public Type { public: ParcelableType(const AidlParcelable& parcelable, 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), "readParcelableVector", "writeParcelableVector", false, src_file_name), new NullableParcelableType(parcelable, src_file_name), src_file_name, parcelable.GetLine()) {} virtual ~ParcelableType() = default; bool CanBeOutParameter() const override { return true; } private: static string GetCppName(const AidlParcelable& parcelable) { return "::" + Join(parcelable.GetSplitPackage(), "::") + "::" + parcelable.GetCppName(); } }; class NullableMap : public Type { public: NullableMap() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "Map", {"binder/Map.h", "binder/Value.h"}, "::std::unique_ptr<::android::binder::Map>", "readNullableMap", "writeNullableMap") {} virtual ~NullableMap() = default; bool CanBeOutParameter() const override { return true; } }; class MapType : public Type { public: MapType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "Map", {"binder/Map.h","binder/Value.h"}, "::android::binder::Map", "readMap", "writeMap", kNoArrayType, new NullableMap() ) {} virtual ~MapType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(MapType); }; // class MapType class NullableStringListType : public Type { public: NullableStringListType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<" + string(kStringCanonicalName) + ">", {"utils/String16.h", "memory", "vector"}, "::std::unique_ptr<::std::vector>>", "readString16Vector", "writeString16Vector") {} virtual ~NullableStringListType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(NullableStringListType); }; // class NullableStringListType class StringListType : public Type { public: StringListType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<" + string(kStringCanonicalName) + ">", {"utils/String16.h", "vector"}, "::std::vector<::android::String16>", "readString16Vector", "writeString16Vector", kNoArrayType, new NullableStringListType()) {} virtual ~StringListType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(StringListType); }; // class StringListType class NullableUtf8InCppStringListType : public Type { public: NullableUtf8InCppStringListType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<" + string(kUtf8InCppStringCanonicalName) + ">", {"memory", "string", "vector"}, "::std::unique_ptr<::std::vector>>", "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector") {} virtual ~NullableUtf8InCppStringListType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(NullableUtf8InCppStringListType); }; // class NullableUtf8InCppStringListType class Utf8InCppStringListType : public Type { public: Utf8InCppStringListType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List<" + string(kUtf8InCppStringCanonicalName) + ">", {"string", "vector"}, "::std::vector<::std::string>", "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector", kNoArrayType, new NullableUtf8InCppStringListType()) {} virtual ~Utf8InCppStringListType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(Utf8InCppStringListType); }; // class Utf8InCppStringListType class NullableBinderListType : public Type { public: NullableBinderListType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List", {"binder/IBinder.h", "vector"}, "::std::unique_ptr<::std::vector<::android::sp<::android::IBinder>>>", "readStrongBinderVector", "writeStrongBinderVector") {} virtual ~NullableBinderListType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(NullableBinderListType); }; // class NullableBinderListType class BinderListType : public Type { public: BinderListType() : Type(ValidatableType::KIND_BUILT_IN, "java.util", "List", {"binder/IBinder.h", "vector"}, "::std::vector<::android::sp<::android::IBinder>>", "readStrongBinderVector", "writeStrongBinderVector", kNoArrayType, new NullableBinderListType()) {} virtual ~BinderListType() = default; bool CanBeOutParameter() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(BinderListType); }; // class BinderListType } // namespace Type::Type(int kind, const std::string& package, const std::string& aidl_type, const vector& headers, const string& cpp_type, const string& read_method, const string& write_method, Type* array_type, Type* nullable_type, const string& src_file_name, int line) : ValidatableType(kind, package, aidl_type, src_file_name, line), headers_(headers), aidl_type_(aidl_type), cpp_type_(cpp_type), parcel_read_method_(read_method), parcel_write_method_(write_method), array_type_(array_type), nullable_type_(nullable_type) {} bool Type::CanWriteToParcel() const { return true; } void TypeNamespace::Init() { Add(new ByteType()); Add(new PrimitiveType( "int", "cstdint", "int32_t", "readInt32", "writeInt32", "readInt32Vector", "writeInt32Vector")); Add(new PrimitiveType( "long", "cstdint", "int64_t", "readInt64", "writeInt64", "readInt64Vector", "writeInt64Vector")); Add(new PrimitiveType( "float", kNoHeader, "float", "readFloat", "writeFloat", "readFloatVector", "writeFloatVector")); Add(new PrimitiveType( "double", kNoHeader, "double", "readDouble", "writeDouble", "readDoubleVector", "writeDoubleVector")); Add(new PrimitiveType( "boolean", kNoHeader, "bool", "readBool", "writeBool", "readBoolVector", "writeBoolVector")); // C++11 defines the char16_t type as a built in for Unicode characters. Add(new PrimitiveType( "char", kNoHeader, "char16_t", "readChar", "writeChar", "readCharVector", "writeCharVector")); Type* string_array_type = new CppArrayType( ValidatableType::KIND_BUILT_IN, "java.lang", "String", "utils/String16.h", "::android::String16", "readString16Vector", "writeString16Vector", false); Type* nullable_string_type = new Type(ValidatableType::KIND_BUILT_IN, "java.lang", "String", {"memory", "utils/String16.h"}, "::std::unique_ptr<::android::String16>", "readString16", "writeString16"); string_type_ = new Type(ValidatableType::KIND_BUILT_IN, "java.lang", "String", {"utils/String16.h"}, "::android::String16", "readString16", "writeString16", string_array_type, nullable_string_type); Add(string_type_); using ::android::aidl::kAidlReservedTypePackage; using ::android::aidl::kUtf8InCppStringClass; // This type is a Utf16 string in the parcel, but deserializes to // a std::string in Utf8 format when we use it in C++. Type* cpp_utf8_string_array = new CppArrayType( ValidatableType::KIND_BUILT_IN, kAidlReservedTypePackage, kUtf8InCppStringClass, "string", "::std::string", "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector", false); Type* nullable_cpp_utf8_string_type = new Type( ValidatableType::KIND_BUILT_IN, kAidlReservedTypePackage, kUtf8InCppStringClass, {"string", "memory"}, "::std::unique_ptr<::std::string>", "readUtf8FromUtf16", "writeUtf8AsUtf16"); Add(new Type( ValidatableType::KIND_BUILT_IN, kAidlReservedTypePackage, kUtf8InCppStringClass, {"string"}, "::std::string", "readUtf8FromUtf16", "writeUtf8AsUtf16", cpp_utf8_string_array, nullable_cpp_utf8_string_type)); Type* nullable_ibinder = new Type( ValidatableType::KIND_BUILT_IN, "android.os", "IBinder", {"binder/IBinder.h"}, "::android::sp<::android::IBinder>", "readNullableStrongBinder", "writeStrongBinder"); ibinder_type_ = new Type( ValidatableType::KIND_BUILT_IN, "android.os", "IBinder", {"binder/IBinder.h"}, "::android::sp<::android::IBinder>", "readStrongBinder", "writeStrongBinder", kNoArrayType, nullable_ibinder); Add(ibinder_type_); Add(new MapType()); Add(new BinderListType()); Add(new StringListType()); Add(new Utf8InCppStringListType()); Type* fd_vector_type = new CppArrayType( ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor", "android-base/unique_fd.h", "::android::base::unique_fd", "readUniqueFileDescriptorVector", "writeUniqueFileDescriptorVector", false); Add(new Type( ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor", {"android-base/unique_fd.h"}, "::android::base::unique_fd", "readUniqueFileDescriptor", "writeUniqueFileDescriptor", fd_vector_type)); void_type_ = new class VoidType(); Add(void_type_); } bool TypeNamespace::AddParcelableType(const AidlParcelable& p, const string& filename) { if (p.GetCppHeader().empty()) { LOG(ERROR) << "Parcelable " << p.GetCanonicalName() << " has no C++ header defined."; return false; } Add(new ParcelableType(p, filename)); return true; } bool TypeNamespace::AddBinderType(const AidlInterface& b, const string& file_name) { Add(new BinderType(b, file_name)); return true; } bool TypeNamespace::AddListType(const std::string& type_name) { const Type* contained_type = FindTypeByCanonicalName(type_name); if (!contained_type) { LOG(ERROR) << "Cannot create List<" << type_name << "> because contained " "type cannot be found or is invalid."; return false; } if (contained_type->IsCppPrimitive()) { LOG(ERROR) << "Cannot create List<" << type_name << "> because contained " "type is a primitive in Java and Java List cannot hold " "primitives."; return false; } if (contained_type->CanonicalName() == kStringCanonicalName || contained_type->CanonicalName() == kUtf8InCppStringCanonicalName || contained_type == IBinderType()) { return true; } // TODO Support lists of parcelables b/23600712 LOG(ERROR) << "aidl-cpp does not yet support List<" << type_name << ">"; return false; } bool TypeNamespace::AddMapType(const std::string& /* key_type_name */, const std::string& /* value_type_name */) { // TODO Support list types b/25242025 LOG(ERROR) << "aidl does not implement support for typed maps!"; return false; } bool TypeNamespace::IsValidPackage(const string& package) const { if (package.empty()) { return false; } auto pieces = Split(package, "."); for (const string& piece : pieces) { if (is_cpp_keyword(piece)) { return false; } } return true; } const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index, const std::string& filename, const AidlInterface& interface) 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); // check that the name doesn't match a keyword if (is_cpp_keyword(a.GetName().c_str())) { cerr << error_prefix << "Argument name is a C++ keyword" << endl; return nullptr; } return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, filename, interface); } } // namespace cpp } // namespace aidl } // namespace android type_cpp.h0100644 0000000 0000000 00000007674 13277516055 011632 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_TYPE_CPP_H_ #define AIDL_TYPE_CPP_H_ #include #include #include #include #include #include "type_namespace.h" namespace android { namespace aidl { namespace cpp { class Type : public ValidatableType { public: Type(int kind, // from ValidatableType const std::string& package, const std::string& aidl_type, const std::vector& header, const std::string& cpp_type, const std::string& read_method, const std::string& write_method, Type* array_type = nullptr, Type* nullable_type = nullptr, const std::string& src_file_name = "", int line = -1); virtual ~Type() = default; // overrides of ValidatableType bool CanBeOutParameter() const override { return false; } bool CanWriteToParcel() const override; const Type* ArrayType() const override { return array_type_.get(); } const Type* NullableType() const override { return nullable_type_.get(); } std::string CppType() const { return cpp_type_; } const std::string& ReadFromParcelMethod() const { return parcel_read_method_; } const std::string& WriteToParcelMethod() const { return parcel_write_method_; } void GetHeaders(std::set* headers) const { for (const std::string& header : headers_) { if (!header.empty()) { headers->insert(header); } } } virtual bool IsCppPrimitive() const { return false; } virtual std::string WriteCast(const std::string& value) const { return value; } private: // |headers| are the headers we must include to use this type const std::vector headers_; // |aidl_type| is what we find in the yacc generated AST (e.g. "int"). const std::string aidl_type_; // |cpp_type| is what we use in the generated C++ code (e.g. "int32_t"). const std::string cpp_type_; const std::string parcel_read_method_; const std::string parcel_write_method_; const std::unique_ptr array_type_; const std::unique_ptr nullable_type_; DISALLOW_COPY_AND_ASSIGN(Type); }; // class Type class TypeNamespace : public ::android::aidl::LanguageTypeNamespace { public: TypeNamespace() = default; virtual ~TypeNamespace() = default; void Init() override; bool AddParcelableType(const AidlParcelable& p, const std::string& filename) override; bool AddBinderType(const AidlInterface& b, const std::string& filename) override; bool AddListType(const std::string& type_name) override; bool AddMapType(const std::string& key_type_name, 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 Type* VoidType() const { return void_type_; } const Type* IBinderType() const { return ibinder_type_; } private: Type* void_type_ = nullptr; Type* string_type_ = nullptr; Type* ibinder_type_ = nullptr; DISALLOW_COPY_AND_ASSIGN(TypeNamespace); }; // class TypeNamespace } // namespace cpp } // namespace aidl } // namespace android #endif // AIDL_TYPE_NAMESPACE_CPP_H_ type_cpp_unittest.cpp0100644 0000000 0000000 00000004034 13277516055 014107 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include #include "type_cpp.h" using std::string; using std::unique_ptr; namespace android { namespace aidl { namespace cpp { namespace { string kParcelableDotName = "Outer.Inner"; string kParcelableColonName = "Outer::Inner"; } // namespace class CppTypeNamespaceTest : public ::testing::Test { protected: void SetUp() override { types_.Init(); } TypeNamespace types_; }; TEST_F(CppTypeNamespaceTest, HasSomeBasicTypes) { EXPECT_TRUE(types_.HasTypeByCanonicalName("byte")); EXPECT_TRUE(types_.HasTypeByCanonicalName("int")); EXPECT_TRUE(types_.HasTypeByCanonicalName("long")); EXPECT_TRUE(types_.HasTypeByCanonicalName("float")); EXPECT_TRUE(types_.HasTypeByCanonicalName("double")); EXPECT_TRUE(types_.HasTypeByCanonicalName("boolean")); EXPECT_TRUE(types_.HasTypeByCanonicalName("char")); EXPECT_TRUE(types_.HasTypeByCanonicalName("String")); } TEST_F(CppTypeNamespaceTest, SupportsListString) { EXPECT_TRUE( types_.HasTypeByCanonicalName("java.util.List")); } TEST_F(CppTypeNamespaceTest, SupportsNestedParcelableClass) { unique_ptr parcelable( new AidlParcelable(new AidlQualifiedName(kParcelableDotName, ""), 0, {"a", "goog"})); EXPECT_EQ(parcelable->GetCppName(), kParcelableColonName); } } // namespace cpp } // namespace android } // namespace aidl type_java.cpp0100644 0000000 0000000 00000107012 13277516055 012307 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "type_java.h" #include #include #include "aidl_language.h" #include "logging.h" using std::string; using android::base::Split; using android::base::Join; using android::base::Trim; namespace android { namespace aidl { namespace java { Expression* NULL_VALUE; Expression* THIS_VALUE; Expression* SUPER_VALUE; Expression* TRUE_VALUE; Expression* FALSE_VALUE; // ================================================================ Type::Type(const JavaTypeNamespace* types, const string& name, int kind, bool canWriteToParcel, bool canBeOut) : Type(types, "", name, kind, canWriteToParcel, canBeOut, "", -1) {} Type::Type(const JavaTypeNamespace* types, const string& package, const string& name, int kind, bool canWriteToParcel, bool canBeOut, const string& declFile, int declLine) : ValidatableType(kind, package, name, declFile, declLine), m_types(types), m_javaType((package.empty()) ? name : package + "." + name), m_canWriteToParcel(canWriteToParcel), m_canBeOut(canBeOut) { } string Type::CreatorName() const { return ""; } string Type::InstantiableName() const { return JavaType(); } void Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn", __FILE__, __LINE__, m_javaType.c_str()); addTo->Add(new LiteralExpression("/* WriteToParcel error " + m_javaType + " */")); } void Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__, __LINE__, m_javaType.c_str()); addTo->Add(new LiteralExpression("/* CreateFromParcel error " + m_javaType + " */")); } void Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n", __FILE__, __LINE__, m_javaType.c_str()); addTo->Add(new LiteralExpression("/* ReadFromParcel error " + m_javaType + " */")); } Expression* Type::BuildWriteToParcelFlags(int flags) const { if (flags == 0) { return new LiteralExpression("0"); } if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0) { return new FieldVariable(m_types->ParcelableInterfaceType(), "PARCELABLE_WRITE_RETURN_VALUE"); } return new LiteralExpression("0"); } // ================================================================ BasicType::BasicType(const JavaTypeNamespace* types, const string& name, const string& marshallParcel, const string& unmarshallParcel, const string& writeArrayParcel, const string& createArrayParcel, const string& readArrayParcel) : Type(types, name, ValidatableType::KIND_BUILT_IN, true, false), m_marshallParcel(marshallParcel), m_unmarshallParcel(unmarshallParcel) { m_array_type.reset(new BasicArrayType(types, name, writeArrayParcel, createArrayParcel, readArrayParcel)); } void BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v)); } void BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel))); } BasicArrayType::BasicArrayType(const JavaTypeNamespace* types, const string& name, const string& writeArrayParcel, const string& createArrayParcel, const string& readArrayParcel) : Type(types, name, ValidatableType::KIND_BUILT_IN, true, true), m_writeArrayParcel(writeArrayParcel), m_createArrayParcel(createArrayParcel), m_readArrayParcel(readArrayParcel) {} void BasicArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v)); } void BasicArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel))); } void BasicArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v)); } // ================================================================ FileDescriptorType::FileDescriptorType(const JavaTypeNamespace* types) : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN, true, false) { m_array_type.reset(new FileDescriptorArrayType(types)); } void FileDescriptorType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeRawFileDescriptor", 1, v)); } void FileDescriptorType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "readRawFileDescriptor"))); } FileDescriptorArrayType::FileDescriptorArrayType(const JavaTypeNamespace* types) : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN, true, true) {} void FileDescriptorArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeRawFileDescriptorArray", 1, v)); } void FileDescriptorArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "createRawFileDescriptorArray"))); } void FileDescriptorArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new MethodCall(parcel, "readRawFileDescriptorArray", 1, v)); } // ================================================================ BooleanType::BooleanType(const JavaTypeNamespace* types) : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true, false) { m_array_type.reset(new BooleanArrayType(types)); } void BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall( parcel, "writeInt", 1, new Ternary(v, new LiteralExpression("1"), new LiteralExpression("0")))); } void BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add( new Assignment(v, new Comparison(new LiteralExpression("0"), "!=", new MethodCall(parcel, "readInt")))); } BooleanArrayType::BooleanArrayType(const JavaTypeNamespace* types) : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true, true) {} void BooleanArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v)); } void BooleanArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray"))); } void BooleanArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v)); } // ================================================================ CharType::CharType(const JavaTypeNamespace* types) : Type(types, "char", ValidatableType::KIND_BUILT_IN, true, false) { m_array_type.reset(new CharArrayType(types)); } void CharType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add( new MethodCall(parcel, "writeInt", 1, new Cast(m_types->IntType(), v))); } void CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this)); } CharArrayType::CharArrayType(const JavaTypeNamespace* types) : Type(types, "char", ValidatableType::KIND_BUILT_IN, true, true) {} void CharArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v)); } void CharArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray"))); } void CharArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new MethodCall(parcel, "readCharArray", 1, v)); } // ================================================================ StringType::StringType(const JavaTypeNamespace* types, const std::string& package, const std::string& class_name) : Type(types, package, class_name, ValidatableType::KIND_BUILT_IN, true, false) { m_array_type.reset(new StringArrayType(types)); } string StringType::CreatorName() const { return "android.os.Parcel.STRING_CREATOR"; } void StringType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeString", 1, v)); } void StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "readString"))); } StringArrayType::StringArrayType(const JavaTypeNamespace* types) : Type(types, "java.lang", "String", ValidatableType::KIND_BUILT_IN, true, true) {} string StringArrayType::CreatorName() const { return "android.os.Parcel.STRING_CREATOR"; } void StringArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v)); } void StringArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray"))); } void StringArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new MethodCall(parcel, "readStringArray", 1, v)); } // ================================================================ CharSequenceType::CharSequenceType(const JavaTypeNamespace* types) : Type(types, "java.lang", "CharSequence", ValidatableType::KIND_BUILT_IN, true, false) {} string CharSequenceType::CreatorName() const { return "android.os.Parcel.STRING_CREATOR"; } void CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { // if (v != null) { // parcel.writeInt(1); // v.writeToParcel(parcel); // } else { // parcel.writeInt(0); // } IfStatement* elsepart = new IfStatement(); elsepart->statements->Add( new MethodCall(parcel, "writeInt", 1, new LiteralExpression("0"))); IfStatement* ifpart = new IfStatement; ifpart->expression = new Comparison(v, "!=", NULL_VALUE); ifpart->elseif = elsepart; ifpart->statements->Add( new MethodCall(parcel, "writeInt", 1, new LiteralExpression("1"))); ifpart->statements->Add(new MethodCall(m_types->TextUtilsType(), "writeToParcel", 3, v, parcel, BuildWriteToParcelFlags(flags))); addTo->Add(ifpart); } void CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { // if (0 != parcel.readInt()) { // v = TextUtils.createFromParcel(parcel) // } else { // v = null; // } IfStatement* elsepart = new IfStatement(); elsepart->statements->Add(new Assignment(v, NULL_VALUE)); IfStatement* ifpart = new IfStatement(); ifpart->expression = new Comparison(new LiteralExpression("0"), "!=", new MethodCall(parcel, "readInt")); ifpart->elseif = elsepart; ifpart->statements->Add(new Assignment( v, new MethodCall(m_types->TextUtilsType(), "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel))); addTo->Add(ifpart); } // ================================================================ RemoteExceptionType::RemoteExceptionType(const JavaTypeNamespace* types) : Type(types, "android.os", "RemoteException", ValidatableType::KIND_BUILT_IN, false, false) {} void RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ RuntimeExceptionType::RuntimeExceptionType(const JavaTypeNamespace* types) : Type(types, "java.lang", "RuntimeException", ValidatableType::KIND_BUILT_IN, false, false) {} void RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ IBinderType::IBinderType(const JavaTypeNamespace* types) : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN, true, false) { m_array_type.reset(new IBinderArrayType(types)); } void IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v)); } void IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder"))); } IBinderArrayType::IBinderArrayType(const JavaTypeNamespace* types) : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN, true, true) {} void IBinderArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v)); } void IBinderArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray"))); } void IBinderArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v)); } // ================================================================ IInterfaceType::IInterfaceType(const JavaTypeNamespace* types) : Type(types, "android.os", "IInterface", ValidatableType::KIND_BUILT_IN, false, false) {} void IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ BinderType::BinderType(const JavaTypeNamespace* types) : Type(types, "android.os", "Binder", ValidatableType::KIND_BUILT_IN, false, false) {} void BinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ BinderProxyType::BinderProxyType(const JavaTypeNamespace* types) : Type(types, "android.os", "BinderProxy", ValidatableType::KIND_BUILT_IN, false, false) {} void BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ ParcelType::ParcelType(const JavaTypeNamespace* types) : Type(types, "android.os", "Parcel", ValidatableType::KIND_BUILT_IN, false, false) {} void ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ ParcelableInterfaceType::ParcelableInterfaceType(const JavaTypeNamespace* types) : Type(types, "android.os", "Parcelable", ValidatableType::KIND_BUILT_IN, false, false) {} void ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } void ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__); } // ================================================================ MapType::MapType(const JavaTypeNamespace* types) : Type(types, "java.util", "Map", ValidatableType::KIND_BUILT_IN, true, true) {} void MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeMap", 1, v)); } static void EnsureClassLoader(StatementBlock* addTo, Variable** cl, const JavaTypeNamespace* types) { // We don't want to look up the class loader once for every // collection argument, so ensure we do it at most once per method. if (*cl == NULL) { *cl = new Variable(types->ClassLoaderType(), "cl"); addTo->Add(new VariableDeclaration( *cl, new LiteralExpression("this.getClass().getClassLoader()"), types->ClassLoaderType())); } } void MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const { EnsureClassLoader(addTo, cl, m_types); addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl))); } void MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const { EnsureClassLoader(addTo, cl, m_types); addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl)); } // ================================================================ ListType::ListType(const JavaTypeNamespace* types) : Type(types, "java.util", "List", ValidatableType::KIND_BUILT_IN, true, true) {} string ListType::InstantiableName() const { return "java.util.ArrayList"; } void ListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeList", 1, v)); } void ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const { EnsureClassLoader(addTo, cl, m_types); addTo->Add( new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl))); } void ListType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const { EnsureClassLoader(addTo, cl, m_types); addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl)); } // ================================================================ UserDataType::UserDataType(const JavaTypeNamespace* types, const string& package, const string& name, bool builtIn, bool canWriteToParcel, const string& declFile, int declLine) : Type(types, package, name, builtIn ? ValidatableType::KIND_BUILT_IN : ValidatableType::KIND_PARCELABLE, canWriteToParcel, true, declFile, declLine) { m_array_type.reset(new UserDataArrayType(types, package, name, builtIn, canWriteToParcel, declFile, declLine)); } string UserDataType::CreatorName() const { return JavaType() + ".CREATOR"; } void UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { // if (v != null) { // parcel.writeInt(1); // v.writeToParcel(parcel); // } else { // parcel.writeInt(0); // } IfStatement* elsepart = new IfStatement(); elsepart->statements->Add( new MethodCall(parcel, "writeInt", 1, new LiteralExpression("0"))); IfStatement* ifpart = new IfStatement; ifpart->expression = new Comparison(v, "!=", NULL_VALUE); ifpart->elseif = elsepart; ifpart->statements->Add( new MethodCall(parcel, "writeInt", 1, new LiteralExpression("1"))); ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2, parcel, BuildWriteToParcelFlags(flags))); addTo->Add(ifpart); } void UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { // if (0 != parcel.readInt()) { // v = CLASS.CREATOR.createFromParcel(parcel) // } else { // v = null; // } IfStatement* elsepart = new IfStatement(); elsepart->statements->Add(new Assignment(v, NULL_VALUE)); IfStatement* ifpart = new IfStatement(); ifpart->expression = new Comparison(new LiteralExpression("0"), "!=", new MethodCall(parcel, "readInt")); ifpart->elseif = elsepart; ifpart->statements->Add(new Assignment( v, new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel))); addTo->Add(ifpart); } void UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { // TODO: really, we don't need to have this extra check, but we // don't have two separate marshalling code paths // if (0 != parcel.readInt()) { // v.readFromParcel(parcel) // } IfStatement* ifpart = new IfStatement(); ifpart->expression = new Comparison(new LiteralExpression("0"), "!=", new MethodCall(parcel, "readInt")); ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel)); addTo->Add(ifpart); } UserDataArrayType::UserDataArrayType(const JavaTypeNamespace* types, const string& package, const string& name, bool builtIn, bool canWriteToParcel, const string& declFile, int declLine) : Type(types, package, name, builtIn ? ValidatableType::KIND_BUILT_IN : ValidatableType::KIND_PARCELABLE, canWriteToParcel, true, declFile, declLine) {} string UserDataArrayType::CreatorName() const { return JavaType() + ".CREATOR"; } void UserDataArrayType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v, BuildWriteToParcelFlags(flags))); } void UserDataArrayType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { string creator = v->type->JavaType() + ".CREATOR"; addTo->Add(new Assignment(v, new MethodCall(parcel, "createTypedArray", 1, new LiteralExpression(creator)))); } void UserDataArrayType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { string creator = v->type->JavaType() + ".CREATOR"; addTo->Add(new MethodCall(parcel, "readTypedArray", 2, v, new LiteralExpression(creator))); } // ================================================================ InterfaceType::InterfaceType(const JavaTypeNamespace* types, const string& package, const string& name, bool builtIn, bool oneway, const string& declFile, int declLine, const Type* stub, const Type* proxy) : Type(types, package, name, builtIn ? ValidatableType::KIND_BUILT_IN : ValidatableType::KIND_INTERFACE, true, false, declFile, declLine), m_oneway(oneway), stub_(stub), proxy_(proxy) {} bool InterfaceType::OneWay() const { return m_oneway; } void InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { // parcel.writeStrongBinder(v != null ? v.asBinder() : null); addTo->Add( new MethodCall(parcel, "writeStrongBinder", 1, new Ternary(new Comparison(v, "!=", NULL_VALUE), new MethodCall(v, "asBinder"), NULL_VALUE))); } void InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { // v = Interface.asInterface(parcel.readStrongBinder()); addTo->Add(new Assignment( v, new MethodCall(stub_, "asInterface", 1, new MethodCall(parcel, "readStrongBinder")))); } // ================================================================ GenericListType::GenericListType(const JavaTypeNamespace* types, const Type* contained_type) : Type(types, "java.util", "List<" + contained_type->CanonicalName() + ">", ValidatableType::KIND_BUILT_IN, true, true), m_contained_type(contained_type), m_creator(contained_type->CreatorName()) {} string GenericListType::CreatorName() const { return "android.os.Parcel.arrayListCreator"; } string GenericListType::InstantiableName() const { return "java.util.ArrayList<" + m_contained_type->JavaType() + ">"; } void GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const { if (m_creator == m_types->StringType()->CreatorName()) { addTo->Add(new MethodCall(parcel, "writeStringList", 1, v)); } else if (m_creator == m_types->IBinderType()->CreatorName()) { addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v)); } else { // parcel.writeTypedListXX(arg); addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v)); } } void GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { if (m_creator == m_types->StringType()->CreatorName()) { addTo->Add( new Assignment(v, new MethodCall(parcel, "createStringArrayList", 0))); } else if (m_creator == m_types->IBinderType()->CreatorName()) { addTo->Add( new Assignment(v, new MethodCall(parcel, "createBinderArrayList", 0))); } else { // v = _data.readTypedArrayList(XXX.creator); addTo->Add( new Assignment(v, new MethodCall(parcel, "createTypedArrayList", 1, new LiteralExpression(m_creator)))); } } void GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**) const { if (m_creator == m_types->StringType()->CreatorName()) { addTo->Add(new MethodCall(parcel, "readStringList", 1, v)); } else if (m_creator == m_types->IBinderType()->CreatorName()) { addTo->Add(new MethodCall(parcel, "readBinderList", 1, v)); } else { // v = _data.readTypedList(v, XXX.creator); addTo->Add(new MethodCall(parcel, "readTypedList", 2, v, new LiteralExpression(m_creator))); } } // ================================================================ ClassLoaderType::ClassLoaderType(const JavaTypeNamespace* types) : Type(types, "java.lang", "ClassLoader", ValidatableType::KIND_BUILT_IN, false, false) {} // ================================================================ void JavaTypeNamespace::Init() { Add(new BasicType(this, "void", "XXX", "XXX", "XXX", "XXX", "XXX")); m_bool_type = new BooleanType(this); Add(m_bool_type); Add(new BasicType(this, "byte", "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray")); Add(new CharType(this)); m_int_type = new BasicType(this, "int", "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray"); Add(m_int_type); Add(new BasicType(this, "long", "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray")); Add(new BasicType(this, "float", "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray")); Add(new BasicType(this, "double", "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray")); m_string_type = new class StringType(this, "java.lang", "String"); Add(m_string_type); Add(new class StringType(this, ::android::aidl::kAidlReservedTypePackage, ::android::aidl::kUtf8InCppStringClass)); Add(new Type(this, "java.lang", "Object", ValidatableType::KIND_BUILT_IN, false, false)); Add(new FileDescriptorType(this)); Add(new CharSequenceType(this)); Add(new MapType(this)); Add(new ListType(this)); m_text_utils_type = new Type(this, "android.text", "TextUtils", ValidatableType::KIND_BUILT_IN, false, false); Add(m_text_utils_type); m_remote_exception_type = new class RemoteExceptionType(this); Add(m_remote_exception_type); m_runtime_exception_type = new class RuntimeExceptionType(this); Add(m_runtime_exception_type); m_ibinder_type = new class IBinderType(this); Add(m_ibinder_type); m_iinterface_type = new class IInterfaceType(this); Add(m_iinterface_type); m_binder_native_type = new class BinderType(this); Add(m_binder_native_type); m_binder_proxy_type = new class BinderProxyType(this); Add(m_binder_proxy_type); m_parcel_type = new class ParcelType(this); Add(m_parcel_type); m_parcelable_interface_type = new class ParcelableInterfaceType(this); Add(m_parcelable_interface_type); m_context_type = new class Type(this, "android.content", "Context", ValidatableType::KIND_BUILT_IN, false, false); Add(m_context_type); m_classloader_type = new class ClassLoaderType(this); Add(m_classloader_type); NULL_VALUE = new LiteralExpression("null"); THIS_VALUE = new LiteralExpression("this"); SUPER_VALUE = new LiteralExpression("super"); TRUE_VALUE = new LiteralExpression("true"); FALSE_VALUE = new LiteralExpression("false"); } bool JavaTypeNamespace::AddParcelableType(const AidlParcelable& p, const std::string& filename) { Type* type = new UserDataType(this, p.GetPackage(), p.GetName(), false, true, filename, p.GetLine()); return Add(type); } bool JavaTypeNamespace::AddBinderType(const AidlInterface& b, const std::string& filename) { // for interfaces, add the stub, proxy, and interface types. Type* stub = new Type(this, b.GetPackage(), b.GetName() + ".Stub", ValidatableType::KIND_GENERATED, false, false, filename, b.GetLine()); Type* proxy = new Type(this, b.GetPackage(), b.GetName() + ".Stub.Proxy", ValidatableType::KIND_GENERATED, false, false, filename, b.GetLine()); Type* type = new InterfaceType(this, b.GetPackage(), b.GetName(), false, b.IsOneway(), filename, b.GetLine(), stub, proxy); bool success = true; success &= Add(type); success &= Add(stub); success &= Add(proxy); return success; } bool JavaTypeNamespace::AddListType(const std::string& contained_type_name) { const Type* contained_type = FindTypeByCanonicalName(contained_type_name); if (!contained_type) { return false; } Add(new GenericListType(this, contained_type)); return true; } bool JavaTypeNamespace::AddMapType(const string& key_type_name, const string& value_type_name) { LOG(ERROR) << "Don't know how to create a Map container."; return false; } } // namespace java } // namespace aidl } // namespace android type_java.h0100644 0000000 0000000 00000045231 13277516055 011760 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_TYPE_JAVA_H_ #define AIDL_TYPE_JAVA_H_ #include #include #include "ast_java.h" #include "type_namespace.h" namespace android { namespace aidl { namespace java { class JavaTypeNamespace; class Type : public ValidatableType { public: // WriteToParcel flags enum { PARCELABLE_WRITE_RETURN_VALUE = 0x0001 }; Type(const JavaTypeNamespace* types, const std::string& name, int kind, bool canWriteToParcel, bool canBeOut); Type(const JavaTypeNamespace* types, const std::string& package, const std::string& name, int kind, bool canWriteToParcel, bool canBeOut, const std::string& declFile = "", int declLine = -1); virtual ~Type() = default; bool CanBeOutParameter() const override { return m_canBeOut; } bool CanWriteToParcel() const override { return m_canWriteToParcel; } const ValidatableType* ArrayType() const override { return m_array_type.get(); } const ValidatableType* NullableType() const override { return nullptr; } virtual std::string JavaType() const { return m_javaType; } virtual std::string CreatorName() const; virtual std::string InstantiableName() const; virtual void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const; virtual void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const; virtual void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const; protected: Expression* BuildWriteToParcelFlags(int flags) const; const JavaTypeNamespace* m_types; std::unique_ptr m_array_type; private: Type(); Type(const Type&); std::string m_javaType; std::string m_declFile; bool m_canWriteToParcel; bool m_canBeOut; }; class BasicArrayType : public Type { public: BasicArrayType(const JavaTypeNamespace* types, const std::string& name, const std::string& writeArrayParcel, const std::string& createArrayParcel, const std::string& readArrayParcel); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } private: std::string m_writeArrayParcel; std::string m_createArrayParcel; std::string m_readArrayParcel; }; class BasicType : public Type { public: BasicType(const JavaTypeNamespace* types, const std::string& name, const std::string& marshallParcel, const std::string& unmarshallParcel, const std::string& writeArrayParcel, const std::string& createArrayParcel, const std::string& readArrayParcel); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; private: std::string m_marshallParcel; std::string m_unmarshallParcel; }; class FileDescriptorArrayType : public Type { public: explicit FileDescriptorArrayType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class FileDescriptorType : public Type { public: explicit FileDescriptorType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class BooleanArrayType : public Type { public: explicit BooleanArrayType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class BooleanType : public Type { public: explicit BooleanType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class CharArrayType : public Type { public: explicit CharArrayType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class CharType : public Type { public: explicit CharType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class StringArrayType : public Type { public: explicit StringArrayType(const JavaTypeNamespace* types); std::string CreatorName() const override; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class StringType : public Type { public: StringType(const JavaTypeNamespace* types, const std::string& package, const std::string& class_name); std::string JavaType() const override { return "java.lang.String"; } std::string CreatorName() const override; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class CharSequenceType : public Type { public: explicit CharSequenceType(const JavaTypeNamespace* types); std::string CreatorName() const override; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class RemoteExceptionType : public Type { public: explicit RemoteExceptionType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class RuntimeExceptionType : public Type { public: explicit RuntimeExceptionType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class IBinderArrayType : public Type { public: explicit IBinderArrayType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class IBinderType : public Type { public: explicit IBinderType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class IInterfaceType : public Type { public: explicit IInterfaceType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class BinderType : public Type { public: explicit BinderType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class BinderProxyType : public Type { public: explicit BinderProxyType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class ParcelType : public Type { public: explicit ParcelType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class ParcelableInterfaceType : public Type { public: explicit ParcelableInterfaceType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; }; class MapType : public Type { public: explicit MapType(const JavaTypeNamespace* types); void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class ListType : public Type { public: explicit ListType(const JavaTypeNamespace* types); std::string InstantiableName() const override; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class UserDataArrayType : public Type { public: UserDataArrayType(const JavaTypeNamespace* types, const std::string& package, const std::string& name, bool builtIn, bool canWriteToParcel, const std::string& declFile = "", int declLine = -1); std::string CreatorName() const override; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class UserDataType : public Type { public: UserDataType(const JavaTypeNamespace* types, const std::string& package, const std::string& name, bool builtIn, bool canWriteToParcel, const std::string& declFile = "", int declLine = -1); std::string CreatorName() const override; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } }; class InterfaceType : public Type { public: InterfaceType(const JavaTypeNamespace* types, const std::string& package, const std::string& name, bool builtIn, bool oneway, const std::string& declFile, int declLine, const Type* stub, const Type* proxy); bool OneWay() const; void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } const Type* GetStub() const { return stub_; } const Type* GetProxy() const { return proxy_; } private: bool m_oneway; const Type* stub_; const Type* proxy_; }; class ClassLoaderType : public Type { public: explicit ClassLoaderType(const JavaTypeNamespace* types); }; class GenericListType : public Type { public: GenericListType(const JavaTypeNamespace* types, const Type* arg); std::string CreatorName() const override; std::string InstantiableName() const override; std::string JavaType() const override { return "java.util.List<" + m_contained_type->JavaType() + ">"; } void WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags) const override; void CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; void ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl) const override; const ValidatableType* NullableType() const override { return this; } private: const Type* m_contained_type; const std::string m_creator; }; class JavaTypeNamespace : public LanguageTypeNamespace { public: JavaTypeNamespace() = default; virtual ~JavaTypeNamespace() = default; void Init() override; bool AddParcelableType(const AidlParcelable& p, const std::string& filename) override; bool AddBinderType(const AidlInterface& b, const std::string& filename) override; bool AddListType(const std::string& contained_type_name) override; bool AddMapType(const std::string& key_type_name, const std::string& value_type_name) override; const Type* BoolType() const { return m_bool_type; } const Type* IntType() const { return m_int_type; } const Type* StringType() const { return m_string_type; } const Type* TextUtilsType() const { return m_text_utils_type; } const Type* RemoteExceptionType() const { return m_remote_exception_type; } const Type* RuntimeExceptionType() const { return m_runtime_exception_type; } const Type* IBinderType() const { return m_ibinder_type; } const Type* IInterfaceType() const { return m_iinterface_type; } const Type* BinderNativeType() const { return m_binder_native_type; } const Type* BinderProxyType() const { return m_binder_proxy_type; } const Type* ParcelType() const { return m_parcel_type; } const Type* ParcelableInterfaceType() const { return m_parcelable_interface_type; } const Type* ContextType() const { return m_context_type; } const Type* ClassLoaderType() const { return m_classloader_type; } private: const Type* m_bool_type{nullptr}; const Type* m_int_type{nullptr}; const Type* m_string_type{nullptr}; const Type* m_text_utils_type{nullptr}; const Type* m_remote_exception_type{nullptr}; const Type* m_runtime_exception_type{nullptr}; const Type* m_ibinder_type{nullptr}; const Type* m_iinterface_type{nullptr}; const Type* m_binder_native_type{nullptr}; const Type* m_binder_proxy_type{nullptr}; const Type* m_parcel_type{nullptr}; const Type* m_parcelable_interface_type{nullptr}; const Type* m_context_type{nullptr}; const Type* m_classloader_type{nullptr}; DISALLOW_COPY_AND_ASSIGN(JavaTypeNamespace); }; extern Expression* NULL_VALUE; extern Expression* THIS_VALUE; extern Expression* SUPER_VALUE; extern Expression* TRUE_VALUE; extern Expression* FALSE_VALUE; } // namespace java } // namespace aidl } // namespace android #endif // AIDL_TYPE_JAVA_H_ type_java_unittest.cpp0100644 0000000 0000000 00000004235 13277516055 014251 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 #include #include "aidl_language.h" #include "type_java.h" using std::unique_ptr; namespace android { namespace aidl { namespace java { class JavaTypeNamespaceTest : public ::testing::Test { protected: void SetUp() override { types_.Init(); } JavaTypeNamespace types_; }; TEST_F(JavaTypeNamespaceTest, HasSomeBasicTypes) { EXPECT_TRUE(types_.HasTypeByCanonicalName("void")); EXPECT_TRUE(types_.HasTypeByCanonicalName("int")); EXPECT_TRUE(types_.HasTypeByCanonicalName("java.lang.String")); } TEST_F(JavaTypeNamespaceTest, ContainerTypeCreation) { // We start with no knowledge of parcelables or lists of them. EXPECT_FALSE(types_.HasTypeByCanonicalName("Foo")); EXPECT_FALSE(types_.HasTypeByCanonicalName("java.util.List")); unique_ptr parcelable( new AidlParcelable(new AidlQualifiedName("Foo", ""), 0, {"a", "goog"})); // Add the parcelable type we care about. EXPECT_TRUE(types_.AddParcelableType(*parcelable.get(), __FILE__)); // Now we can find the parcelable type, but not the List of them. EXPECT_TRUE(types_.HasTypeByCanonicalName("a.goog.Foo")); EXPECT_FALSE(types_.HasTypeByCanonicalName("java.util.List")); // But after we add the list explicitly... AidlType container_type("List", 0, "", false /* not array */); EXPECT_TRUE(types_.MaybeAddContainerType(container_type)); // This should work. EXPECT_TRUE(types_.HasTypeByCanonicalName("java.util.List")); } } // namespace java } // namespace android } // namespace aidl type_namespace.cpp0100644 0000000 0000000 00000012713 13277516055 013325 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 "type_namespace.h" #include #include #include #include "aidl_language.h" #include "logging.h" using android::base::StringPrintf; using android::base::Split; using android::base::Trim; using std::string; using std::vector; namespace android { namespace aidl { // Since packages cannot contain '-' normally, we cannot be asked // to create a type that conflicts with these strings. const char kAidlReservedTypePackage[] = "aidl-internal"; const char kUtf8StringClass[] = "Utf8String"; const char kUtf8InCppStringClass[] = "Utf8InCppString"; // These *must* match the package and class names above. const char kUtf8StringCanonicalName[] = "aidl-internal.Utf8String"; const char kUtf8InCppStringCanonicalName[] = "aidl-internal.Utf8InCppString"; const char kStringCanonicalName[] = "java.lang.String"; const char kUtf8Annotation[] = "@utf8"; const char kUtf8InCppAnnotation[] = "@utfInCpp"; namespace { bool is_java_keyword(const char* str) { static const std::vector kJavaKeywords{ "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", "true", "false", "null", }; return std::find(kJavaKeywords.begin(), kJavaKeywords.end(), str) != kJavaKeywords.end(); } } // namespace ValidatableType::ValidatableType( int kind, const string& package, const string& type_name, const string& decl_file, int decl_line) : kind_(kind), type_name_(type_name), canonical_name_((package.empty()) ? type_name : package + "." + type_name), origin_file_(decl_file), origin_line_(decl_line) {} string ValidatableType::HumanReadableKind() const { switch (Kind()) { case ValidatableType::KIND_BUILT_IN: return "a built in"; case ValidatableType::KIND_PARCELABLE: return "a parcelable"; case ValidatableType::KIND_INTERFACE: return "an interface"; case ValidatableType::KIND_GENERATED: return "a generated"; } return "unknown"; } bool TypeNamespace::IsValidPackage(const string& /* package */) const { return true; } const ValidatableType* TypeNamespace::GetReturnType( const AidlType& raw_type, const string& filename, const AidlInterface& interface) const { string error_msg; const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg, interface); if (return_type == nullptr) { LOG(ERROR) << StringPrintf("In file %s line %d return type %s:\n ", filename.c_str(), raw_type.GetLine(), raw_type.ToString().c_str()) << error_msg; return nullptr; } return return_type; } const ValidatableType* TypeNamespace::GetArgType( const AidlArgument& a, int arg_index, const string& filename, const AidlInterface& interface) 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); if (t == nullptr) { LOG(ERROR) << error_prefix << error_msg; return nullptr; } if (!a.DirectionWasSpecified() && t->CanBeOutParameter()) { LOG(ERROR) << error_prefix << StringPrintf( "'%s' can be an out type, so you must declare it as in," " out or inout.", a.GetType().ToString().c_str()); return nullptr; } if (a.GetDirection() != AidlArgument::IN_DIR && !t->CanBeOutParameter()) { LOG(ERROR) << error_prefix << StringPrintf( "'%s' can only be an in parameter.", a.ToString().c_str()); return nullptr; } // check that the name doesn't match a keyword if (is_java_keyword(a.GetName().c_str())) { LOG(ERROR) << error_prefix << "Argument name is a Java or aidl keyword"; return nullptr; } // Reserve a namespace for internal use if (a.GetName().substr(0, 5) == "_aidl") { LOG(ERROR) << error_prefix << "Argument name cannot begin with '_aidl'"; return nullptr; } return t; } } // namespace aidl } // namespace android type_namespace.h0100644 0000000 0000000 00000040062 13277516055 012770 0ustar000000000 0000000 /* * Copyright (C) 2015, 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 AIDL_TYPE_NAMESPACE_H_ #define AIDL_TYPE_NAMESPACE_H_ #include #include #include #include #include #include "aidl_language.h" #include "logging.h" namespace android { namespace aidl { // Special reserved type names. extern const char kAidlReservedTypePackage[]; extern const char kUtf8StringClass[]; // UTF8 wire format string extern const char kUtf8InCppStringClass[]; // UTF16 wire format, UTF8 in C++ // Helpful aliases defined to be . extern const char kUtf8StringCanonicalName[]; extern const char kUtf8InCppStringCanonicalName[]; // We sometimes special case this class. extern const char kStringCanonicalName[]; // Note that these aren't the strings recognized by the parser, we just keep // here for the sake of logging a common string constant. extern const char kUtf8Annotation[]; extern const char kUtf8InCppAnnotation[]; class ValidatableType { public: enum { KIND_BUILT_IN, KIND_PARCELABLE, KIND_INTERFACE, KIND_GENERATED, }; ValidatableType(int kind, const std::string& package, const std::string& type_name, const std::string& decl_file, int decl_line); virtual ~ValidatableType() = default; virtual bool CanBeArray() const { return ArrayType() != nullptr; } virtual bool CanBeOutParameter() const = 0; virtual bool CanWriteToParcel() const = 0; virtual const ValidatableType* ArrayType() const = 0; virtual const ValidatableType* NullableType() const = 0; // ShortName() is the class name without a package. std::string ShortName() const { return type_name_; } // CanonicalName() returns the canonical AIDL type, with packages. std::string CanonicalName() const { return canonical_name_; } int Kind() const { return kind_; } std::string HumanReadableKind() const; std::string DeclFile() const { return origin_file_; } int DeclLine() const { return origin_line_; } private: const int kind_; const std::string type_name_; const std::string canonical_name_; const std::string origin_file_; const int origin_line_; DISALLOW_COPY_AND_ASSIGN(ValidatableType); }; class TypeNamespace { public: // Load the TypeNamespace with built in types. Don't do work in the // constructor because many of the useful methods are virtual. virtual void Init() = 0; // 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 // on error. Silently discards requests to add non-container types. virtual bool MaybeAddContainerType(const AidlType& aidl_type) = 0; // Returns true iff this has a type for |import|. virtual bool HasImportType(const AidlImport& import) const = 0; // Returns true iff |package| is a valid package name. virtual bool IsValidPackage(const std::string& package) const; // 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; // 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; // Returns a pointer to a type corresponding to |interface|. virtual const ValidatableType* GetInterfaceType( const AidlInterface& interface) const = 0; protected: TypeNamespace() = default; virtual ~TypeNamespace() = default; virtual const ValidatableType* GetValidatableType( const AidlType& type, std::string* error_msg, const AidlInterface& interface) const = 0; private: DISALLOW_COPY_AND_ASSIGN(TypeNamespace); }; template class LanguageTypeNamespace : public TypeNamespace { public: LanguageTypeNamespace() = default; virtual ~LanguageTypeNamespace() = default; // Get a pointer to an existing type. Searches first by fully-qualified // name, and then class name (dropping package qualifiers). const T* Find(const AidlType& aidl_type) const; // Find a type by its |name|. If |name| refers to a container type (e.g. // List) you must turn it into a canonical name first (e.g. // java.util.List). const T* FindTypeByCanonicalName(const std::string& name) const; bool HasTypeByCanonicalName(const std::string& type_name) const { return FindTypeByCanonicalName(type_name) != nullptr; } bool HasImportType(const AidlImport& import) const override { return HasTypeByCanonicalName(import.GetNeededClass()); } const ValidatableType* GetInterfaceType( const AidlInterface& interface) const override { return FindTypeByCanonicalName(interface.GetCanonicalName()); } bool MaybeAddContainerType(const AidlType& aidl_type) override; // We dynamically create container types as we discover them in the parse // tree. Returns false if the contained types cannot be canonicalized. virtual bool AddListType(const std::string& contained_type_name) = 0; virtual bool AddMapType(const std::string& key_type_name, const std::string& value_type_name) = 0; protected: bool Add(const T* type); private: // Returns true iff the name can be canonicalized to a container type. virtual bool CanonicalizeContainerType( const AidlType& aidl_type, std::vector* container_class, std::vector* contained_type_names) const; // 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; std::vector> types_; DISALLOW_COPY_AND_ASSIGN(LanguageTypeNamespace); }; // class LanguageTypeNamespace template bool LanguageTypeNamespace::Add(const T* type) { const T* existing = FindTypeByCanonicalName(type->CanonicalName()); if (!existing) { types_.emplace_back(type); return true; } if (existing->Kind() == ValidatableType::KIND_BUILT_IN) { LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine() << " attempt to redefine built in class " << type->CanonicalName(); return false; } if (type->Kind() != existing->Kind()) { LOG(ERROR) << type->DeclFile() << ":" << type->DeclLine() << " attempt to redefine " << type->CanonicalName() << " as " << type->HumanReadableKind(); LOG(ERROR) << existing->DeclFile() << ":" << existing->DeclLine() << " previously defined here as " << existing->HumanReadableKind(); return false; } return true; } template const T* LanguageTypeNamespace::Find(const AidlType& aidl_type) const { using std::string; using std::vector; using android::base::Join; using android::base::Trim; string name = Trim(aidl_type.GetName()); if (IsContainerType(name)) { vector container_class; vector contained_type_names; if (!CanonicalizeContainerType(aidl_type, &container_class, &contained_type_names)) { return nullptr; } name = Join(container_class, '.') + "<" + Join(contained_type_names, ',') + ">"; } // Here, we know that we have the canonical name for this container. return FindTypeByCanonicalName(name); } template const T* LanguageTypeNamespace::FindTypeByCanonicalName( const std::string& raw_name) const { using android::base::Trim; std::string name = Trim(raw_name); const T* ret = nullptr; for (const auto& type : types_) { // Always prefer a exact match if possible. // This works for primitives and class names qualified with a package. if (type->CanonicalName() == name) { ret = type.get(); break; } // We allow authors to drop packages when refering to a class name. if (type->ShortName() == name) { ret = type.get(); } } return ret; } template bool LanguageTypeNamespace::MaybeAddContainerType( const AidlType& aidl_type) { using android::base::Join; const std::string& type_name = aidl_type.GetName(); if (!IsContainerType(type_name)) { return true; } std::vector container_class; std::vector contained_type_names; if (!CanonicalizeContainerType(aidl_type, &container_class, &contained_type_names)) { return false; } const std::string canonical_name = Join(container_class, ".") + "<" + Join(contained_type_names, ",") + ">"; if (HasTypeByCanonicalName(canonical_name)) { return true; } // We only support two types right now and this type is one of them. switch (contained_type_names.size()) { case 1: return AddListType(contained_type_names[0]); case 2: return AddMapType(contained_type_names[0], contained_type_names[1]); default: break; // Should never get here, will FATAL below. } LOG(FATAL) << "aidl internal error"; return false; } template bool LanguageTypeNamespace::IsContainerType( const std::string& type_name) const { const size_t opening_brace = type_name.find('<'); const size_t closing_brace = type_name.find('>'); if (opening_brace != std::string::npos || closing_brace != std::string::npos) { return true; // Neither < nor > appear in normal AIDL types. } return false; } template bool LanguageTypeNamespace::CanonicalizeContainerType( const AidlType& aidl_type, std::vector* container_class, std::vector* contained_type_names) const { using android::base::Trim; using android::base::Split; std::string name = Trim(aidl_type.GetName()); const size_t opening_brace = name.find('<'); const size_t closing_brace = name.find('>'); if (opening_brace == std::string::npos || closing_brace == std::string::npos) { return false; } if (opening_brace != name.rfind('<') || closing_brace != name.rfind('>') || closing_brace != name.length() - 1) { // Nested/invalid templates are forbidden. LOG(ERROR) << "Invalid template type '" << name << "'"; return false; } std::string container = Trim(name.substr(0, opening_brace)); std::string remainder = name.substr(opening_brace + 1, (closing_brace - opening_brace) - 1); std::vector args = Split(remainder, ","); for (auto& type_name: args) { // Here, we are relying on FindTypeByCanonicalName to do its best when // given a non-canonical name for non-compound type (i.e. not another // container). const T* arg_type = FindTypeByCanonicalName(type_name); if (!arg_type) { return false; } // Now get the canonical names for these contained types, remapping them if // necessary. type_name = arg_type->CanonicalName(); if (aidl_type.IsUtf8() && type_name == "java.lang.String") { type_name = kUtf8StringCanonicalName; } else if (aidl_type.IsUtf8InCpp() && type_name == "java.lang.String") { type_name = kUtf8InCppStringCanonicalName; } } // Map the container name to its canonical form for supported containers. if ((container == "List" || container == "java.util.List") && args.size() == 1) { *container_class = {"java", "util", "List"}; *contained_type_names = args; return true; } if ((container == "Map" || container == "java.util.Map") && args.size() == 2) { *container_class = {"java", "util", "Map"}; *contained_type_names = args; return true; } LOG(ERROR) << "Unknown find container with name " << container << " and " << args.size() << "contained types."; return false; } template const ValidatableType* LanguageTypeNamespace::GetValidatableType( const AidlType& aidl_type, std::string* error_msg, const AidlInterface& interface) const { using android::base::StringPrintf; const ValidatableType* type = Find(aidl_type); if (type == nullptr) { *error_msg = "unknown type"; return nullptr; } if (aidl_type.GetName() == "void") { if (aidl_type.IsArray()) { *error_msg = "void type cannot be an array"; return nullptr; } if (aidl_type.IsNullable() || aidl_type.IsUtf8() || aidl_type.IsUtf8InCpp()) { *error_msg = "void type cannot be annotated"; return nullptr; } // We have no more special handling for void. return type; } // No type may be annotated with both these annotations. if (aidl_type.IsUtf8() && aidl_type.IsUtf8InCpp()) { *error_msg = StringPrintf("Type cannot be marked as both %s and %s.", kUtf8Annotation, kUtf8InCppAnnotation); return nullptr; } bool utf8 = aidl_type.IsUtf8(); bool utf8InCpp = aidl_type.IsUtf8InCpp(); // Strings inside containers get remapped to appropriate utf8 versions when // we convert the container name to its canonical form and the look up the // type. However, for non-compound types (i.e. those not in a container) we // must patch them up here. if (IsContainerType(type->CanonicalName())) { utf8 = false; utf8InCpp = false; } else if (aidl_type.GetName() == "String" || aidl_type.GetName() == "java.lang.String") { utf8 = utf8 || interface.IsUtf8(); utf8InCpp = utf8InCpp || interface.IsUtf8InCpp(); } else if (utf8 || utf8InCpp) { const char* annotation_literal = (utf8) ? kUtf8Annotation : kUtf8InCppAnnotation; *error_msg = StringPrintf("type '%s' may not be annotated as %s.", aidl_type.GetName().c_str(), annotation_literal); return nullptr; } if (utf8) { type = FindTypeByCanonicalName(kUtf8StringCanonicalName); } else if (utf8InCpp) { type = FindTypeByCanonicalName(kUtf8InCppStringCanonicalName); } // One of our UTF8 transforms made type null if (type == nullptr) { const char* annotation_literal = (utf8) ? kUtf8Annotation : kUtf8InCppAnnotation; *error_msg = StringPrintf( "%s is unsupported when generating code for this language.", annotation_literal); return nullptr; } if (!type->CanWriteToParcel()) { *error_msg = "type cannot be marshalled"; return nullptr; } if (aidl_type.IsArray()) { type = type->ArrayType(); if (!type) { *error_msg = StringPrintf("type '%s' cannot be an array", aidl_type.GetName().c_str()); return nullptr; } } if (interface.IsNullable()) { const ValidatableType* nullableType = type->NullableType(); if (nullableType) { return nullableType; } } if (aidl_type.IsNullable()) { type = type->NullableType(); if (!type) { *error_msg = StringPrintf("type '%s%s' cannot be marked as possibly null", aidl_type.GetName().c_str(), (aidl_type.IsArray()) ? "[]" : ""); return nullptr; } } return type; } } // namespace aidl } // namespace android #endif // AIDL_TYPE_NAMESPACE_H_