.clang-format0100644 0000000 0000000 00000001415 13755771705 012202 0ustar000000000 0000000 # # Copyright (C) 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # BasedOnStyle: Google CommentPragmas: NOLINT:.* DerivePointerAlignment: false AllowShortFunctionsOnASingleLine: Inline ColumnLimit: 100 TabWidth: 2 UseTab: Never IndentWidth: 2 Android.bp0100644 0000000 0000000 00000014562 13755771705 011541 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", cflags: [ "-Wall", "-Werror", "-Wextra", ], whole_static_libs: ["libgtest_prod"], static_libs: [ "libbase", "libcutils", ], target: { windows: { enabled: true, }, }, } // Logic shared between aidl and its unittests cc_library_static { name: "libaidl-common", defaults: ["aidl_defaults"], host_supported: true, srcs: [ "aidl.cpp", "aidl_apicheck.cpp", "aidl_language.cpp", "aidl_language_l.ll", "aidl_language_y.yy", "aidl_typenames.cpp", "aidl_to_cpp.cpp", "aidl_to_java.cpp", "aidl_to_ndk.cpp", "ast_cpp.cpp", "ast_java.cpp", "code_writer.cpp", "generate_cpp.cpp", "aidl_to_cpp_common.cpp", "generate_ndk.cpp", "generate_java.cpp", "generate_java_binder.cpp", "generate_aidl_mappings.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.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 { name: "aidl_unittests", host_supported: true, test_suites: ["device-tests"], cflags: [ "-Wall", "-Wextra", "-Werror", "-g", "-DUNIT_TEST", ], srcs: [ "aidl_unittest.cpp", "ast_cpp_unittest.cpp", "ast_java_unittest.cpp", "code_writer_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", ], target: { host: { static_libs: ["libgmock_host"], }, android: { static_libs: [ "libgmock", "liblog", ], }, }, } // // 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", ], } cc_defaults { name: "aidl_test_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", ], 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/*.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", "tests/aidl_test_client_defaultimpl.cpp", ], } android_app { name: "aidl_test_services", platform_apis: true, // Turn off Java optimization tools to speed up our test iterations. optimize: { enabled: false, }, dex_preopt: { enabled: false, }, certificate: "platform", manifest: "tests/java_app/AndroidManifest.xml", resource_dirs: ["tests/java_app/resources"], srcs: [ "tests/android/aidl/tests/ITestService.aidl", "tests/android/aidl/tests/INamedCallback.aidl", "tests/android/aidl/tests/StructuredParcelable.aidl", "tests/java_app/src/android/aidl/tests/NullableTests.java", "tests/java_app/src/android/aidl/tests/SimpleParcelable.java", "tests/java_app/src/android/aidl/tests/TestFailException.java", "tests/java_app/src/android/aidl/tests/TestLogger.java", "tests/java_app/src/android/aidl/tests/TestServiceClient.java", ], aidl: { include_dirs: [ "system/tools/aidl/tests/", "frameworks/native/aidl/binder", ], }, } aidl_interface { name: "aidl_test_loggable_interface", local_include_dir: "tests", srcs: [ "tests/android/aidl/loggable/ILoggableInterface.aidl", ], backend: { cpp: { gen_log: true, }, ndk: { enabled: false, }, }, } aidl_interface { name: "aidl_test_loggable_interface_ndk", local_include_dir: "tests", srcs: [ "tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl", ], backend: { ndk: { gen_log: true, }, }, } MODULE_LICENSE_APACHE20100644 0000000 0000000 00000000000 13755771705 012751 0ustar000000000 0000000 NOTICE0100644 0000000 0000000 00000024707 13755771705 010544 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 00000000200 13755771705 010556 0ustar000000000 0000000 elsk@google.com jiyong@google.com malchev@google.com sadmac@google.com smoreland@google.com agampe@google.com vmarko@google.com PREUPLOAD.cfg0100644 0000000 0000000 00000000131 13755771705 011635 0ustar000000000 0000000 [Options] ignore_merged_commits = true [Builtin Hooks] clang_format = true gofmt = true TEST_MAPPING0100644 0000000 0000000 00000000170 13755771705 011501 0ustar000000000 0000000 { "presubmit": [ { "name": "aidl_unittests" }, { "name": "CtsNdkBinderTestCases" } ] } aidl.cpp0100644 0000000 0000000 00000073136 13755771705 011255 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 #include #include #ifdef _WIN32 #include #include #include #endif #include #include "aidl_language.h" #include "aidl_typenames.h" #include "generate_aidl_mappings.h" #include "generate_cpp.h" #include "generate_java.h" #include "generate_ndk.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::set; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace { // Copied from android.is.IBinder.[FIRST|LAST]_CALL_TRANSACTION const int kFirstCallTransaction = 1; const int kLastCallTransaction = 0x00ffffff; // Following IDs are all offsets from kFirstCallTransaction // IDs for meta transactions. Most of the meta transactions are implemented in // the framework side (Binder.java or Binder.cpp). But these are the ones that // are auto-implemented by the AIDL compiler. const int kFirstMetaMethodId = kLastCallTransaction - kFirstCallTransaction; const int kGetInterfaceVersionId = kFirstMetaMethodId; // Additional meta transactions implemented by AIDL should use // kFirstMetaMethodId -1, -2, ...and so on. // Reserve 100 IDs for meta methods, which is more than enough. If we don't reserve, // in the future, a newly added meta transaction ID will have a chance to // collide with the user-defined methods that were added in the past. So, // let's prevent users from using IDs in this range from the beginning. const int kLastMetaMethodId = kFirstMetaMethodId - 99; // Range of IDs that is allowed for user-defined methods. const int kMinUserSetMethodId = 0; const int kMaxUserSetMethodId = kLastMetaMethodId - 1; bool check_filename(const std::string& filename, const AidlDefinedType& defined_type) { const char* p; string expected; string fn; size_t len; bool valid = false; if (!IoDelegate::GetAbsolutePath(filename, &fn)) { return false; } const std::string package = defined_type.GetPackage(); 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) { AIDL_ERROR(defined_type) << name << " should be declared in a file called " << expected; } return valid; } bool register_types(const AidlStructuredParcelable* parcel, TypeNamespace* types) { for (const auto& v : parcel->GetFields()) { if (!types->MaybeAddContainerType(v->GetType())) { return false; } const ValidatableType* type = types->GetReturnType(v->GetType(), *parcel); if (type == nullptr) { return false; } v->GetMutableType()->SetLanguageType(type); } return true; } bool register_types(const AidlInterface* c, TypeNamespace* types) { for (const auto& m : c->GetMethods()) { if (!types->MaybeAddContainerType(m->GetType())) { return false; } const ValidatableType* return_type = types->GetReturnType(m->GetType(), *c); if (return_type == nullptr) { return false; } m->GetMutableType()->SetLanguageType(return_type); set argument_names; int index = 1; for (const auto& arg : m->GetArguments()) { if (!types->MaybeAddContainerType(arg->GetType())) { return false; } const ValidatableType* arg_type = types->GetArgType(*arg, index, *c); if (arg_type == nullptr) { return false; } arg->GetMutableType()->SetLanguageType(arg_type); } } for (const std::unique_ptr& constant : c->GetConstantDeclarations()) { AidlTypeSpecifier* specifier = constant->GetMutableType(); const ValidatableType* return_type = types->GetReturnType(*specifier, *c); if (return_type == nullptr) { return false; } specifier->SetLanguageType(return_type); } return true; } bool write_dep_file(const Options& options, const AidlDefinedType& defined_type, const vector& imports, const IoDelegate& io_delegate, const string& input_file, const string& output_file) { string dep_file_name = options.DependencyFile(); if (dep_file_name.empty() && options.AutoDepFile()) { dep_file_name = output_file + ".d"; } 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 = {input_file}; for (const auto& import : imports) { source_aidl.push_back(import); } // Encode that the output file depends on aidl input files. if (defined_type.AsUnstructuredParcelable() != nullptr && options.TargetLanguage() == Options::Language::JAVA) { // Legacy behavior. For parcelable declarations in Java, don't emit output file as // the dependency target. b/141372861 writer->Write(" : \\\n"); } else { writer->Write("%s : \\\n", output_file.c_str()); } writer->Write(" %s", Join(source_aidl, " \\\n ").c_str()); writer->Write("\n"); if (!options.DependencyFileNinja()) { 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 : source_aidl) { writer->Write("%s :\n", src.c_str()); } } if (options.IsCppOutput()) { if (!options.DependencyFileNinja()) { using ::android::aidl::cpp::ClassNames; using ::android::aidl::cpp::HeaderFile; vector headers; for (ClassNames c : {ClassNames::CLIENT, ClassNames::SERVER, ClassNames::RAW}) { headers.push_back(options.OutputHeaderDir() + HeaderFile(defined_type, 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 Options& options, const AidlDefinedType& defined_type) { // create the path to the destination folder based on the // defined_type package name string result = options.OutputDir(); string package = defined_type.GetPackage(); size_t len = package.length(); for (size_t i = 0; i < len; i++) { if (package[i] == '.') { package[i] = OS_PATH_SEPARATOR; } } result += package; // add the filename by replacing the .aidl extension to .java const string& name = defined_type.GetName(); result += OS_PATH_SEPARATOR; result.append(name, 0, name.find('.')); if (options.TargetLanguage() == Options::Language::JAVA) { result += ".java"; } else if (options.IsCppOutput()) { result += ".cpp"; } else { LOG(FATAL) << "Should not reach here" << endl; return ""; } return result; } bool check_and_assign_method_ids(const std::vector>& 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 uplicates 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) { // However, meta transactions that are added by the AIDL compiler are // exceptions. They have fixed IDs but allowed to be with user-defined // methods having auto-assigned IDs. This is because the Ids of the meta // transactions must be stable during the entire lifetime of an interface. // In other words, their IDs must be the same even when new user-defined // methods are added. if (!item->IsUserDefined()) { continue; } 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. AIDL_ERROR(item) << "Found duplicate method id (" << item->GetId() << ") for method " << item->GetName(); return false; } // Ensure that the user set id is within the appropriate limits if (item->GetId() < kMinUserSetMethodId || item->GetId() > kMaxUserSetMethodId) { AIDL_ERROR(item) << "Found out of bounds id (" << item->GetId() << ") for method " << item->GetName() << ". Value for id must be between " << kMinUserSetMethodId << " and " << kMaxUserSetMethodId << " inclusive."; return false; } usedIds.insert(item->GetId()); } else { hasUnassignedIds = true; } if (hasAssignedIds && hasUnassignedIds) { AIDL_ERROR(item) << "You must either assign id's to all methods or to none of them."; return false; } } // In the case that all methods have unassigned id's, set a unique id for them. if (hasUnassignedIds) { int newId = kMinUserSetMethodId; for (const auto& item : items) { assert(newId <= kMaxUserSetMethoId); if (item->IsUserDefined()) { item->SetId(newId++); } } } return true; } // 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, AidlTypenames& typenames) { 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; } AidlLocation::Point point = {.line = lineno, .column = 0 /*column*/}; AidlLocation location = AidlLocation(filename, point, point); if (decl == "parcelable") { // ParcelFileDescriptor is treated as a built-in type, but it's also in the framework.aidl. // So aidl should ignore built-in types in framework.aidl to prevent duplication. // (b/130899491) if (AidlTypenames::IsBuiltinTypename(class_name)) { continue; } AidlParcelable* doc = new AidlParcelable( location, new AidlQualifiedName(location, class_name, ""), package, "" /* comments */); types->AddParcelableType(*doc, filename); typenames.AddPreprocessedType(unique_ptr(doc)); } else if (decl == "structured_parcelable") { auto temp = new std::vector>(); AidlStructuredParcelable* doc = new AidlStructuredParcelable(location, new AidlQualifiedName(location, class_name, ""), package, "" /* comments */, temp); types->AddParcelableType(*doc, filename); typenames.AddPreprocessedType(unique_ptr(doc)); } else if (decl == "interface") { auto temp = new std::vector>(); AidlInterface* doc = new AidlInterface(location, class_name, "", false, temp, package); types->AddBinderType(*doc, filename); typenames.AddPreprocessedType(unique_ptr(doc)); } else { success = false; break; } } if (!success) { LOG(ERROR) << filename << ':' << lineno << " malformed preprocessed file line: '" << line << "'"; } return success; } AidlError load_and_validate_aidl(const std::string& input_file_name, const Options& options, const IoDelegate& io_delegate, TypeNamespace* types, vector* defined_types, vector* imported_files) { AidlError err = AidlError::OK; ////////////////////////////////////////////////////////////////////////// // Loading phase ////////////////////////////////////////////////////////////////////////// // Parse the main input file std::unique_ptr main_parser = Parser::Parse(input_file_name, io_delegate, types->typenames_); if (main_parser == nullptr) { return AidlError::PARSE_ERROR; } if (!types->AddDefinedTypes(main_parser->GetDefinedTypes(), input_file_name)) { return AidlError::BAD_TYPE; } // Import the preprocessed file for (const string& s : options.PreprocessedFiles()) { if (!parse_preprocessed_file(io_delegate, s, types, types->typenames_)) { err = AidlError::BAD_PRE_PROCESSED_FILE; } } if (err != AidlError::OK) { return err; } // Find files to import and parse them vector import_paths; ImportResolver import_resolver{io_delegate, input_file_name, options.ImportDirs(), options.InputFiles()}; set type_from_import_statements; for (const auto& import : main_parser->GetImports()) { if (!AidlTypenames::IsBuiltinTypename(import->GetNeededClass())) { type_from_import_statements.emplace(import->GetNeededClass()); } } // When referencing a type using fully qualified name it should be imported // without the import statement. To support that, add all unresolved // typespecs encountered during the parsing to the import_candidates list. // Note that there is no guarantee that the typespecs are all fully qualified. // It will be determined by calling FindImportFile(). set unresolved_types; for (const auto type : main_parser->GetUnresolvedTypespecs()) { if (!AidlTypenames::IsBuiltinTypename(type->GetName())) { unresolved_types.emplace(type->GetName()); } } set import_candidates(type_from_import_statements); import_candidates.insert(unresolved_types.begin(), unresolved_types.end()); for (const auto& import : import_candidates) { 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); if (import_path.empty()) { if (type_from_import_statements.find(import) != type_from_import_statements.end()) { // Complain only when the import from the import statement has failed. AIDL_ERROR(import) << "couldn't find import for class " << import; err = AidlError::BAD_IMPORT; } continue; } import_paths.emplace_back(import_path); std::unique_ptr import_parser = Parser::Parse(import_path, io_delegate, types->typenames_); if (import_parser == nullptr) { cerr << "error while importing " << import_path << " for " << import << endl; err = AidlError::BAD_IMPORT; continue; } if (!types->AddDefinedTypes(import_parser->GetDefinedTypes(), import_path)) { return AidlError::BAD_TYPE; } } if (err != AidlError::OK) { return err; } for (const auto& imported_file : options.ImportFiles()) { import_paths.emplace_back(imported_file); std::unique_ptr import_parser = Parser::Parse(imported_file, io_delegate, types->typenames_); if (import_parser == nullptr) { AIDL_ERROR(imported_file) << "error while importing " << imported_file; err = AidlError::BAD_IMPORT; continue; } if (!types->AddDefinedTypes(import_parser->GetDefinedTypes(), imported_file)) { return AidlError::BAD_TYPE; } } if (err != AidlError::OK) { return err; } const bool is_check_api = options.GetTask() == Options::Task::CHECK_API; // Resolve the unresolved type references found from the input file if (!is_check_api && !main_parser->Resolve()) { // Resolution is not need for check api because all typespecs are // using fully qualified names. return AidlError::BAD_TYPE; } if (!is_check_api) { for (const auto defined_type : main_parser->GetDefinedTypes()) { AidlInterface* interface = defined_type->AsInterface(); AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable(); // Link the AIDL type with the type of the target language. This will // be removed when the migration to AidlTypenames is done. defined_type->SetLanguageType(types->GetDefinedType(*defined_type)); if (interface != nullptr) { if (!register_types(interface, types)) { return AidlError::BAD_TYPE; } } if (parcelable != nullptr) { if (!register_types(parcelable, types)) { return AidlError::BAD_TYPE; } } } } ////////////////////////////////////////////////////////////////////////// // Validation phase ////////////////////////////////////////////////////////////////////////// AidlTypenames& typenames = types->typenames_; // For legacy reasons, by default, compiling an unstructured parcelable (which contains no output) // is allowed. This must not be returned as an error until the very end of this procedure since // this may be considered a success, and we should first check that there are not other, more // serious failures. bool contains_unstructured_parcelable = false; const int num_defined_types = main_parser->GetDefinedTypes().size(); for (const auto defined_type : main_parser->GetDefinedTypes()) { CHECK(defined_type != nullptr); AidlParcelable* unstructuredParcelable = defined_type->AsUnstructuredParcelable(); if (unstructuredParcelable != nullptr) { if (!unstructuredParcelable->CheckValid(typenames)) { return AidlError::BAD_TYPE; } bool isStable = unstructuredParcelable->IsStableParcelable(); if (options.IsStructured() && !isStable) { AIDL_ERROR(unstructuredParcelable) << "Cannot declared parcelable in a --structured interface. Parcelable must be defined " "in AIDL directly."; return AidlError::NOT_STRUCTURED; } if (options.FailOnParcelable()) { AIDL_ERROR(unstructuredParcelable) << "Refusing to generate code with unstructured parcelables. Declared parcelables " "should be in their own file and/or cannot be used with --structured interfaces."; // Continue parsing for more errors } contains_unstructured_parcelable = true; continue; } // Ensure that a type is either an interface or a structured parcelable AidlInterface* interface = defined_type->AsInterface(); AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable(); CHECK(interface != nullptr || parcelable != nullptr); // Ensure that foo.bar.IFoo is defined in /foo/bar/IFoo.aidl if (num_defined_types == 1 && !check_filename(input_file_name, *defined_type)) { return AidlError::BAD_PACKAGE; } // Check the referenced types in parsed_doc to make sure we've imported them if (!is_check_api) { // No need to do this for check api because all typespecs are already // using fully qualified name and we don't import in AIDL files. if (!defined_type->CheckValid(typenames)) { return AidlError::BAD_TYPE; } } if (interface != nullptr) { // add the meta-method 'int getInterfaceVersion()' if version is specified. if (options.Version() > 0) { AidlTypeSpecifier* ret = new AidlTypeSpecifier(AIDL_LOCATION_HERE, "int", false, nullptr, ""); ret->Resolve(typenames); vector>* args = new vector>(); AidlMethod* method = new AidlMethod(AIDL_LOCATION_HERE, false, ret, "getInterfaceVersion", args, "", kGetInterfaceVersionId, false /* is_user_defined */); interface->GetMutableMethods().emplace_back(method); } if (!check_and_assign_method_ids(interface->GetMethods())) { return AidlError::BAD_METHOD_ID; } } } if (options.IsStructured()) { typenames.IterateTypes([&](const AidlDefinedType& type) { if (type.AsUnstructuredParcelable() != nullptr && !type.AsUnstructuredParcelable()->IsStableParcelable()) { err = AidlError::NOT_STRUCTURED; LOG(ERROR) << type.GetCanonicalName() << " is not structured, but this is a structured interface."; } }); } if (err != AidlError::OK) { return err; } if (defined_types != nullptr) { *defined_types = main_parser->GetDefinedTypes(); } if (imported_files != nullptr) { *imported_files = import_paths; } if (contains_unstructured_parcelable) { // Considered a success for the legacy case, so this must be returned last. return AidlError::FOUND_PARCELABLE; } return AidlError::OK; } } // namespace internals int compile_aidl(const Options& options, const IoDelegate& io_delegate) { const Options::Language lang = options.TargetLanguage(); for (const string& input_file : options.InputFiles()) { // Create type namespace that will hold the types identified by the parser. // This two namespaces that are specific to the target language will be // unified to AidlTypenames which is agnostic to the target language. cpp::TypeNamespace cpp_types; cpp_types.Init(); java::JavaTypeNamespace java_types; java_types.Init(); TypeNamespace* types; if (options.IsCppOutput()) { types = &cpp_types; } else if (lang == Options::Language::JAVA) { types = &java_types; } else { LOG(FATAL) << "Unsupported target language." << endl; return 1; } vector defined_types; vector imported_files; AidlError aidl_err = internals::load_and_validate_aidl(input_file, options, io_delegate, types, &defined_types, &imported_files); bool allowError = aidl_err == AidlError::FOUND_PARCELABLE && !options.FailOnParcelable(); if (aidl_err != AidlError::OK && !allowError) { return 1; } for (const auto defined_type : defined_types) { CHECK(defined_type != nullptr); string output_file_name = options.OutputFile(); // if needed, generate the output file name from the base folder if (output_file_name.empty() && !options.OutputDir().empty()) { output_file_name = generate_outputFileName(options, *defined_type); if (output_file_name.empty()) { return 1; } } if (!write_dep_file(options, *defined_type, imported_files, io_delegate, input_file, output_file_name)) { return 1; } bool success = false; if (lang == Options::Language::CPP) { success = cpp::GenerateCpp(output_file_name, options, cpp_types, *defined_type, io_delegate); } else if (lang == Options::Language::NDK) { ndk::GenerateNdk(output_file_name, options, cpp_types.typenames_, *defined_type, io_delegate); success = true; } else if (lang == Options::Language::JAVA) { if (defined_type->AsUnstructuredParcelable() != nullptr) { // Legacy behavior. For parcelable declarations in Java, don't generate output file. success = true; } else { success = java::generate_java(output_file_name, defined_type, &java_types, io_delegate, options); } } else { LOG(FATAL) << "Should not reach here" << endl; return 1; } if (!success) { return 1; } } } return 0; } bool dump_mappings(const Options& options, const IoDelegate& io_delegate) { android::aidl::mappings::SignatureMap all_mappings; for (const string& input_file : options.InputFiles()) { java::JavaTypeNamespace java_types; java_types.Init(); vector defined_types; vector imported_files; AidlError aidl_err = internals::load_and_validate_aidl( input_file, options, io_delegate, &java_types, &defined_types, &imported_files); if (aidl_err != AidlError::OK) { LOG(WARNING) << "AIDL file is invalid.\n"; continue; } for (const auto defined_type : defined_types) { auto mappings = mappings::generate_mappings(defined_type); all_mappings.insert(mappings.begin(), mappings.end()); } } std::stringstream mappings_str; for (const auto& mapping : all_mappings) { mappings_str << mapping.first << "\n" << mapping.second << "\n"; } auto code_writer = io_delegate.GetCodeWriter(options.OutputFile()); code_writer->Write("%s", mappings_str.str().c_str()); return true; } bool preprocess_aidl(const Options& options, const IoDelegate& io_delegate) { unique_ptr writer = io_delegate.GetCodeWriter(options.OutputFile()); for (const auto& file : options.InputFiles()) { AidlTypenames typenames; std::unique_ptr p = Parser::Parse(file, io_delegate, typenames); if (p == nullptr) return false; for (const auto& defined_type : p->GetDefinedTypes()) { if (!writer->Write("%s %s;\n", defined_type->GetPreprocessDeclarationName().c_str(), defined_type->GetCanonicalName().c_str())) { return false; } } } return writer->Close(); } static string GetApiDumpPathFor(const AidlDefinedType& defined_type, const Options& options) { string package_as_path = Join(Split(defined_type.GetPackage(), "."), OS_PATH_SEPARATOR); CHECK(!options.OutputDir().empty() && options.OutputDir().back() == '/'); return options.OutputDir() + package_as_path + OS_PATH_SEPARATOR + defined_type.GetName() + ".aidl"; } bool dump_api(const Options& options, const IoDelegate& io_delegate) { for (const auto& file : options.InputFiles()) { java::JavaTypeNamespace ns; ns.Init(); vector defined_types; if (internals::load_and_validate_aidl(file, options, io_delegate, &ns, &defined_types, nullptr) == AidlError::OK) { for (const auto type : defined_types) { unique_ptr writer = io_delegate.GetCodeWriter(GetApiDumpPathFor(*type, options)); if (!type->GetPackage().empty()) { (*writer) << "package " << type->GetPackage() << ";\n"; } type->Write(writer.get()); } } else { return false; } } return true; } } // namespace android } // namespace aidl aidl.h0100644 0000000 0000000 00000004026 13755771705 010712 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. */ #pragma once #include #include #include #include #include "aidl_language.h" #include "import_resolver.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_INPUT, NOT_STRUCTURED, OK = 0, }; int compile_aidl(const Options& options, const IoDelegate& io_delegate); bool preprocess_aidl(const Options& options, const IoDelegate& io_delegate); bool dump_api(const Options& options, const IoDelegate& io_delegate); bool dump_mappings(const Options& options, const IoDelegate& io_delegate); const string kGetInterfaceVersion("getInterfaceVersion"); namespace internals { AidlError load_and_validate_aidl(const std::string& input_file_name, const Options& options, const IoDelegate& io_delegate, TypeNamespace* types, vector* defined_types, vector* imported_files); bool parse_preprocessed_file(const IoDelegate& io_delegate, const std::string& filename, TypeNamespace* types, AidlTypenames& typenames); } // namespace internals } // namespace android } // namespace aidl aidl_apicheck.cpp0100644 0000000 0000000 00000024071 13755771705 013076 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "aidl.h" #include "aidl_language.h" #include "import_resolver.h" #include "options.h" #include "type_java.h" #include #include #include namespace android { namespace aidl { using std::map; using std::set; using std::string; using std::vector; static bool have_compatible_annotations(const AidlAnnotatable& older, const AidlAnnotatable& newer) { set olderAnnotations(older.GetAnnotations().begin(), older.GetAnnotations().end()); set newerAnnotations(newer.GetAnnotations().begin(), newer.GetAnnotations().end()); if (olderAnnotations != newerAnnotations) { const string from = older.ToString().empty() ? "(empty)" : older.ToString(); const string to = newer.ToString().empty() ? "(empty)" : newer.ToString(); AIDL_ERROR(newer) << "Changed annotations: " << from << " to " << to; return false; } return true; } static bool are_compatible_types(const AidlTypeSpecifier& older, const AidlTypeSpecifier& newer) { bool compatible = true; if (older.ToString() != newer.ToString()) { AIDL_ERROR(newer) << "Type changed: " << older.ToString() << " to " << newer.ToString() << "."; compatible = false; } compatible &= have_compatible_annotations(older, newer); return compatible; } static bool are_compatible_interfaces(const AidlInterface& older, const AidlInterface& newer) { bool compatible = true; compatible &= have_compatible_annotations(older, newer); map new_methods; for (const auto& m : newer.AsInterface()->GetMethods()) { new_methods.emplace(m->Signature(), m.get()); } for (const auto& old_m : older.AsInterface()->GetMethods()) { const auto found = new_methods.find(old_m->Signature()); if (found == new_methods.end()) { AIDL_ERROR(old_m) << "Removed or changed method: " << older.GetCanonicalName() << "." << old_m->Signature(); compatible = false; continue; } // Compare IDs to detect method reordering. IDs are assigned by their // textual order, so if there is an ID mismatch, that means reordering // has happened. const auto new_m = found->second; if (old_m->IsOneway() != new_m->IsOneway()) { AIDL_ERROR(new_m) << "Oneway attribute " << (old_m->IsOneway() ? "removed" : "added") << ": " << older.GetCanonicalName() << "." << old_m->Signature(); compatible = false; } if (old_m->GetId() != new_m->GetId()) { AIDL_ERROR(new_m) << "Transaction ID changed: " << older.GetCanonicalName() << "." << old_m->Signature() << " is changed from " << old_m->GetId() << " to " << new_m->GetId() << "."; compatible = false; } compatible &= are_compatible_types(old_m->GetType(), new_m->GetType()); const auto& old_args = old_m->GetArguments(); const auto& new_args = new_m->GetArguments(); // this is guaranteed because arguments are part of AidlMethod::Signature() CHECK(old_args.size() == new_args.size()); for (size_t i = 0; i < old_args.size(); i++) { const AidlArgument& old_a = *(old_args.at(i)); const AidlArgument& new_a = *(new_args.at(i)); compatible &= are_compatible_types(old_a.GetType(), new_a.GetType()); if (old_a.GetDirection() != new_a.GetDirection()) { AIDL_ERROR(new_m) << "Direction changed: " << old_a.GetDirectionSpecifier() << " to " << new_a.GetDirectionSpecifier() << "."; compatible = false; } } } map new_constdecls; for (const auto& c : newer.AsInterface()->GetConstantDeclarations()) { new_constdecls.emplace(c->GetName(), c.get()); } for (const auto& old_c : older.AsInterface()->GetConstantDeclarations()) { const auto found = new_constdecls.find(old_c->GetName()); if (found == new_constdecls.end()) { AIDL_ERROR(old_c) << "Removed constant declaration: " << older.GetCanonicalName() << "." << old_c->GetName(); compatible = false; continue; } const auto new_c = found->second; compatible &= are_compatible_types(old_c->GetType(), new_c->GetType()); const string old_value = old_c->ValueString(AidlConstantValueDecorator); const string new_value = new_c->ValueString(AidlConstantValueDecorator); if (old_value != new_value) { AIDL_ERROR(newer) << "Changed constant value: " << older.GetCanonicalName() << "." << old_c->GetName() << " from " << old_value << " to " << new_value << "."; compatible = false; } } return compatible; } static bool are_compatible_parcelables(const AidlStructuredParcelable& older, const AidlStructuredParcelable& newer) { const auto& old_fields = older.GetFields(); const auto& new_fields = newer.GetFields(); if (old_fields.size() > new_fields.size()) { // you can add new fields only at the end AIDL_ERROR(newer) << "Number of fields in " << older.GetCanonicalName() << " is reduced from " << old_fields.size() << " to " << new_fields.size() << "."; return false; } bool compatible = true; for (size_t i = 0; i < old_fields.size(); i++) { const auto& old_field = old_fields.at(i); const auto& new_field = new_fields.at(i); compatible &= are_compatible_types(old_field->GetType(), new_field->GetType()); // Note: unlike method argument names, field name change is an incompatible // change, otherwise, we can't detect // parcelable Point {int x; int y;} -> parcelable Point {int y; int x;} if (old_field->GetName() != new_field->GetName()) { AIDL_ERROR(newer) << "Renamed field: " << old_field->GetName() << " to " << new_field->GetName() << "."; compatible = false; } const string old_value = old_field->ValueString(AidlConstantValueDecorator); const string new_value = new_field->ValueString(AidlConstantValueDecorator); if (old_value != new_value) { AIDL_ERROR(newer) << "Changed default value: " << old_value << " to " << new_value << "."; compatible = false; } } return compatible; } bool check_api(const Options& options, const IoDelegate& io_delegate) { CHECK(options.IsStructured()); CHECK(options.InputFiles().size() == 2) << "--checkapi requires two inputs " << "but got " << options.InputFiles().size(); java::JavaTypeNamespace old_ns; old_ns.Init(); const string old_dir = options.InputFiles().at(0); vector old_types; vector old_files = io_delegate.ListFiles(old_dir); if (old_files.size() == 0) { AIDL_ERROR(old_dir) << "No API file exist"; return false; } for (const auto& file : old_files) { vector types; if (internals::load_and_validate_aidl(file, options, io_delegate, &old_ns, &types, nullptr /* imported_files */) != AidlError::OK) { AIDL_ERROR(file) << "Failed to read."; return false; } old_types.insert(old_types.end(), types.begin(), types.end()); } java::JavaTypeNamespace new_ns; new_ns.Init(); const string new_dir = options.InputFiles().at(1); vector new_types; vector new_files = io_delegate.ListFiles(new_dir); if (new_files.size() == 0) { AIDL_ERROR(new_dir) << "No API file exist"; return false; } for (const auto& file : new_files) { vector types; if (internals::load_and_validate_aidl(file, options, io_delegate, &new_ns, &types, nullptr /* imported_files */) != AidlError::OK) { AIDL_ERROR(file) << "Failed to read."; return false; } new_types.insert(new_types.end(), types.begin(), types.end()); } map new_map; for (const auto t : new_types) { new_map.emplace(t->GetCanonicalName(), t); } bool compatible = true; for (const auto old_type : old_types) { const auto found = new_map.find(old_type->GetCanonicalName()); if (found == new_map.end()) { AIDL_ERROR(old_type) << "Removed type: " << old_type->GetCanonicalName(); compatible = false; continue; } const auto new_type = found->second; const bool old_is_iface = old_type->AsInterface() != nullptr; const bool new_is_iface = new_type->AsInterface() != nullptr; if (old_is_iface != new_is_iface) { AIDL_ERROR(new_type) << "Type mismatch: " << old_type->GetCanonicalName() << " is changed from " << old_type->GetPreprocessDeclarationName() << " to " << new_type->GetPreprocessDeclarationName(); compatible = false; continue; } if (old_is_iface) { compatible &= are_compatible_interfaces(*(old_type->AsInterface()), *(new_type->AsInterface())); } else { CHECK(old_type->AsStructuredParcelable() != nullptr) << "Parcelable" << old_type->GetCanonicalName() << " is not structured. "; CHECK(new_type->AsStructuredParcelable() != nullptr) << "Parcelable" << new_type->GetCanonicalName() << " is not structured. "; compatible &= are_compatible_parcelables(*(old_type->AsStructuredParcelable()), *(new_type->AsStructuredParcelable())); } } return compatible; } } // namespace aidl } // namespace android aidl_apicheck.h0100644 0000000 0000000 00000001732 13755771705 012542 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "io_delegate.h" #include "options.h" namespace android { namespace aidl { // Compare the two API dumps, which are given as input files, and test whether // the second API dump is backwards compatible with the first API dump. bool check_api(const Options& options, const IoDelegate& io_delegate); } // namespace aidl } // namespace android aidl_language.cpp0100644 0000000 0000000 00000070054 13755771705 013114 0ustar000000000 0000000 #include "aidl_language.h" #include "aidl_typenames.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "aidl_language_y.h" #include "logging.h" #include "type_java.h" #include "type_namespace.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::pair; using std::set; using std::string; using std::unique_ptr; using std::vector; 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) {} AidlLocation::AidlLocation(const std::string& file, Point begin, Point end) : file_(file), begin_(begin), end_(end) {} std::ostream& operator<<(std::ostream& os, const AidlLocation& l) { os << l.file_ << ":" << l.begin_.line << "." << l.begin_.column << "-"; if (l.begin_.line != l.end_.line) { os << l.end_.line << "."; } os << l.end_.column; return os; } AidlNode::AidlNode(const AidlLocation& location) : location_(location) {} std::string AidlNode::PrintLocation() const { std::stringstream ss; ss << location_.file_ << ":" << location_.begin_.line; return ss.str(); } AidlError::AidlError(bool fatal) : os_(std::cerr), fatal_(fatal) { os_ << "ERROR: "; } static const string kNullable("nullable"); static const string kUtf8InCpp("utf8InCpp"); static const string kUnsupportedAppUsage("UnsupportedAppUsage"); static const string kSystemApi("SystemApi"); static const string kStableParcelable("JavaOnlyStableParcelable"); static const set kAnnotationNames{kNullable, kUtf8InCpp, kUnsupportedAppUsage, kSystemApi, kStableParcelable}; AidlAnnotation* AidlAnnotation::Parse(const AidlLocation& location, const string& name) { if (kAnnotationNames.find(name) == kAnnotationNames.end()) { std::ostringstream stream; stream << "'" << name << "' is not a recognized annotation. "; stream << "It must be one of:"; for (const string& kv : kAnnotationNames) { stream << " " << kv; } stream << "."; AIDL_ERROR(location) << stream.str(); return nullptr; } return new AidlAnnotation(location, name); } AidlAnnotation::AidlAnnotation(const AidlLocation& location, const string& name) : AidlNode(location), name_(name) {} static bool HasAnnotation(const vector& annotations, const string& name) { for (const auto& a : annotations) { if (a.GetName() == name) { return true; } } return false; } AidlAnnotatable::AidlAnnotatable(const AidlLocation& location) : AidlNode(location) {} bool AidlAnnotatable::IsNullable() const { return HasAnnotation(annotations_, kNullable); } bool AidlAnnotatable::IsUtf8InCpp() const { return HasAnnotation(annotations_, kUtf8InCpp); } bool AidlAnnotatable::IsUnsupportedAppUsage() const { return HasAnnotation(annotations_, kUnsupportedAppUsage); } bool AidlAnnotatable::IsSystemApi() const { return HasAnnotation(annotations_, kSystemApi); } bool AidlAnnotatable::IsStableParcelable() const { return HasAnnotation(annotations_, kStableParcelable); } string AidlAnnotatable::ToString() const { vector ret; for (const auto& a : annotations_) { ret.emplace_back(a.ToString()); } std::sort(ret.begin(), ret.end()); return Join(ret, " "); } AidlTypeSpecifier::AidlTypeSpecifier(const AidlLocation& location, const string& unresolved_name, bool is_array, vector>* type_params, const string& comments) : AidlAnnotatable(location), unresolved_name_(unresolved_name), is_array_(is_array), type_params_(type_params), comments_(comments) {} AidlTypeSpecifier AidlTypeSpecifier::ArrayBase() const { AIDL_FATAL_IF(!is_array_, this); AidlTypeSpecifier arrayBase = *this; arrayBase.is_array_ = false; return arrayBase; } string AidlTypeSpecifier::ToString() const { string ret = GetName(); if (IsGeneric()) { vector arg_names; for (const auto& ta : GetTypeParameters()) { arg_names.emplace_back(ta->ToString()); } ret += "<" + Join(arg_names, ",") + ">"; } if (IsArray()) { ret += "[]"; } return ret; } string AidlTypeSpecifier::Signature() const { string ret = ToString(); string annotations = AidlAnnotatable::ToString(); if (annotations != "") { ret = annotations + " " + ret; } return ret; } bool AidlTypeSpecifier::Resolve(android::aidl::AidlTypenames& typenames) { assert(!IsResolved()); pair result = typenames.ResolveTypename(unresolved_name_); if (result.second) { fully_qualified_name_ = result.first; } return result.second; } bool AidlTypeSpecifier::CheckValid(const AidlTypenames& typenames) const { if (IsGeneric()) { const string& type_name = GetName(); const int num = GetTypeParameters().size(); if (type_name == "List") { if (num > 1) { AIDL_ERROR(this) << " List cannot have type parameters more than one, but got " << "'" << ToString() << "'"; return false; } } else if (type_name == "Map") { if (num != 0 && num != 2) { AIDL_ERROR(this) << "Map must have 0 or 2 type parameters, but got " << "'" << ToString() << "'"; return false; } } } if (GetName() == "void") { if (IsArray() || IsNullable() || IsUtf8InCpp()) { AIDL_ERROR(this) << "void type cannot be an array or nullable or utf8 string"; return false; } } if (IsArray()) { const auto definedType = typenames.TryGetDefinedType(GetName()); if (definedType != nullptr && definedType->AsInterface() != nullptr) { AIDL_ERROR(this) << "Binder type cannot be an array"; return false; } } if (IsNullable()) { if (AidlTypenames::IsPrimitiveTypename(GetName()) && !IsArray()) { AIDL_ERROR(this) << "Primitive type cannot get nullable annotation"; return false; } } return true; } std::string AidlConstantValueDecorator(const AidlTypeSpecifier& /*type*/, const std::string& raw_value) { return raw_value; } AidlVariableDeclaration::AidlVariableDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name) : AidlVariableDeclaration(location, type, name, nullptr /*default_value*/) {} AidlVariableDeclaration::AidlVariableDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name, AidlConstantValue* default_value) : AidlNode(location), type_(type), name_(name), default_value_(default_value) {} bool AidlVariableDeclaration::CheckValid(const AidlTypenames& typenames) const { bool valid = true; valid &= type_->CheckValid(typenames); if (default_value_ == nullptr) return valid; valid &= default_value_->CheckValid(); if (!valid) return false; return !ValueString(AidlConstantValueDecorator).empty(); } string AidlVariableDeclaration::ToString() const { string ret = type_->Signature() + " " + name_; if (default_value_ != nullptr) { ret += " = " + ValueString(AidlConstantValueDecorator); } return ret; } string AidlVariableDeclaration::Signature() const { return type_->Signature() + " " + name_; } std::string AidlVariableDeclaration::ValueString(const ConstantValueDecorator& decorator) const { if (default_value_ != nullptr) { return GetDefaultValue()->As(GetType(), decorator); } else { return ""; } } AidlArgument::AidlArgument(const AidlLocation& location, AidlArgument::Direction direction, AidlTypeSpecifier* type, const std::string& name) : AidlVariableDeclaration(location, type, name), direction_(direction), direction_specified_(true) {} AidlArgument::AidlArgument(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name) : AidlVariableDeclaration(location, type, name), direction_(AidlArgument::IN_DIR), direction_specified_(false) {} string AidlArgument::GetDirectionSpecifier() 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; } } return ret; } string AidlArgument::ToString() const { return GetDirectionSpecifier() + AidlVariableDeclaration::ToString(); } std::string AidlArgument::Signature() const { class AidlInterface; class AidlInterface; class AidlParcelable; class AidlStructuredParcelable; class AidlParcelable; class AidlStructuredParcelable; return GetDirectionSpecifier() + AidlVariableDeclaration::Signature(); } AidlMember::AidlMember(const AidlLocation& location) : AidlNode(location) {} AidlConstantValue::AidlConstantValue(const AidlLocation& location, Type type, const std::string& checked_value) : AidlNode(location), type_(type), value_(checked_value) { CHECK(!value_.empty() || type_ == Type::ERROR); CHECK(type_ != Type::ARRAY); } AidlConstantValue::AidlConstantValue(const AidlLocation& location, Type type, std::vector>* values) : AidlNode(location), type_(type), values_(std::move(*values)) {} static bool isValidLiteralChar(char c) { return !(c <= 0x1f || // control characters are < 0x20 c >= 0x7f || // DEL is 0x7f c == '\\'); // Disallow backslashes for future proofing. } AidlConstantValue* AidlConstantValue::Boolean(const AidlLocation& location, bool value) { return new AidlConstantValue(location, Type::BOOLEAN, value ? "true" : "false"); } AidlConstantValue* AidlConstantValue::Character(const AidlLocation& location, char value) { if (!isValidLiteralChar(value)) { AIDL_ERROR(location) << "Invalid character literal " << value; return new AidlConstantValue(location, Type::ERROR, ""); } return new AidlConstantValue(location, Type::CHARACTER, std::string("'") + value + "'"); } AidlConstantValue* AidlConstantValue::Floating(const AidlLocation& location, const std::string& value) { return new AidlConstantValue(location, Type::FLOATING, value); } AidlConstantValue* AidlConstantValue::Hex(const AidlLocation& location, const std::string& value) { return new AidlConstantValue(location, Type::HEXIDECIMAL, value); } AidlConstantValue* AidlConstantValue::Integral(const AidlLocation& location, const std::string& value) { return new AidlConstantValue(location, Type::INTEGRAL, value); } AidlConstantValue* AidlConstantValue::Array( const AidlLocation& location, std::vector>* values) { return new AidlConstantValue(location, Type::ARRAY, values); } AidlConstantValue* AidlConstantValue::String(const AidlLocation& location, const std::string& value) { for (size_t i = 0; i < value.length(); ++i) { if (!isValidLiteralChar(value[i])) { AIDL_ERROR(location) << "Found invalid character at index " << i << " in string constant '" << value << "'"; return new AidlConstantValue(location, Type::ERROR, ""); } } return new AidlConstantValue(location, Type::STRING, value); } bool AidlConstantValue::CheckValid() const { // error always logged during creation return type_ != AidlConstantValue::Type::ERROR; } static string TrimIfSuffix(const string& str, const string& suffix) { if (str.size() > suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix)) { return str.substr(0, str.size() - suffix.size()); } return str; } string AidlConstantValue::As(const AidlTypeSpecifier& type, const ConstantValueDecorator& decorator) const { if (type.IsGeneric()) { AIDL_ERROR(type) << "Generic type cannot be specified with a constant literal."; return ""; } const std::string& type_string = type.GetName(); if ((type_ == Type::ARRAY) != type.IsArray()) { goto mismatch_error; } switch (type_) { case AidlConstantValue::Type::ARRAY: { vector raw_values; raw_values.reserve(values_.size()); bool success = true; for (const auto& value : values_) { const AidlTypeSpecifier& array_base = type.ArrayBase(); const std::string raw_value = value->As(array_base, decorator); success &= !raw_value.empty(); raw_values.push_back(decorator(array_base, raw_value)); } if (!success) { AIDL_ERROR(this) << "Default value must be a literal array of " << type_string << "."; return ""; } return decorator(type, "{" + Join(raw_values, ", ") + "}"); } case AidlConstantValue::Type::BOOLEAN: if (type_string == "boolean") return decorator(type, value_); goto mismatch_error; case AidlConstantValue::Type::CHARACTER: if (type_string == "char") return decorator(type, value_); goto mismatch_error; case AidlConstantValue::Type::FLOATING: { bool is_float_literal = value_.back() == 'f'; const std::string raw_value = TrimIfSuffix(value_, "f"); if (type_string == "double") { double parsed_value; if (!android::base::ParseDouble(raw_value, &parsed_value)) goto parse_error; return decorator(type, std::to_string(parsed_value)); } if (is_float_literal && type_string == "float") { float parsed_value; if (!android::base::ParseFloat(raw_value, &parsed_value)) goto parse_error; return decorator(type, std::to_string(parsed_value) + "f"); } goto mismatch_error; } case AidlConstantValue::Type::HEXIDECIMAL: // For historical reasons, a hexidecimal int needs to have the specified bits interpreted // as the signed type, so the other types are made consistent with it. if (type_string == "byte") { uint8_t unsigned_value; if (!android::base::ParseUint(value_, &unsigned_value)) goto parse_error; return decorator(type, std::to_string((int8_t)unsigned_value)); } if (type_string == "int") { uint32_t unsigned_value; if (!android::base::ParseUint(value_, &unsigned_value)) goto parse_error; return decorator(type, std::to_string((int32_t)unsigned_value)); } if (type_string == "long") { uint64_t unsigned_value; if (!android::base::ParseUint(value_, &unsigned_value)) goto parse_error; return decorator(type, std::to_string((int64_t)unsigned_value)); } goto mismatch_error; case AidlConstantValue::Type::INTEGRAL: if (type_string == "byte") { if (!android::base::ParseInt(value_, nullptr)) goto parse_error; return decorator(type, value_); } if (type_string == "int") { if (!android::base::ParseInt(value_, nullptr)) goto parse_error; return decorator(type, value_); } if (type_string == "long") { if (!android::base::ParseInt(value_, nullptr)) goto parse_error; return decorator(type, value_); } goto mismatch_error; case AidlConstantValue::Type::STRING: if (type_string == "String") return decorator(type, value_); goto mismatch_error; default: AIDL_FATAL(this) << "Unrecognized constant value type"; } mismatch_error: AIDL_ERROR(this) << "Expecting type " << type_string << " but constant is " << ToString(type_); return ""; parse_error: AIDL_ERROR(this) << "Could not parse " << value_ << " as " << type_string; return ""; } string AidlConstantValue::ToString(Type type) { switch (type) { case Type::ARRAY: return "a literal array"; case Type::BOOLEAN: return "a literal boolean"; case Type::CHARACTER: return "a literal char"; case Type::FLOATING: return "a floating-point literal"; case Type::HEXIDECIMAL: return "a hexidecimal literal"; case Type::INTEGRAL: return "an integral literal"; case Type::STRING: return "a literal string"; case Type::ERROR: LOG(FATAL) << "aidl internal error: error type failed to halt program"; return ""; default: LOG(FATAL) << "aidl internal error: unknown constant type: " << static_cast(type); return ""; // not reached } } AidlConstantDeclaration::AidlConstantDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name, AidlConstantValue* value) : AidlMember(location), type_(type), name_(name), value_(value) {} bool AidlConstantDeclaration::CheckValid(const AidlTypenames& typenames) const { bool valid = true; valid &= type_->CheckValid(typenames); valid &= value_->CheckValid(); if (!valid) return false; const static set kSupportedConstTypes = {"String", "int"}; if (kSupportedConstTypes.find(type_->ToString()) == kSupportedConstTypes.end()) { AIDL_ERROR(this) << "Constant of type " << type_->ToString() << " is not supported."; return false; } return !ValueString(AidlConstantValueDecorator).empty(); } string AidlConstantDeclaration::ToString() const { return "const " + type_->ToString() + " " + name_ + " = " + ValueString(AidlConstantValueDecorator); } string AidlConstantDeclaration::Signature() const { return type_->Signature() + " " + name_; } AidlMethod::AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type, const std::string& name, std::vector>* args, const std::string& comments) : AidlMethod(location, oneway, type, name, args, comments, 0, true) { has_id_ = false; } AidlMethod::AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type, const std::string& name, std::vector>* args, const std::string& comments, int id, bool is_user_defined) : AidlMember(location), oneway_(oneway), comments_(comments), type_(type), name_(name), arguments_(std::move(*args)), id_(id), is_user_defined_(is_user_defined) { 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()); } } } string AidlMethod::Signature() const { vector arg_signatures; for (const auto& arg : GetArguments()) { arg_signatures.emplace_back(arg->GetType().ToString()); } return GetName() + "(" + Join(arg_signatures, ", ") + ")"; } string AidlMethod::ToString() const { vector arg_strings; for (const auto& arg : GetArguments()) { arg_strings.emplace_back(arg->Signature()); } string ret = (IsOneway() ? "oneway " : "") + GetType().Signature() + " " + GetName() + "(" + Join(arg_strings, ", ") + ")"; if (HasId()) { ret += " = " + std::to_string(GetId()); } return ret; } AidlDefinedType::AidlDefinedType(const AidlLocation& location, const std::string& name, const std::string& comments, const std::vector& package) : AidlAnnotatable(location), name_(name), comments_(comments), package_(package) {} std::string AidlDefinedType::GetPackage() const { return Join(package_, '.'); } std::string AidlDefinedType::GetCanonicalName() const { if (package_.empty()) { return GetName(); } return GetPackage() + "." + GetName(); } AidlParcelable::AidlParcelable(const AidlLocation& location, AidlQualifiedName* name, const std::vector& package, const std::string& comments, const std::string& cpp_header) : AidlDefinedType(location, name->GetDotName(), comments, package), name_(name), 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); } } bool AidlParcelable::CheckValid(const AidlTypenames&) const { static const std::set allowed{kStableParcelable}; for (const auto& v : GetAnnotations()) { if (allowed.find(v.GetName()) == allowed.end()) { std::ostringstream stream; stream << "Unstructured parcelable can contain only"; for (const string& kv : allowed) { stream << " " << kv; } stream << "."; AIDL_ERROR(this) << stream.str(); return false; } } return true; } void AidlParcelable::Write(CodeWriter* writer) const { writer->Write("parcelable %s ;\n", GetName().c_str()); } AidlStructuredParcelable::AidlStructuredParcelable( const AidlLocation& location, AidlQualifiedName* name, const std::vector& package, const std::string& comments, std::vector>* variables) : AidlParcelable(location, name, package, comments, "" /*cpp_header*/), variables_(std::move(*variables)) {} void AidlStructuredParcelable::Write(CodeWriter* writer) const { writer->Write("parcelable %s {\n", GetName().c_str()); writer->Indent(); for (const auto& field : GetFields()) { writer->Write("%s;\n", field->ToString().c_str()); } writer->Dedent(); writer->Write("}\n"); } bool AidlStructuredParcelable::CheckValid(const AidlTypenames& typenames) const { for (const auto& v : GetFields()) { if (!(v->CheckValid(typenames))) { return false; } } return true; } AidlInterface::AidlInterface(const AidlLocation& location, const std::string& name, const std::string& comments, bool oneway, std::vector>* members, const std::vector& package) : AidlDefinedType(location, name, comments, package) { for (auto& member : *members) { AidlMember* local = member.release(); AidlMethod* method = local->AsMethod(); AidlConstantDeclaration* constant = local->AsConstantDeclaration(); CHECK(method == nullptr || constant == nullptr); if (method) { method->ApplyInterfaceOneway(oneway); methods_.emplace_back(method); } else if (constant) { constants_.emplace_back(constant); } else { AIDL_FATAL(this) << "Member is neither method nor constant!"; } } delete members; } void AidlInterface::Write(CodeWriter* writer) const { writer->Write("interface %s {\n", GetName().c_str()); writer->Indent(); for (const auto& method : GetMethods()) { writer->Write("%s;\n", method->ToString().c_str()); } for (const auto& constdecl : GetConstantDeclarations()) { writer->Write("%s;\n", constdecl->ToString().c_str()); } writer->Dedent(); writer->Write("}\n"); } bool AidlInterface::CheckValid(const AidlTypenames& typenames) const { // Has to be a pointer due to deleting copy constructor. No idea why. map method_names; for (const auto& m : GetMethods()) { if (!m->GetType().CheckValid(typenames)) { return false; } if (m->IsOneway() && m->GetType().GetName() != "void") { AIDL_ERROR(m) << "oneway method '" << m->GetName() << "' cannot return a value"; return false; } set argument_names; for (const auto& arg : m->GetArguments()) { auto it = argument_names.find(arg->GetName()); if (it != argument_names.end()) { AIDL_ERROR(m) << "method '" << m->GetName() << "' has duplicate argument name '" << arg->GetName() << "'"; return false; } argument_names.insert(arg->GetName()); if (!arg->GetType().CheckValid(typenames)) { return false; } if (m->IsOneway() && arg->IsOut()) { AIDL_ERROR(m) << "oneway method '" << m->GetName() << "' cannot have out parameters"; return false; } } auto it = method_names.find(m->GetName()); // prevent duplicate methods if (it == method_names.end()) { method_names[m->GetName()] = m.get(); } else { AIDL_ERROR(m) << "attempt to redefine method " << m->GetName() << ":"; AIDL_ERROR(it->second) << "previously defined here."; return false; } static set reserved_methods{"asBinder()", "getInterfaceVersion()", "getTransactionName(int)"}; if (reserved_methods.find(m->Signature()) != reserved_methods.end()) { AIDL_ERROR(m) << " method " << m->Signature() << " is reserved for internal use." << endl; return false; } } bool success = true; set constant_names; for (const std::unique_ptr& constant : GetConstantDeclarations()) { if (constant_names.count(constant->GetName()) > 0) { LOG(ERROR) << "Found duplicate constant name '" << constant->GetName() << "'"; success = false; } constant_names.insert(constant->GetName()); success = success && constant->CheckValid(typenames); } return success; } AidlQualifiedName::AidlQualifiedName(const AidlLocation& location, const std::string& term, const std::string& comments) : AidlNode(location), terms_({term}), comments_(comments) { if (term.find('.') != string::npos) { terms_ = Split(term, "."); for (const auto& subterm : terms_) { if (subterm.empty()) { AIDL_FATAL(this) << "Malformed qualified identifier: '" << term << "'"; } } } } void AidlQualifiedName::AddTerm(const std::string& term) { terms_.push_back(term); } AidlImport::AidlImport(const AidlLocation& location, const std::string& needed_class) : AidlNode(location), needed_class_(needed_class) {} std::unique_ptr Parser::Parse(const std::string& filename, const android::aidl::IoDelegate& io_delegate, AidlTypenames& typenames) { // Make sure we can read the file first, before trashing previous state. unique_ptr raw_buffer = io_delegate.GetFileContents(filename); if (raw_buffer == nullptr) { AIDL_ERROR(filename) << "Error while opening file for parsing"; return nullptr; } // We're going to scan this buffer in place, and yacc demands we put two // nulls at the end. raw_buffer->append(2u, '\0'); std::unique_ptr parser(new Parser(filename, *raw_buffer, typenames)); if (yy::parser(parser.get()).parse() != 0 || parser->HasError()) return nullptr; return parser; } std::vector Parser::Package() const { if (!package_) { return {}; } return package_->GetTerms(); } void Parser::AddImport(AidlImport* import) { imports_.emplace_back(import); } bool Parser::Resolve() { bool success = true; for (AidlTypeSpecifier* typespec : unresolved_typespecs_) { if (!typespec->Resolve(typenames_)) { AIDL_ERROR(typespec) << "Failed to resolve '" << typespec->GetUnresolvedName() << "'"; success = false; // don't stop to show more errors if any } } return success; } Parser::Parser(const std::string& filename, std::string& raw_buffer, android::aidl::AidlTypenames& typenames) : filename_(filename), typenames_(typenames) { yylex_init(&scanner_); buffer_ = yy_scan_buffer(&raw_buffer[0], raw_buffer.length(), scanner_); } Parser::~Parser() { yy_delete_buffer(buffer_, scanner_); yylex_destroy(scanner_); } aidl_language.h0100644 0000000 0000000 00000056263 13755771705 012567 0ustar000000000 0000000 #pragma once #include "aidl_typenames.h" #include "code_writer.h" #include "io_delegate.h" #include #include #include #include #include #include struct yy_buffer_state; typedef yy_buffer_state* YY_BUFFER_STATE; using android::aidl::AidlTypenames; using android::aidl::CodeWriter; using std::shared_ptr; using std::string; using std::unique_ptr; using std::vector; class AidlNode; namespace android { namespace aidl { namespace mappings { std::string dump_location(const AidlNode& method); } // namespace mappings } // namespace aidl } // namespace android 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 AidlLocation { public: struct Point { unsigned int line; unsigned int column; }; AidlLocation(const std::string& file, Point begin, Point end); friend std::ostream& operator<<(std::ostream& os, const AidlLocation& l); friend class AidlNode; private: const std::string file_; Point begin_; Point end_; }; #define AIDL_LOCATION_HERE \ AidlLocation { \ __FILE__, {__LINE__, 0}, { __LINE__, 0 } \ } std::ostream& operator<<(std::ostream& os, const AidlLocation& l); // Anything that is locatable in a .aidl file. class AidlNode { public: AidlNode(const AidlLocation& location); AidlNode(const AidlNode&) = default; AidlNode(AidlNode&&) = default; virtual ~AidlNode() = default; // DO NOT ADD. This is intentionally omitted. Nothing should refer to the location // for a functional purpose. It is only for error messages. // NO const AidlLocation& GetLocation() const { return location_; } NO // To be able to print AidlLocation (nothing else should use this information) friend class AidlError; friend std::string android::aidl::mappings::dump_location(const AidlNode&); private: std::string PrintLocation() const; const AidlLocation location_; }; // Generic point for printing any error in the AIDL compiler. class AidlError { public: AidlError(bool fatal, const std::string& filename) : AidlError(fatal) { os_ << filename << ": "; } AidlError(bool fatal, const AidlLocation& location) : AidlError(fatal) { os_ << location << ": "; } AidlError(bool fatal, const AidlNode& node) : AidlError(fatal, node.location_) {} AidlError(bool fatal, const AidlNode* node) : AidlError(fatal, *node) {} template AidlError(bool fatal, const std::unique_ptr& node) : AidlError(fatal, *node) {} ~AidlError() { os_ << std::endl; if (fatal_) abort(); } std::ostream& os_; private: AidlError(bool fatal); bool fatal_; DISALLOW_COPY_AND_ASSIGN(AidlError); }; #define AIDL_ERROR(CONTEXT) ::AidlError(false /*fatal*/, (CONTEXT)).os_ #define AIDL_FATAL(CONTEXT) ::AidlError(true /*fatal*/, (CONTEXT)).os_ #define AIDL_FATAL_IF(CONDITION, CONTEXT) \ if (CONDITION) AIDL_FATAL(CONTEXT) << "Bad internal state: " << #CONDITION << ": " namespace android { namespace aidl { class ValidatableType; class AidlTypenames; } // namespace aidl } // namespace android class AidlAnnotation : public AidlNode { public: static AidlAnnotation* Parse(const AidlLocation& location, const string& name); AidlAnnotation(const AidlAnnotation&) = default; AidlAnnotation(AidlAnnotation&&) = default; virtual ~AidlAnnotation() = default; const string& GetName() const { return name_; } string ToString() const { return "@" + name_; } const string& GetComments() const { return comments_; } void SetComments(const string& comments) { comments_ = comments; } private: AidlAnnotation(const AidlLocation& location, const string& name); const string name_; string comments_; }; static inline bool operator<(const AidlAnnotation& lhs, const AidlAnnotation& rhs) { return lhs.GetName() < rhs.GetName(); } static inline bool operator==(const AidlAnnotation& lhs, const AidlAnnotation& rhs) { return lhs.GetName() == rhs.GetName(); } class AidlAnnotatable : public AidlNode { public: AidlAnnotatable(const AidlLocation& location); AidlAnnotatable(const AidlAnnotatable&) = default; AidlAnnotatable(AidlAnnotatable&&) = default; virtual ~AidlAnnotatable() = default; void Annotate(vector&& annotations) { annotations_ = std::move(annotations); } bool IsNullable() const; bool IsUtf8InCpp() const; bool IsUnsupportedAppUsage() const; bool IsSystemApi() const; bool IsStableParcelable() const; std::string ToString() const; const vector& GetAnnotations() const { return annotations_; } private: vector annotations_; }; class AidlQualifiedName; // AidlTypeSpecifier represents a reference to either a built-in type, // a defined type, or a variant (e.g., array of generic) of a type. class AidlTypeSpecifier final : public AidlAnnotatable { public: AidlTypeSpecifier(const AidlLocation& location, const string& unresolved_name, bool is_array, vector>* type_params, const string& comments); virtual ~AidlTypeSpecifier() = default; // Copy of this type which is not an array. AidlTypeSpecifier ArrayBase() const; // Returns the full-qualified name of the base type. // int -> int // int[] -> int // List -> List // IFoo -> foo.bar.IFoo (if IFoo is in package foo.bar) const string& GetName() const { if (IsResolved()) { return fully_qualified_name_; } else { return GetUnresolvedName(); } } // Returns string representation of this type specifier. // This is GetBaseTypeName() + array modifieir or generic type parameters string ToString() const; std::string Signature() const; const string& GetUnresolvedName() const { return unresolved_name_; } const string& GetComments() const { return comments_; } void SetComments(const string& comment) { comments_ = comment; } bool IsResolved() const { return fully_qualified_name_ != ""; } bool IsArray() const { return is_array_; } bool IsGeneric() const { return type_params_ != nullptr; } const vector>& GetTypeParameters() const { return *type_params_; } // Resolve the base type name to a fully-qualified name. Return false if the // resolution fails. bool Resolve(android::aidl::AidlTypenames& typenames); bool CheckValid(const AidlTypenames& typenames) const; void SetLanguageType(const android::aidl::ValidatableType* language_type) { language_type_ = language_type; } template const T* GetLanguageType() const { return reinterpret_cast(language_type_); } private: AidlTypeSpecifier(const AidlTypeSpecifier&) = default; const string unresolved_name_; string fully_qualified_name_; bool is_array_; const shared_ptr>> type_params_; string comments_; const android::aidl::ValidatableType* language_type_ = nullptr; }; // Transforms a value string into a language specific form. Raw value as produced by // AidlConstantValue. using ConstantValueDecorator = std::function; // Returns the universal value unaltered. std::string AidlConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value); class AidlConstantValue; class AidlVariableDeclaration : public AidlNode { public: AidlVariableDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name); AidlVariableDeclaration(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name, AidlConstantValue* default_value); virtual ~AidlVariableDeclaration() = default; std::string GetName() const { return name_; } const AidlTypeSpecifier& GetType() const { return *type_; } const AidlConstantValue* GetDefaultValue() const { return default_value_.get(); } AidlTypeSpecifier* GetMutableType() { return type_.get(); } bool CheckValid(const AidlTypenames& typenames) const; std::string ToString() const; std::string Signature() const; std::string ValueString(const ConstantValueDecorator& decorator) const; private: std::unique_ptr type_; std::string name_; std::unique_ptr default_value_; DISALLOW_COPY_AND_ASSIGN(AidlVariableDeclaration); }; class AidlArgument : public AidlVariableDeclaration { public: enum Direction { IN_DIR = 1, OUT_DIR = 2, INOUT_DIR = 3 }; AidlArgument(const AidlLocation& location, AidlArgument::Direction direction, AidlTypeSpecifier* type, const std::string& name); AidlArgument(const AidlLocation& location, AidlTypeSpecifier* type, const std::string& name); 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_; } string GetDirectionSpecifier() const; std::string ToString() const; std::string Signature() const; private: Direction direction_; bool direction_specified_; DISALLOW_COPY_AND_ASSIGN(AidlArgument); }; class AidlMethod; class AidlConstantDeclaration; class AidlMember : public AidlNode { public: AidlMember(const AidlLocation& location); virtual ~AidlMember() = default; virtual AidlMethod* AsMethod() { return nullptr; } virtual AidlConstantDeclaration* AsConstantDeclaration() { return nullptr; } private: DISALLOW_COPY_AND_ASSIGN(AidlMember); }; class AidlConstantValue : public AidlNode { public: enum class Type { ERROR, ARRAY, BOOLEAN, CHARACTER, FLOATING, HEXIDECIMAL, INTEGRAL, STRING }; virtual ~AidlConstantValue() = default; static AidlConstantValue* Boolean(const AidlLocation& location, bool value); static AidlConstantValue* Character(const AidlLocation& location, char value); // example: "0x4f" static AidlConstantValue* Floating(const AidlLocation& location, const std::string& value); static AidlConstantValue* Hex(const AidlLocation& location, const std::string& value); // example: 123, -5498, maybe any size static AidlConstantValue* Integral(const AidlLocation& location, const std::string& value); static AidlConstantValue* Array(const AidlLocation& location, std::vector>* values); // example: "\"asdf\"" static AidlConstantValue* String(const AidlLocation& location, const std::string& value); Type GetType() const { return type_; } bool CheckValid() const; // Raw value of type (currently valid in C++ and Java). Empty string on error. string As(const AidlTypeSpecifier& type, const ConstantValueDecorator& decorator) const; private: AidlConstantValue(const AidlLocation& location, Type type, const std::string& checked_value); AidlConstantValue(const AidlLocation& location, Type type, std::vector>* values); static string ToString(Type type); const Type type_ = Type::ERROR; const std::vector> values_; // if type_ == ARRAY const std::string value_; // otherwise DISALLOW_COPY_AND_ASSIGN(AidlConstantValue); }; class AidlConstantDeclaration : public AidlMember { public: AidlConstantDeclaration(const AidlLocation& location, AidlTypeSpecifier* specifier, const std::string& name, AidlConstantValue* value); virtual ~AidlConstantDeclaration() = default; const AidlTypeSpecifier& GetType() const { return *type_; } AidlTypeSpecifier* GetMutableType() { return type_.get(); } const std::string& GetName() const { return name_; } const AidlConstantValue& GetValue() const { return *value_; } bool CheckValid(const AidlTypenames& typenames) const; std::string ToString() const; std::string Signature() const; string ValueString(const ConstantValueDecorator& decorator) const { return GetValue().As(GetType(), decorator); } AidlConstantDeclaration* AsConstantDeclaration() override { return this; } private: const unique_ptr type_; const std::string name_; const unique_ptr value_; DISALLOW_COPY_AND_ASSIGN(AidlConstantDeclaration); }; class AidlMethod : public AidlMember { public: AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type, const std::string& name, std::vector>* args, const std::string& comments); AidlMethod(const AidlLocation& location, bool oneway, AidlTypeSpecifier* type, const std::string& name, std::vector>* args, const std::string& comments, int id, bool is_user_defined = true); virtual ~AidlMethod() = default; AidlMethod* AsMethod() override { return this; } const std::string& GetComments() const { return comments_; } const AidlTypeSpecifier& GetType() const { return *type_; } AidlTypeSpecifier* GetMutableType() { return type_.get(); } // set if this method is part of an interface that is marked oneway void ApplyInterfaceOneway(bool oneway) { oneway_ = oneway_ || oneway; } bool IsOneway() const { return oneway_; } const std::string& GetName() const { return name_; } bool HasId() const { return has_id_; } int GetId() const { return id_; } void SetId(unsigned id) { id_ = id; } bool IsUserDefined() const { return is_user_defined_; } 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_; } // name + type parameter types // i.e, foo(int, String) std::string Signature() const; // return type + name + type parameter types + annotations // i.e, boolean foo(int, @Nullable String) std::string ToString() const; private: bool oneway_; std::string comments_; std::unique_ptr type_; std::string name_; const std::vector> arguments_; std::vector in_arguments_; std::vector out_arguments_; bool has_id_; int id_; bool is_user_defined_ = true; DISALLOW_COPY_AND_ASSIGN(AidlMethod); }; class AidlDefinedType; class AidlInterface; class AidlParcelable; class AidlStructuredParcelable; class AidlQualifiedName : public AidlNode { public: AidlQualifiedName(const AidlLocation& location, const std::string& term, const 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 AidlInterface; class AidlParcelable; class AidlStructuredParcelable; // AidlDefinedType represents either an interface or a parcelable that is // defined in the source file. class AidlDefinedType : public AidlAnnotatable { public: AidlDefinedType(const AidlLocation& location, const std::string& name, const std::string& comments, const std::vector& package); virtual ~AidlDefinedType() = default; const std::string& GetName() const { return name_; }; const std::string& GetComments() const { return comments_; } void SetComments(const std::string comments) { comments_ = comments; } /* dot joined package, example: "android.package.foo" */ std::string GetPackage() const; /* dot joined package and name, example: "android.package.foo.IBar" */ std::string GetCanonicalName() const; const std::vector& GetSplitPackage() const { return package_; } virtual std::string GetPreprocessDeclarationName() const = 0; virtual const AidlStructuredParcelable* AsStructuredParcelable() const { return nullptr; } virtual const AidlParcelable* AsParcelable() const { return nullptr; } virtual const AidlInterface* AsInterface() const { return nullptr; } virtual bool CheckValid(const AidlTypenames&) const { return true; } AidlStructuredParcelable* AsStructuredParcelable() { return const_cast( const_cast(this)->AsStructuredParcelable()); } AidlParcelable* AsParcelable() { return const_cast(const_cast(this)->AsParcelable()); } AidlInterface* AsInterface() { return const_cast(const_cast(this)->AsInterface()); } const AidlParcelable* AsUnstructuredParcelable() const { if (this->AsStructuredParcelable() != nullptr) return nullptr; return this->AsParcelable(); } AidlParcelable* AsUnstructuredParcelable() { return const_cast( const_cast(this)->AsUnstructuredParcelable()); } void SetLanguageType(const android::aidl::ValidatableType* language_type) { language_type_ = language_type; } template const T* GetLanguageType() const { return reinterpret_cast(language_type_); } virtual void Write(CodeWriter* writer) const = 0; private: std::string name_; std::string comments_; const android::aidl::ValidatableType* language_type_ = nullptr; const std::vector package_; DISALLOW_COPY_AND_ASSIGN(AidlDefinedType); }; class AidlParcelable : public AidlDefinedType { public: AidlParcelable(const AidlLocation& location, AidlQualifiedName* name, const std::vector& package, const std::string& comments, const std::string& cpp_header = ""); virtual ~AidlParcelable() = default; // C++ uses "::" instead of "." to refer to a inner class. std::string GetCppName() const { return name_->GetColonName(); } std::string GetCppHeader() const { return cpp_header_; } bool CheckValid(const AidlTypenames& typenames) const override; const AidlParcelable* AsParcelable() const override { return this; } std::string GetPreprocessDeclarationName() const override { return "parcelable"; } void Write(CodeWriter* writer) const override; private: std::unique_ptr name_; std::string cpp_header_; DISALLOW_COPY_AND_ASSIGN(AidlParcelable); }; class AidlStructuredParcelable : public AidlParcelable { public: AidlStructuredParcelable(const AidlLocation& location, AidlQualifiedName* name, const std::vector& package, const std::string& comments, std::vector>* variables); const std::vector>& GetFields() const { return variables_; } const AidlStructuredParcelable* AsStructuredParcelable() const override { return this; } std::string GetPreprocessDeclarationName() const override { return "structured_parcelable"; } void Write(CodeWriter* writer) const override; bool CheckValid(const AidlTypenames& typenames) const override; private: const std::vector> variables_; DISALLOW_COPY_AND_ASSIGN(AidlStructuredParcelable); }; class AidlInterface final : public AidlDefinedType { public: AidlInterface(const AidlLocation& location, const std::string& name, const std::string& comments, bool oneway_, std::vector>* members, const std::vector& package); virtual ~AidlInterface() = default; const std::vector>& GetMethods() const { return methods_; } std::vector>& GetMutableMethods() { return methods_; } const std::vector>& GetConstantDeclarations() const { return constants_; } const AidlInterface* AsInterface() const override { return this; } std::string GetPreprocessDeclarationName() const override { return "interface"; } void Write(CodeWriter* writer) const override; bool CheckValid(const AidlTypenames& typenames) const override; private: std::vector> methods_; std::vector> constants_; DISALLOW_COPY_AND_ASSIGN(AidlInterface); }; class AidlImport : public AidlNode { public: AidlImport(const AidlLocation& location, const std::string& needed_class); virtual ~AidlImport() = default; const std::string& GetFilename() const { return filename_; } const std::string& GetNeededClass() const { return needed_class_; } private: std::string filename_; std::string needed_class_; DISALLOW_COPY_AND_ASSIGN(AidlImport); }; class Parser { public: ~Parser(); // Parse contents of file |filename|. Should only be called once. static std::unique_ptr Parse(const std::string& filename, const android::aidl::IoDelegate& io_delegate, AidlTypenames& typenames); void AddError() { error_++; } bool HasError() { return error_ != 0; } const std::string& FileName() const { return filename_; } void* Scanner() const { return scanner_; } void AddImport(AidlImport* import); const std::vector>& GetImports() { return imports_; } void ReleaseImports(std::vector>* ret) { *ret = std::move(imports_); imports_.clear(); } void SetPackage(unique_ptr name) { package_ = std::move(name); } std::vector Package() const; void DeferResolution(AidlTypeSpecifier* typespec) { unresolved_typespecs_.emplace_back(typespec); } const vector& GetUnresolvedTypespecs() const { return unresolved_typespecs_; } bool Resolve(); void AddDefinedType(unique_ptr type) { // Parser does NOT own AidlDefinedType, it just has references to the types // that it encountered while parsing the input file. defined_types_.emplace_back(type.get()); // AidlDefinedType IS owned by AidlTypenames if (!typenames_.AddDefinedType(std::move(type))) { AddError(); } } vector& GetDefinedTypes() { return defined_types_; } private: explicit Parser(const std::string& filename, std::string& raw_buffer, android::aidl::AidlTypenames& typenames); std::string filename_; std::unique_ptr package_; AidlTypenames& typenames_; void* scanner_ = nullptr; YY_BUFFER_STATE buffer_; int error_ = 0; std::vector> imports_; vector defined_types_; vector unresolved_typespecs_; DISALLOW_COPY_AND_ASSIGN(Parser); }; aidl_language_l.ll0100644 0000000 0000000 00000010124 13755771705 013244 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 nounput %option noinput %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]+ floatvalue [-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?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 '>'; } /* annotations */ @{identifier} { yylval->token = new AidlToken(yytext + 1, extra_text); return yy::parser::token::ANNOTATION; } /* keywords */ parcelable { yylval->token = new AidlToken("parcelable", extra_text); return yy::parser::token::PARCELABLE; } import { return yy::parser::token::IMPORT; } package { return yy::parser::token::PACKAGE; } 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; } true { return yy::parser::token::TRUE_LITERAL; } false { return yy::parser::token::FALSE_LITERAL; } 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; } '.' { yylval->character = yytext[1]; return yy::parser::token::CHARVALUE; } {intvalue} { yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::INTVALUE; } {floatvalue} { yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::FLOATVALUE; } {hexvalue} { yylval->token = new AidlToken(yytext, extra_text); return yy::parser::token::HEXVALUE; } /* lexical error! */ . { return yy::parser::token::UNKNOWN; } %% // comment and whitespace handling // ================================================ aidl_language_y.yy0100644 0000000 0000000 00000024650 13755771705 013324 0ustar000000000 0000000 %{ #include "aidl_language.h" #include "aidl_language_y.h" #include "logging.h" #include #include #include #include int yylex(yy::parser::semantic_type *, yy::parser::location_type *, void *); AidlLocation loc(const yy::parser::location_type& l) { CHECK(l.begin.filename == l.end.filename); AidlLocation::Point begin { .line = l.begin.line, .column = l.begin.column, }; AidlLocation::Point end { .line = l.end.line, .column = l.end.column, }; return AidlLocation(*l.begin.filename, begin, end); } #define lex_scanner ps->Scanner() %} %initial-action { @$.begin.filename = @$.end.filename = const_cast(&ps->FileName()); } %parse-param { Parser* ps } %lex-param { void *lex_scanner } %pure-parser %glr-parser %skeleton "glr.cc" %expect-rr 0 %error-verbose %union { AidlToken* token; char character; std::string *str; AidlAnnotation* annotation; std::vector* annotation_list; AidlTypeSpecifier* type; AidlArgument* arg; AidlArgument::Direction direction; AidlConstantValue* constant_value; std::vector>* constant_value_list; std::vector>* arg_list; AidlVariableDeclaration* variable; std::vector>* variable_list; AidlMethod* method; AidlMember* constant; std::vector>* interface_members; AidlQualifiedName* qname; AidlInterface* interface; AidlParcelable* parcelable; AidlDefinedType* declaration; std::vector>* type_args; } %token ANNOTATION "annotation" %token C_STR "string literal" %token IDENTIFIER "identifier" %token INTERFACE "interface" %token PARCELABLE "parcelable" %token ONEWAY "oneway" %token CHARVALUE "char literal" %token FLOATVALUE "float literal" %token HEXVALUE "hex literal" %token INTVALUE "int literal" %token '(' ')' ',' '=' '[' ']' '<' '>' '.' '{' '}' ';' %token CONST "const" %token UNKNOWN "unrecognized character" %token CPP_HEADER "cpp_header" %token IMPORT "import" %token IN "in" %token INOUT "inout" %token OUT "out" %token PACKAGE "package" %token TRUE_LITERAL "true" %token FALSE_LITERAL "false" %type decl %type variable_decls %type variable_decl %type interface_members %type unannotated_decl %type interface_decl %type parcelable_decl %type method_decl %type constant_decl %type annotation %typeannotation_list %type type %type unannotated_type %type arg_list %type arg %type direction %type type_args %type qualified_name %type constant_value %type constant_value_list %type constant_value_non_empty_list %type identifier error %% document : package imports decls {}; /* 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", ""); } ; package : {} | PACKAGE qualified_name ';' { ps->SetPackage(unique_ptr($2)); }; imports : {} | import imports {}; import : IMPORT qualified_name ';' { ps->AddImport(new AidlImport(loc(@2), $2->GetDotName())); delete $2; }; qualified_name : identifier { $$ = new AidlQualifiedName(loc(@1), $1->GetText(), $1->GetComments()); delete $1; } | qualified_name '.' identifier { $$ = $1; $$->AddTerm($3->GetText()); delete $3; }; decls : decl { ps->AddDefinedType(unique_ptr($1)); } | decls decl { ps->AddDefinedType(unique_ptr($2)); }; decl : annotation_list unannotated_decl { $$ = $2; if ($1->size() > 0) { // copy comments from annotation to decl $2->SetComments($1->begin()->GetComments()); } $$->Annotate(std::move(*$1)); delete $1; } ; unannotated_decl : parcelable_decl { $$ = $1; } | interface_decl { $$ = $1; } ; parcelable_decl : PARCELABLE qualified_name ';' { $$ = new AidlParcelable(loc(@2), $2, ps->Package(), $1->GetComments()); } | PARCELABLE qualified_name CPP_HEADER C_STR ';' { $$ = new AidlParcelable(loc(@2), $2, ps->Package(), $1->GetComments(), $4->GetText()); } | PARCELABLE identifier '{' variable_decls '}' { AidlQualifiedName* name = new AidlQualifiedName(loc(@2), $2->GetText(), $2->GetComments()); $$ = new AidlStructuredParcelable(loc(@2), name, ps->Package(), $1->GetComments(), $4); } | PARCELABLE error ';' { ps->AddError(); $$ = NULL; }; variable_decls : /* empty */ { $$ = new std::vector>; } | variable_decls variable_decl { $$ = $1; if ($2 != nullptr) { $$->push_back(std::unique_ptr($2)); } }; variable_decl : type identifier ';' { $$ = new AidlVariableDeclaration(loc(@2), $1, $2->GetText()); } | type identifier '=' constant_value ';' { $$ = new AidlVariableDeclaration(loc(@2), $1, $2->GetText(), $4); } | error ';' { ps->AddError(); $$ = nullptr; } interface_decl : INTERFACE identifier '{' interface_members '}' { $$ = new AidlInterface(loc(@1), $2->GetText(), $1->GetComments(), false, $4, ps->Package()); delete $1; delete $2; } | ONEWAY INTERFACE identifier '{' interface_members '}' { $$ = new AidlInterface(loc(@2), $3->GetText(), $1->GetComments(), true, $5, ps->Package()); delete $1; delete $2; delete $3; } | INTERFACE error '{' interface_members '}' { ps->AddError(); $$ = nullptr; delete $1; delete $2; delete $4; }; interface_members : { $$ = new std::vector>(); } | interface_members method_decl { $1->push_back(std::unique_ptr($2)); } | interface_members constant_decl { $1->push_back(std::unique_ptr($2)); } | interface_members error ';' { ps->AddError(); $$ = $1; }; constant_value : TRUE_LITERAL { $$ = AidlConstantValue::Boolean(loc(@1), true); } | FALSE_LITERAL { $$ = AidlConstantValue::Boolean(loc(@1), false); } | CHARVALUE { $$ = AidlConstantValue::Character(loc(@1), $1); } | INTVALUE { $$ = AidlConstantValue::Integral(loc(@1), $1->GetText()); delete $1; } | FLOATVALUE { $$ = AidlConstantValue::Floating(loc(@1), $1->GetText()); delete $1; } | HEXVALUE { $$ = AidlConstantValue::Hex(loc(@1), $1->GetText()); delete $1; } | C_STR { $$ = AidlConstantValue::String(loc(@1), $1->GetText()); delete $1; } | '{' constant_value_list '}' { $$ = AidlConstantValue::Array(loc(@1), $2); delete $2; } ; constant_value_list : /* empty */ { $$ = new std::vector>; } | constant_value_non_empty_list { $$ = $1; } ; constant_value_non_empty_list : constant_value { $$ = new std::vector>; $$->push_back(std::unique_ptr($1)); } | constant_value_non_empty_list ',' constant_value { $$ = $1; $$->push_back(std::unique_ptr($3)); } ; constant_decl : CONST type identifier '=' constant_value ';' { $$ = new AidlConstantDeclaration(loc(@3), $2, $3->GetText(), $5); delete $3; } ; method_decl : type identifier '(' arg_list ')' ';' { $$ = new AidlMethod(loc(@2), false, $1, $2->GetText(), $4, $1->GetComments()); delete $2; } | ONEWAY type identifier '(' arg_list ')' ';' { $$ = new AidlMethod(loc(@3), true, $2, $3->GetText(), $5, $1->GetComments()); delete $1; delete $3; } | type identifier '(' arg_list ')' '=' INTVALUE ';' { $$ = new AidlMethod(loc(@2), false, $1, $2->GetText(), $4, $1->GetComments(), std::stoi($7->GetText())); delete $2; } | ONEWAY type identifier '(' arg_list ')' '=' INTVALUE ';' { $$ = new AidlMethod(loc(@3), true, $2, $3->GetText(), $5, $1->GetComments(), std::stoi($8->GetText())); 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)); }; arg : direction type identifier { $$ = new AidlArgument(loc(@3), $1, $2, $3->GetText()); delete $3; } | type identifier { $$ = new AidlArgument(loc(@2), $1, $2->GetText()); delete $2; } | error { ps->AddError(); }; unannotated_type : qualified_name { $$ = new AidlTypeSpecifier(loc(@1), $1->GetDotName(), false, nullptr, $1->GetComments()); ps->DeferResolution($$); delete $1; } | qualified_name '[' ']' { $$ = new AidlTypeSpecifier(loc(@1), $1->GetDotName(), true, nullptr, $1->GetComments()); ps->DeferResolution($$); delete $1; } | qualified_name '<' type_args '>' { $$ = new AidlTypeSpecifier(loc(@1), $1->GetDotName(), false, $3, $1->GetComments()); ps->DeferResolution($$); delete $1; }; type : annotation_list unannotated_type { $$ = $2; if ($1->size() > 0) { // copy comments from annotation to type $2->SetComments($1->begin()->GetComments()); } $2->Annotate(std::move(*$1)); delete $1; }; type_args : unannotated_type { $$ = new std::vector>(); $$->emplace_back($1); } | type_args ',' unannotated_type { $1->emplace_back($3); }; annotation_list : { $$ = new std::vector(); } | annotation_list annotation { if ($2 != nullptr) { $1->emplace_back(std::move(*$2)); delete $2; } }; annotation : ANNOTATION { $$ = AidlAnnotation::Parse(loc(@1), $1->GetText()); if ($$ == nullptr) { ps->AddError(); } $$->SetComments($1->GetComments()); }; 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) { AIDL_ERROR(loc(l)) << errstr; // parser will return error value } aidl_to_cpp.cpp0100644 0000000 0000000 00000002551 13755771705 012612 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "aidl_to_cpp.h" #include "aidl_language.h" #include "logging.h" #include #include using std::ostringstream; namespace android { namespace aidl { namespace cpp { std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value) { if (type.GetName() == "String" && !type.IsArray() && !type.IsUtf8InCpp()) { return "::android::String16(" + raw_value + ")"; } return raw_value; }; std::string GetTransactionIdFor(const AidlMethod& method) { ostringstream output; output << "::android::IBinder::FIRST_CALL_TRANSACTION + "; output << method.GetId() << " /* " << method.GetName() << " */"; return output.str(); } } // namespace cpp } // namespace aidl } // namespace android aidl_to_cpp.h0100644 0000000 0000000 00000002673 13755771705 012264 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "aidl_language.h" namespace android { namespace aidl { namespace cpp { // This header provides functions that translate AIDL things to cpp things. std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value); struct CodeGeneratorContext { CodeWriter& writer; const AidlTypenames& types; const AidlTypeSpecifier& type; // an argument or return type to generate code for const string name; // name of the variable for the argument or the return value const bool isPointer; // whether the variable 'name' is a pointer or not const string log; // name of the variable of type Json::Value to write the log into }; std::string GetTransactionIdFor(const AidlMethod& method); } // namespace cpp } // namespace aidl } // namespace android aidl_to_cpp_common.cpp0100644 0000000 0000000 00000026620 13755771705 014165 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "aidl_to_cpp_common.h" #include "logging.h" #include "os.h" namespace android { namespace aidl { namespace cpp { string ClassName(const AidlDefinedType& defined_type, ClassNames type) { string base_name = defined_type.GetName(); if (base_name.length() >= 2 && base_name[0] == 'I' && isupper(base_name[1])) { base_name = base_name.substr(1); } switch (type) { case ClassNames::CLIENT: return "Bp" + base_name; case ClassNames::SERVER: return "Bn" + base_name; case ClassNames::INTERFACE: return "I" + base_name; case ClassNames::DEFAULT_IMPL: return "I" + base_name + "Default"; case ClassNames::BASE: return base_name; case ClassNames::RAW: [[fallthrough]]; default: return defined_type.GetName(); } } std::string HeaderFile(const AidlDefinedType& defined_type, ClassNames class_type, bool use_os_sep) { std::string file_path = defined_type.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(defined_type, class_type); file_path += ".h"; return file_path; } void EnterNamespace(CodeWriter& out, const AidlDefinedType& defined_type) { const std::vector packages = defined_type.GetSplitPackage(); for (const std::string& package : packages) { out << "namespace " << package << " {\n"; } } void LeaveNamespace(CodeWriter& out, const AidlDefinedType& defined_type) { const std::vector packages = defined_type.GetSplitPackage(); for (auto it = packages.rbegin(); it != packages.rend(); ++it) { out << "} // namespace " << *it << "\n"; } } string BuildVarName(const AidlArgument& a) { string prefix = "out_"; if (a.GetDirection() & AidlArgument::IN_DIR) { prefix = "in_"; } return prefix + a.GetName(); } struct TypeInfo { // name of the type in C++ output std::string cpp_name; // function that writes an expression to convert a variable to a Json::Value // object std::function toJsonValueExpr; }; const static std::unordered_map kTypeInfoMap = { {"void", {"void", nullptr}}, {"boolean", { "bool", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(" << var_name << "? \"true\" : \"false\")"; }, }}, {"byte", { "int8_t", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(" << var_name << ")"; }, }}, {"char", { "char16_t", [](CodeWriter& c, const string& var_name, bool isNdk) { if (isNdk) { c << "Json::Value(" << var_name << ")"; } else { c << "Json::Value(std::string(android::String8(&" << var_name << ", 1)))"; } }, }}, {"int", { "int32_t", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(" << var_name << ")"; }, }}, {"long", { "int64_t", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(static_cast(" << var_name << "))"; }, }}, {"float", { "float", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(" << var_name << ")"; }, }}, {"double", { "double", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(" << var_name << ")"; }, }}, {"String", { "std::string", [](CodeWriter& c, const string& var_name, bool) { c << "Json::Value(" << var_name << ")"; }, }} // missing List, Map, ParcelFileDescriptor, IBinder }; TypeInfo GetTypeInfo(const AidlTypeSpecifier& aidl) { CHECK(aidl.IsResolved()) << aidl.ToString(); const string& aidl_name = aidl.GetName(); TypeInfo info; if (AidlTypenames::IsBuiltinTypename(aidl_name)) { auto it = kTypeInfoMap.find(aidl_name); if (it != kTypeInfoMap.end()) { info = it->second; } } // Missing interface and parcelable type return info; } inline bool CanWriteLog(const TypeInfo& t) { return t.cpp_name != ""; } bool CanWriteLog(const AidlTypeSpecifier& aidl) { return CanWriteLog(GetTypeInfo(aidl)); } void WriteLogFor(CodeWriter& writer, const AidlTypeSpecifier& type, const std::string& name, bool isPointer, const std::string& log, bool isNdk) { const TypeInfo info = GetTypeInfo(type); if (!CanWriteLog(info)) { return; } const string var_object_expr = ((isPointer ? "*" : "")) + name; if (type.IsArray()) { writer << log << " = Json::Value(Json::arrayValue);\n"; writer << "for (const auto& v: " << var_object_expr << ") " << log << ".append("; info.toJsonValueExpr(writer, "v", isNdk); writer << ");"; } else { writer << log << " = "; info.toJsonValueExpr(writer, var_object_expr, isNdk); writer << ";"; } writer << "\n"; } void WriteLogForArguments(CodeWriterPtr& writer, const AidlArgument& a, bool isServer, string logVarName, bool isNdk) { if (!CanWriteLog(a.GetType())) { return; } string logElementVarName = "_log_arg_element"; (*writer) << "{\n"; (*writer).Indent(); (*writer) << "Json::Value " << logElementVarName << "(Json::objectValue);\n"; string varName = isServer || isNdk ? BuildVarName(a) : a.GetName(); (*writer) << logElementVarName << "[\"name\"] = \"" << varName << "\";\n"; bool isPointer = a.IsOut() && !isServer; WriteLogFor(*(writer.get()), a.GetType(), varName, isPointer, logElementVarName + "[\"value\"]", isNdk); (*writer) << logVarName << ".append(" << logElementVarName << ");\n"; (*writer) << "}\n"; (*writer).Dedent(); } const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer, bool isNdk) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); (*writer) << "Json::Value _log_input_args(Json::arrayValue);\n"; (*writer) << "if (" << className << "::logFunc != nullptr) {\n"; (*writer).Indent(); for (const auto& a : method.GetArguments()) { if (a->IsIn()) { WriteLogForArguments(writer, *a, isServer, "_log_input_args", isNdk); } } (*writer).Dedent(); (*writer) << "}\n"; (*writer) << "auto _log_start = std::chrono::steady_clock::now();\n"; writer->Close(); return code; } const string GenLogAfterExecute(const string className, const AidlInterface& interface, const AidlMethod& method, const string& statusVarName, const string& returnVarName, bool isServer, bool isNdk) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); (*writer) << "if (" << className << "::logFunc != nullptr) {\n"; (*writer).Indent(); // Write the log as a Json object. For example, // // Json log object for following interface description // // package foo.bar; // interface IFoo { // String TestMethod(int arg1, inout String[] arg2, out double arg3); // } // // would be: // // { // duration_ms: 100.42, // interface_name: "foo.bar.IFoo", // method_name: "TestMethod", // (proxy|stub)_address: "0x12345678", // input_args: [ // {name: "arg1", value: 30,}, // {name: "arg2", value: ["apple", "grape"],}, // ], // output_args: [ // {name: "arg2", value: ["mango", "banana"],}, // {name: "arg3", value: "10.5",}, // ], // _aidl_return: "ok", // binder_status: { // exception_code: -8, // exception_message: "Something wrong", // transaction_error: 0, // service_specific_error_code: -42, // }, // } (*writer) << "auto _log_end = std::chrono::steady_clock::now();\n"; (*writer) << "Json::Value _log_transaction(Json::objectValue);\n"; (*writer) << "_log_transaction[\"duration_ms\"] = " << "std::chrono::duration(_log_end - " "_log_start).count();\n"; (*writer) << "_log_transaction[\"interface_name\"] = " << "Json::Value(\"" << interface.GetCanonicalName() << "\");\n"; (*writer) << "_log_transaction[\"method_name\"] = " << "Json::Value(\"" << method.GetName() << "\");\n"; (*writer) << "_log_transaction[\"" << (isServer ? "stub_address" : "proxy_address") << "\"] = "; (*writer) << "Json::Value(" << "(std::ostringstream() << " << (isNdk && isServer ? "_aidl_impl" : "static_cast(this)") << ").str()" << ");\n"; (*writer) << "_log_transaction[\"input_args\"] = _log_input_args;\n"; (*writer) << "Json::Value _log_output_args(Json::arrayValue);\n"; (*writer) << "Json::Value _log_status(Json::objectValue);\n"; if (isNdk) { (*writer) << "_log_status[\"exception_code\"] = Json::Value(AStatus_getExceptionCode(" << statusVarName << ".get()));\n"; (*writer) << "_log_status[\"exception_message\"] = Json::Value(AStatus_getMessage(" << statusVarName << ".get()));\n"; (*writer) << "_log_status[\"transaction_error\"] = Json::Value(AStatus_getStatus(" << statusVarName << ".get()));\n"; (*writer) << "_log_status[\"service_specific_error_code\"] = " "Json::Value(AStatus_getServiceSpecificError(" << statusVarName << ".get()));\n"; } else { (*writer) << "_log_status[\"exception_code\"] = Json::Value(" << statusVarName << ".exceptionCode());\n"; (*writer) << "_log_status[\"exception_message\"] = Json::Value(" << statusVarName << ".exceptionMessage());\n"; (*writer) << "_log_status[\"transaction_error\"] = Json::Value(" << statusVarName << ".transactionError());\n"; (*writer) << "_log_status[\"service_specific_error_code\"] = Json::Value(" << statusVarName << ".serviceSpecificErrorCode());\n"; } (*writer) << "_log_transaction[\"binder_status\"] = _log_status;\n"; for (const auto& a : method.GetOutArguments()) { WriteLogForArguments(writer, *a, isServer, "_log_output_args", isNdk); } (*writer) << "_log_transaction[\"output_args\"] = _log_output_args;\n"; if (method.GetType().GetName() != "void") { WriteLogFor(*(writer.get()), method.GetType(), returnVarName, !isServer, "_log_transaction[\"" + returnVarName + "\"]", isNdk); } // call the user-provided function with the Json object for the entire // transaction (*writer) << className << "::logFunc(_log_transaction);\n"; (*writer).Dedent(); (*writer) << "}\n"; writer->Close(); return code; } } // namespace cpp } // namespace aidl } // namespace android aidl_to_cpp_common.h0100644 0000000 0000000 00000004313 13755771705 013625 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include "aidl_language.h" // This is used to help generate code targetting C++ (the language) whether using the libbinder or // libbinder_ndk backend. namespace android { namespace aidl { namespace cpp { // 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 DEFAULT_IMPL, // IFooDefault RAW, // (as shown in the file) }; string ClassName(const AidlDefinedType& defined_type, ClassNames type); // 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 AidlDefinedType& defined_type, ClassNames class_type, bool use_os_sep = true); void EnterNamespace(CodeWriter& out, const AidlDefinedType& defined_type); void LeaveNamespace(CodeWriter& out, const AidlDefinedType& defined_type); string BuildVarName(const AidlArgument& a); const string GenLogBeforeExecute(const string className, const AidlMethod& method, bool isServer, bool isNdk); const string GenLogAfterExecute(const string className, const AidlInterface& interface, const AidlMethod& method, const string& statusVarName, const string& returnVarName, bool isServer, bool isNdk); } // namespace cpp } // namespace aidl } // namespace android aidl_to_java.cpp0100644 0000000 0000000 00000060076 13755771705 012757 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "aidl_to_java.h" #include "aidl_language.h" #include "aidl_typenames.h" #include "logging.h" #include #include #include #include #include #include #include namespace android { namespace aidl { namespace java { using android::base::Join; using std::endl; using std::function; using std::map; using std::string; using std::vector; std::string ConstantValueDecorator(const AidlTypeSpecifier& /*type*/, const std::string& raw_value) { // no difference return raw_value; }; const string& JavaNameOf(const AidlTypeSpecifier& aidl) { CHECK(aidl.IsResolved()) << aidl.ToString(); // map from AIDL built-in type name to the corresponding Java type name static map m = { {"void", "void"}, {"boolean", "boolean"}, {"byte", "byte"}, {"char", "char"}, {"int", "int"}, {"long", "long"}, {"float", "float"}, {"double", "double"}, {"String", "java.lang.String"}, {"List", "java.util.List"}, {"Map", "java.util.Map"}, {"IBinder", "android.os.IBinder"}, {"FileDescriptor", "java.io.FileDescriptor"}, {"CharSequence", "java.lang.CharSequence"}, {"ParcelFileDescriptor", "android.os.ParcelFileDescriptor"}, }; const string& aidl_name = aidl.GetName(); if (m.find(aidl_name) != m.end()) { CHECK(AidlTypenames::IsBuiltinTypename(aidl_name)); return m[aidl_name]; } else { // 'foo.bar.IFoo' in AIDL maps to 'foo.bar.IFoo' in Java return aidl_name; } } string JavaSignatureOf(const AidlTypeSpecifier& aidl) { string ret = JavaNameOf(aidl); if (aidl.IsGeneric()) { vector arg_names; for (const auto& ta : aidl.GetTypeParameters()) { arg_names.emplace_back(JavaSignatureOf(*ta)); } ret += "<" + Join(arg_names, ",") + ">"; } if (aidl.IsArray()) { ret += "[]"; } return ret; } string DefaultJavaValueOf(const AidlTypeSpecifier& aidl) { static map m = { {"boolean", "false"}, {"byte", "0"}, {"char", R"('\u0000')"}, {"int", "0"}, {"long", "0L"}, {"float", "0.0f"}, {"double", "0.0d"}, }; const string& name = aidl.GetName(); assert(name != "void"); if (!aidl.IsArray() && m.find(name) != m.end()) { CHECK(AidlTypenames::IsBuiltinTypename(name)); return m[name]; } else { return "null"; } } // These are supported by AIDL syntax, but are unsupported by the AIDL compiler static bool IsMarshallingUnsupportedFor(const AidlTypeSpecifier& aidl, const AidlTypenames& typenames) { const string name = aidl.GetName(); // List is support only for String, Binder, ParcelFileDescriptor and Parcelable. if (name == "List" && aidl.IsGeneric()) { const string& contained_type = aidl.GetTypeParameters().at(0)->GetName(); if (AidlTypenames::IsBuiltinTypename(contained_type)) { if (contained_type != "String" && contained_type != "IBinder" && contained_type != "ParcelFileDescriptor") { return true; } } else { const AidlDefinedType* t = typenames.TryGetDefinedType(contained_type); if (t != nullptr && t->AsInterface() != nullptr) { return true; } } } // List[], Map[], CharSequence[] are not supported. if (AidlTypenames::IsBuiltinTypename(name) && aidl.IsArray()) { if (name == "List" || name == "Map" || name == "CharSequence") { return true; } } // T[] is not supported for interfaces const AidlDefinedType* t = typenames.TryGetDefinedType(name); if (aidl.IsArray() && t != nullptr && t->AsInterface() != nullptr) { return true; } return false; } static bool EnsureCodegenIsSupported(const CodeGeneratorContext& c) { if (IsMarshallingUnsupportedFor(c.type, c.typenames)) { AIDL_ERROR(c.type) << c.type.ToString() << "' is not yet supported."; return false; } return true; } static string GetFlagFor(const CodeGeneratorContext& c) { if (c.is_return_value) { return "android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE"; } else { return "0"; } } bool WriteToParcelFor(const CodeGeneratorContext& c) { if (!EnsureCodegenIsSupported(c)) { return false; } static map> method_map{ {"boolean", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeInt(((" << c.var << ")?(1):(0)));\n"; }}, {"boolean[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeBooleanArray(" << c.var << ");\n"; }}, {"byte", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeByte(" << c.var << ");\n"; }}, {"byte[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeByteArray(" << c.var << ");\n"; }}, {"char", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeInt(((int)" << c.var << "));\n"; }}, {"char[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeCharArray(" << c.var << ");\n"; }}, {"int", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeInt(" << c.var << ");\n"; }}, {"int[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeIntArray(" << c.var << ");\n"; }}, {"long", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeLong(" << c.var << ");\n"; }}, {"long[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeLongArray(" << c.var << ");\n"; }}, {"float", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeFloat(" << c.var << ");\n"; }}, {"float[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeFloatArray(" << c.var << ");\n"; }}, {"double", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeDouble(" << c.var << ");\n"; }}, {"double[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeDoubleArray(" << c.var << ");\n"; }}, {"String", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeString(" << c.var << ");\n"; }}, {"String[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeStringArray(" << c.var << ");\n"; }}, {"List", [](const CodeGeneratorContext& c) { if (c.type.IsGeneric()) { const string& contained_type = c.type.GetTypeParameters().at(0)->GetName(); if (AidlTypenames::IsBuiltinTypename(contained_type)) { if (contained_type == "String") { c.writer << c.parcel << ".writeStringList(" << c.var << ");\n"; } else if (contained_type == "IBinder") { c.writer << c.parcel << ".writeBinderList(" << c.var << ");\n"; } } else { const AidlDefinedType* t = c.typenames.TryGetDefinedType(contained_type); CHECK(t != nullptr) << "Unknown type: " << contained_type << endl; if (t->AsParcelable() != nullptr) { c.writer << c.parcel << ".writeTypedList(" << c.var << ");\n"; } } } else { c.writer << c.parcel << ".writeList(" << c.var << ");\n"; } }}, {"Map", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeMap(" << c.var << ");\n"; }}, {"IBinder", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeStrongBinder(" << c.var << ");\n"; }}, {"IBinder[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeBinderArray(" << c.var << ");\n"; }}, {"FileDescriptor", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeRawFileDescriptor(" << c.var << ");\n"; }}, {"FileDescriptor[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeRawFileDescriptorArray(" << c.var << ");\n"; }}, {"ParcelFileDescriptor", [](const CodeGeneratorContext& c) { // This is same as writeTypedObject which was introduced with SDK 23. // Keeping below code so that the generated code is buildable with older SDK. c.writer << "if ((" << c.var << "!=null)) {\n"; c.writer.Indent(); c.writer << c.parcel << ".writeInt(1);\n"; c.writer << c.var << ".writeToParcel(" << c.parcel << ", " << GetFlagFor(c) << ");\n"; c.writer.Dedent(); c.writer << "}\n"; c.writer << "else {\n"; c.writer.Indent(); c.writer << c.parcel << ".writeInt(0);\n"; c.writer.Dedent(); c.writer << "}\n"; }}, {"ParcelFileDescriptor[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".writeTypedArray(" << c.var << ", " << GetFlagFor(c) << ");\n"; }}, {"CharSequence", [](const CodeGeneratorContext& c) { // TextUtils.writeToParcel does not accept null. So, we need to handle // the case here. c.writer << "if (" << c.var << "!=null) {\n"; c.writer.Indent(); c.writer << c.parcel << ".writeInt(1);\n"; c.writer << "android.text.TextUtils.writeToParcel(" << c.var << ", " << c.parcel << ", " << GetFlagFor(c) << ");\n"; c.writer.Dedent(); c.writer << "}\n"; c.writer << "else {\n"; c.writer.Indent(); c.writer << c.parcel << ".writeInt(0);\n"; c.writer.Dedent(); c.writer << "}\n"; }}, }; const string type_name = c.type.GetName() + (c.type.IsArray() ? "[]" : ""); const auto found = method_map.find(type_name); if (found != method_map.end()) { found->second(c); } else { const AidlDefinedType* t = c.typenames.TryGetDefinedType(c.type.GetName()); CHECK(t != nullptr) << "Unknown type: " << c.type.GetName() << endl; if (t->AsInterface() != nullptr) { if (!c.type.IsArray()) { // Why don't we use writeStrongInterface which does the exact same thing? // Keeping below code just not to break unit tests. c.writer << c.parcel << ".writeStrongBinder((((" << c.var << "!=null))?" << "(" << c.var << ".asBinder()):(null)));\n"; } } else if (t->AsParcelable() != nullptr) { if (c.type.IsArray()) { c.writer << c.parcel << ".writeTypedArray(" << c.var << ", " << GetFlagFor(c) << ");\n"; } else { // This is same as writeTypedObject. // Keeping below code just not to break tests. c.writer << "if ((" << c.var << "!=null)) {\n"; c.writer.Indent(); c.writer << c.parcel << ".writeInt(1);\n"; c.writer << c.var << ".writeToParcel(" << c.parcel << ", " << GetFlagFor(c) << ");\n"; c.writer.Dedent(); c.writer << "}\n"; c.writer << "else {\n"; c.writer.Indent(); c.writer << c.parcel << ".writeInt(0);\n"; c.writer.Dedent(); c.writer << "}\n"; } } } return true; } // Ensures that a variable is initialized to refer to the classloader // of the current object and returns the name of the variable. static string EnsureAndGetClassloader(CodeGeneratorContext& c) { CHECK(c.is_classloader_created != nullptr); if (!*(c.is_classloader_created)) { c.writer << "java.lang.ClassLoader cl = " << "(java.lang.ClassLoader)this.getClass().getClassLoader();\n"; *(c.is_classloader_created) = true; } return "cl"; } bool CreateFromParcelFor(const CodeGeneratorContext& c) { if (!EnsureCodegenIsSupported(c)) { return false; } static map> method_map{ {"boolean", [](const CodeGeneratorContext& c) { c.writer << c.var << " = (0!=" << c.parcel << ".readInt());\n"; }}, {"boolean[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createBooleanArray();\n"; }}, {"byte", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readByte();\n"; }}, {"byte[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createByteArray();\n"; }}, {"char", [](const CodeGeneratorContext& c) { c.writer << c.var << " = (char)" << c.parcel << ".readInt();\n"; }}, {"char[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createCharArray();\n"; }}, {"int", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readInt();\n"; }}, {"int[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createIntArray();\n"; }}, {"long", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readLong();\n"; }}, {"long[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createLongArray();\n"; }}, {"float", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readFloat();\n"; }}, {"float[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createFloatArray();\n"; }}, {"double", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readDouble();\n"; }}, {"double[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createDoubleArray();\n"; }}, {"String", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readString();\n"; }}, {"String[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createStringArray();\n"; }}, {"List", [](const CodeGeneratorContext& c) { if (c.type.IsGeneric()) { const string& contained_type = c.type.GetTypeParameters().at(0)->GetName(); if (AidlTypenames::IsBuiltinTypename(contained_type)) { if (contained_type == "String") { c.writer << c.var << " = " << c.parcel << ".createStringArrayList();\n"; } else if (contained_type == "IBinder") { c.writer << c.var << " = " << c.parcel << ".createBinderArrayList();\n"; } } else { const AidlDefinedType* t = c.typenames.TryGetDefinedType(contained_type); CHECK(t != nullptr) << "Unknown type: " << contained_type << endl; if (t->AsParcelable() != nullptr) { c.writer << c.var << " = " << c.parcel << ".createTypedArrayList(" << JavaNameOf(*(c.type.GetTypeParameters().at(0))) << ".CREATOR);\n"; } } } else { const string classloader = EnsureAndGetClassloader(const_cast(c)); c.writer << c.var << " = " << c.parcel << ".readArrayList(" << classloader << ");\n"; } }}, {"Map", [](const CodeGeneratorContext& c) { const string classloader = EnsureAndGetClassloader(const_cast(c)); c.writer << c.var << " = " << c.parcel << ".readHashMap(" << classloader << ");\n"; }}, {"IBinder", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readStrongBinder();\n"; }}, {"IBinder[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createBinderArray();\n"; }}, {"FileDescriptor", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".readRawFileDescriptor();\n"; }}, {"FileDescriptor[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createRawFileDescriptorArray();\n"; }}, {"ParcelFileDescriptor", [](const CodeGeneratorContext& c) { // This is same as readTypedObject which was introduced with SDK 23. // Keeping below code so that the generated code is buildable with older SDK. c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n"; c.writer.Indent(); c.writer << c.var << " = " << "android.os.ParcelFileDescriptor.CREATOR.createFromParcel(" << c.parcel << ");\n"; c.writer.Dedent(); c.writer << "}\n"; c.writer << "else {\n"; c.writer.Indent(); c.writer << c.var << " = null;\n"; c.writer.Dedent(); c.writer << "}\n"; }}, {"ParcelFileDescriptor[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createTypedArray(android.os.ParcelFileDescriptor.CREATOR);\n"; }}, {"CharSequence", [](const CodeGeneratorContext& c) { // We have written 0 for null CharSequence. c.writer << "if (0!=" << c.parcel << ".readInt()) {\n"; c.writer.Indent(); c.writer << c.var << " = android.text.TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(" << c.parcel << ");\n"; c.writer.Dedent(); c.writer << "}\n"; c.writer << "else {\n"; c.writer.Indent(); c.writer << c.var << " = null;\n"; c.writer.Dedent(); c.writer << "}\n"; }}, }; const string type_name = c.type.GetName() + (c.type.IsArray() ? "[]" : ""); const auto found = method_map.find(type_name); if (found != method_map.end()) { found->second(c); } else { const AidlDefinedType* t = c.typenames.TryGetDefinedType(c.type.GetName()); CHECK(t != nullptr) << "Unknown type: " << c.type.GetName() << endl; if (t->AsInterface() != nullptr) { if (!c.type.IsArray()) { c.writer << c.var << " = " << c.type.GetName() << ".Stub.asInterface(" << c.parcel << ".readStrongBinder());\n"; } } else if (t->AsParcelable() != nullptr || t->AsStructuredParcelable() != nullptr) { if (c.type.IsArray()) { c.writer << c.var << " = " << c.parcel << ".createTypedArray(" << JavaNameOf(c.type) << ".CREATOR);\n"; } else { // This is same as readTypedObject. // Keeping below code just not to break unit tests. c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n"; c.writer.Indent(); c.writer << c.var << " = " << c.type.GetName() << ".CREATOR.createFromParcel(" << c.parcel << ");\n"; c.writer.Dedent(); c.writer << "}\n"; c.writer << "else {\n"; c.writer.Indent(); c.writer << c.var << " = null;\n"; c.writer.Dedent(); c.writer << "}\n"; } } } return true; } bool ReadFromParcelFor(const CodeGeneratorContext& c) { if (!EnsureCodegenIsSupported(c)) { return false; } static map> method_map{ {"boolean[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readBooleanArray(" << c.var << ");\n"; }}, {"byte[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readByteArray(" << c.var << ");\n"; }}, {"char[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readCharArray(" << c.var << ");\n"; }}, {"int[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readIntArray(" << c.var << ");\n"; }}, {"long[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readLongArray(" << c.var << ");\n"; }}, {"float[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readFloatArray(" << c.var << ");\n"; }}, {"double[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readDoubleArray(" << c.var << ");\n"; }}, {"String[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readStringArray(" << c.var << ");\n"; }}, {"List", [](const CodeGeneratorContext& c) { if (c.type.IsGeneric()) { const string& contained_type = c.type.GetTypeParameters().at(0)->GetName(); if (AidlTypenames::IsBuiltinTypename(contained_type)) { if (contained_type == "String") { c.writer << c.parcel << ".readStringList(" << c.var << ");\n"; } else if (contained_type == "IBinder") { c.writer << c.parcel << ".readBinderList(" << c.var << ");\n"; } } else { const AidlDefinedType* t = c.typenames.TryGetDefinedType(contained_type); CHECK(t != nullptr) << "Unknown type: " << contained_type << endl; if (t->AsParcelable() != nullptr) { c.writer << c.parcel << ".readTypedList(" << c.var << ", " << JavaNameOf(*(c.type.GetTypeParameters().at(0))) << ".CREATOR);\n"; } } } else { const string classloader = EnsureAndGetClassloader(const_cast(c)); c.writer << c.parcel << ".readList(" << c.var << ", " << classloader << ");\n"; } }}, {"Map", [](const CodeGeneratorContext& c) { const string classloader = EnsureAndGetClassloader(const_cast(c)); c.writer << c.var << " = " << c.parcel << ".readHashMap(" << classloader << ");\n"; }}, {"IBinder[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createBinderArray();\n"; }}, {"FileDescriptor[]", [](const CodeGeneratorContext& c) { c.writer << c.var << " = " << c.parcel << ".createRawFileDescriptorArray();\n"; }}, {"ParcelFileDescriptor", [](const CodeGeneratorContext& c) { c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n"; c.writer.Indent(); c.writer << c.var << " = " << "android.os.ParcelFileDescriptor.CREATOR.createFromParcel(" << c.parcel << ");\n"; c.writer.Dedent(); c.writer << "}\n"; }}, {"ParcelFileDescriptor[]", [](const CodeGeneratorContext& c) { c.writer << c.parcel << ".readTypedArray(" << c.var << ", android.os.ParcelFileDescriptor.CREATOR);\n"; }}, }; const string type_name = c.type.GetName() + (c.type.IsArray() ? "[]" : ""); const auto& found = method_map.find(type_name); if (found != method_map.end()) { found->second(c); } else { const AidlDefinedType* t = c.typenames.TryGetDefinedType(c.type.GetName()); CHECK(t != nullptr) << "Unknown type: " << c.type.GetName() << endl; if (t->AsParcelable() != nullptr) { if (c.type.IsArray()) { c.writer << c.parcel << ".readTypedArray(" << c.var << ", " << c.type.GetName() << ".CREATOR);\n"; } else { c.writer << "if ((0!=" << c.parcel << ".readInt())) {\n"; c.writer.Indent(); c.writer << c.var << ".readFromParcel(" << c.parcel << ");\n"; c.writer.Dedent(); c.writer << "}\n"; } } } return true; } } // namespace java } // namespace aidl } // namespace android aidl_to_java.h0100644 0000000 0000000 00000007316 13755771705 012422 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "aidl_language.h" #include "aidl_typenames.h" #include #include #include #include #include #include #include namespace android { namespace aidl { namespace java { using std::map; using std::pair; using std::set; using std::string; using std::unique_ptr; using std::vector; // This header provides functions that translate AIDL things to Java things. std::string ConstantValueDecorator(const AidlTypeSpecifier& type, const std::string& raw_value); // Returns the corresponding Java type name for an AIDL type spec // This excludes generic type parameters and array modifiers. const string& JavaNameOf(const AidlTypeSpecifier& aidl); // Returns the Java type signature of the AIDL type spec // This includes generic type parameters and array modifiers. string JavaSignatureOf(const AidlTypeSpecifier& aidl); // Returns the default Java value of the AIDL type spec string DefaultJavaValueOf(const AidlTypeSpecifier& aidl); // This carries information that is required to generate code for // marshalling and unmarshalling a method argument or a parcelable field struct CodeGeneratorContext { CodeWriter& writer; // CodeWriter::Write() is mutable const AidlTypenames& typenames; const AidlTypeSpecifier& type; const string parcel; const string var; // Set to true when the marshalled data will be returned to the client // This is given as a hint to the Parcelable that is being marshalled // so that the Parcelable can release its resource after the marshalling // is done. const bool is_return_value; // Most of the variables created by AIDL compiler are typed, i.e., the code // knows exactly what type of object is in the parcel -- because the parcel // itself is created by the code generated by AIDL compiler. // // However, for some collection types (List and Map for now), we write the // elements in them untyped (object is flattened along with its type name) // as the AIDL compiler does not know the type of the contained elements. // So, when unmarshalling such collection, we need to provide a classloader // from where the parcel can reflectively find a class object for // the contained element. // // This field is a pointer to a boolean state variable that indicates whether // the code for declaring and getting the classloader has been emitted or not. // We emit the code at most once per an AIDL method, otherwise we are wasting // time doing the same thing multiple time. bool* const is_classloader_created; // for error message printing const string filename; }; // Writes code fragment that writes a variable to the parcel. bool WriteToParcelFor(const CodeGeneratorContext& c); // Writes code fragment that reads data from the parcel into a variable. When // the variable type is array or List, the array or List is created. bool CreateFromParcelFor(const CodeGeneratorContext& c); // Writes code fragment that reads data from the parcel into an existing // array or a List. bool ReadFromParcelFor(const CodeGeneratorContext& c); } // namespace java } // namespace aidl } // namespace android aidl_to_ndk.cpp0100644 0000000 0000000 00000031767 13755771705 012617 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * limitations under the License. */ #include "aidl_to_ndk.h" #include "aidl_language.h" #include "aidl_to_cpp_common.h" #include "logging.h" #include "os.h" #include #include using ::android::base::Join; namespace android { namespace aidl { namespace ndk { std::string NdkHeaderFile(const AidlDefinedType& defined_type, cpp::ClassNames name, bool use_os_sep) { char seperator = (use_os_sep) ? OS_PATH_SEPARATOR : '/'; return std::string("aidl") + seperator + cpp::HeaderFile(defined_type, name, use_os_sep); } // This represents a type in AIDL (e.g. 'String' which can be referenced in multiple ways) struct TypeInfo { struct Aspect { // name of the type in C++ output std::string cpp_name; // whether to prefer 'value type' over 'const&' bool value_is_cheap; std::function read_func; std::function write_func; }; // e.g. 'String' Aspect raw; // e.g. 'String[]' std::shared_ptr array; // note: Nullable types do not exist in Java. For most Java types, the type is split into a // nullable and non-nullable variant. This is because C++ types are more usually non-nullable, but // everything in Java is non-nullable. This does mean that some Java interfaces may have to have // '@nullable' added to them in order to function as expected w/ the NDK. It also means that some // transactions will be allowed in Java which are not allowed in C++. However, in Java, if a null // is ignored, it will just result in a NullPointerException and be delivered to the other side. // C++ does not have this same capacity (in Android), and so instead, we distinguish nullability // in the type system. // e.g. '@nullable String' std::shared_ptr nullable; // e.g. '@nullable String[]' std::shared_ptr nullable_array; }; static std::function StandardRead(const std::string& name) { return [name](const CodeGeneratorContext& c) { c.writer << name << "(" << c.parcel << ", " << c.var << ")"; }; } static std::function StandardWrite(const std::string& name) { return [name](const CodeGeneratorContext& c) { c.writer << name << "(" << c.parcel << ", " << c.var << ")"; }; } TypeInfo PrimitiveType(const std::string& cpp_name, const std::string& pretty_name) { return TypeInfo{ .raw = TypeInfo::Aspect{ .cpp_name = cpp_name, .value_is_cheap = true, .read_func = StandardRead("AParcel_read" + pretty_name), .write_func = StandardWrite("AParcel_write" + pretty_name), }, .array = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::vector<" + cpp_name + ">", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readVector"), .write_func = StandardWrite("::ndk::AParcel_writeVector"), }), .nullable = nullptr, .nullable_array = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::optional>", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readVector"), .write_func = StandardWrite("::ndk::AParcel_writeVector"), }), }; } TypeInfo InterfaceTypeInfo(const AidlInterface& type) { const std::string clazz = NdkFullClassName(type, cpp::ClassNames::INTERFACE); return TypeInfo{ .raw = TypeInfo::Aspect{ .cpp_name = "std::shared_ptr<" + clazz + ">", .value_is_cheap = false, // TODO(b/111445392): these should be non-null .read_func = StandardRead(clazz + "::readFromParcel"), .write_func = StandardWrite(clazz + "::writeToParcel"), }, .array = nullptr, .nullable = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::shared_ptr<" + clazz + ">", .value_is_cheap = false, .read_func = StandardRead(clazz + "::readFromParcel"), .write_func = StandardWrite(clazz + "::writeToParcel"), }), .nullable_array = nullptr, }; } TypeInfo ParcelableTypeInfo(const AidlParcelable& type) { const std::string clazz = NdkFullClassName(type, cpp::ClassNames::BASE); return TypeInfo{ .raw = TypeInfo::Aspect{ .cpp_name = clazz, .value_is_cheap = false, .read_func = [](const CodeGeneratorContext& c) { c.writer << "(" << c.var << ")->readFromParcel(" << c.parcel << ")"; }, .write_func = [](const CodeGeneratorContext& c) { c.writer << "(" << c.var << ").writeToParcel(" << c.parcel << ")"; }, }, .array = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::vector<" + clazz + ">", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readVector"), .write_func = StandardWrite("::ndk::AParcel_writeVector"), }), .nullable = nullptr, .nullable_array = nullptr, }; } // map from AIDL built-in type name to the corresponding Ndk type name static map kNdkTypeInfoMap = { {"void", TypeInfo{{"void", true, nullptr, nullptr}, nullptr, nullptr, nullptr}}, {"boolean", PrimitiveType("bool", "Bool")}, {"byte", PrimitiveType("int8_t", "Byte")}, {"char", PrimitiveType("char16_t", "Char")}, {"int", PrimitiveType("int32_t", "Int32")}, {"long", PrimitiveType("int64_t", "Int64")}, {"float", PrimitiveType("float", "Float")}, {"double", PrimitiveType("double", "Double")}, {"String", TypeInfo{ .raw = TypeInfo::Aspect{ .cpp_name = "std::string", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readString"), .write_func = StandardWrite("::ndk::AParcel_writeString"), }, .array = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::vector", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readVector"), .write_func = StandardWrite("::ndk::AParcel_writeVector"), }), .nullable = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::optional", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readString"), .write_func = StandardWrite("::ndk::AParcel_writeString"), }), .nullable_array = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "std::optional>>", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readVector"), .write_func = StandardWrite("::ndk::AParcel_writeVector"), }), }}, // TODO(b/111445392) {"List", ""}, // TODO(b/111445392) {"Map", ""}, {"IBinder", TypeInfo{ .raw = TypeInfo::Aspect{ .cpp_name = "::ndk::SpAIBinder", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readRequiredStrongBinder"), .write_func = StandardRead("::ndk::AParcel_writeRequiredStrongBinder"), }, .array = nullptr, .nullable = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "::ndk::SpAIBinder", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readNullableStrongBinder"), .write_func = StandardRead("::ndk::AParcel_writeNullableStrongBinder"), }), .nullable_array = nullptr, }}, // TODO(b/111445392) {"FileDescriptor", ""}, {"ParcelFileDescriptor", TypeInfo{ .raw = TypeInfo::Aspect{ .cpp_name = "::ndk::ScopedFileDescriptor", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readRequiredParcelFileDescriptor"), .write_func = StandardRead("::ndk::AParcel_writeRequiredParcelFileDescriptor"), }, .array = nullptr, .nullable = std::shared_ptr(new TypeInfo::Aspect{ .cpp_name = "::ndk::ScopedFileDescriptor", .value_is_cheap = false, .read_func = StandardRead("::ndk::AParcel_readNullableParcelFileDescriptor"), .write_func = StandardRead("::ndk::AParcel_writeNullableParcelFileDescriptor"), }), .nullable_array = nullptr, }}, // TODO(b/111445392) {"CharSequence", ""}, }; static TypeInfo::Aspect GetTypeAspect(const AidlTypenames& types, const AidlTypeSpecifier& aidl) { CHECK(aidl.IsResolved()) << aidl.ToString(); const string aidl_name = aidl.GetName(); // TODO(b/112664205): this is okay for some types AIDL_FATAL_IF(aidl.IsGeneric(), aidl) << aidl.ToString(); TypeInfo info; if (AidlTypenames::IsBuiltinTypename(aidl_name)) { auto it = kNdkTypeInfoMap.find(aidl_name); CHECK(it != kNdkTypeInfoMap.end()); info = it->second; } else { const AidlDefinedType* type = types.TryGetDefinedType(aidl_name); AIDL_FATAL_IF(type == nullptr, aidl_name) << "Unrecognized type."; if (type->AsInterface() != nullptr) { info = InterfaceTypeInfo(*type->AsInterface()); } else if (type->AsParcelable() != nullptr) { info = ParcelableTypeInfo(*type->AsParcelable()); } else { AIDL_FATAL(aidl_name) << "Unrecognized type"; } } if (aidl.IsArray()) { if (aidl.IsNullable()) { AIDL_FATAL_IF(info.nullable_array == nullptr, aidl) << "Unsupported type in NDK Backend."; return *info.nullable_array; } AIDL_FATAL_IF(info.array == nullptr, aidl) << "Unsupported type in NDK Backend."; return *info.array; } if (aidl.IsNullable()) { AIDL_FATAL_IF(info.nullable == nullptr, aidl) << "Unsupported type in NDK Backend."; return *info.nullable; } return info.raw; } std::string NdkFullClassName(const AidlDefinedType& type, cpp::ClassNames name) { std::vector pieces = {"::aidl"}; std::vector package = type.GetSplitPackage(); pieces.insert(pieces.end(), package.begin(), package.end()); pieces.push_back(cpp::ClassName(type, name)); return Join(pieces, "::"); } std::string NdkNameOf(const AidlTypenames& types, const AidlTypeSpecifier& aidl, StorageMode mode) { TypeInfo::Aspect aspect = GetTypeAspect(types, aidl); switch (mode) { case StorageMode::STACK: return aspect.cpp_name; case StorageMode::ARGUMENT: if (aspect.value_is_cheap) { return aspect.cpp_name; } else { return "const " + aspect.cpp_name + "&"; } case StorageMode::OUT_ARGUMENT: return aspect.cpp_name + "*"; default: AIDL_FATAL(aidl.GetName()) << "Unrecognized mode type: " << static_cast(mode); } } void WriteToParcelFor(const CodeGeneratorContext& c) { TypeInfo::Aspect aspect = GetTypeAspect(c.types, c.type); aspect.write_func(c); } void ReadFromParcelFor(const CodeGeneratorContext& c) { TypeInfo::Aspect aspect = GetTypeAspect(c.types, c.type); aspect.read_func(c); } std::string NdkArgList( const AidlTypenames& types, const AidlMethod& method, std::function formatter) { std::vector method_arguments; for (const auto& a : method.GetArguments()) { StorageMode mode = a->IsOut() ? StorageMode::OUT_ARGUMENT : StorageMode::ARGUMENT; std::string type = NdkNameOf(types, a->GetType(), mode); std::string name = cpp::BuildVarName(*a); method_arguments.emplace_back(formatter(type, name, a->IsOut())); } if (method.GetType().GetName() != "void") { std::string type = NdkNameOf(types, method.GetType(), StorageMode::OUT_ARGUMENT); std::string name = "_aidl_return"; method_arguments.emplace_back(formatter(type, name, true)); } return Join(method_arguments, ", "); } std::string NdkMethodDecl(const AidlTypenames& types, const AidlMethod& method, const std::string& clazz) { std::string class_prefix = clazz.empty() ? "" : (clazz + "::"); return "::ndk::ScopedAStatus " + class_prefix + method.GetName() + "(" + NdkArgList(types, method, FormatArgForDecl) + ")"; } } // namespace ndk } // namespace aidl } // namespace android aidl_to_ndk.h0100644 0000000 0000000 00000005576 13755771705 012263 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "aidl_language.h" #include "aidl_to_cpp_common.h" namespace android { namespace aidl { namespace ndk { enum class StorageMode { STACK, ARGUMENT, // Value for primitives, const& for larger types OUT_ARGUMENT, // Pointer to raw type }; std::string NdkHeaderFile(const AidlDefinedType& defined_type, cpp::ClassNames name, bool use_os_sep = true); // Returns ::aidl::some_package::some_sub_package::foo::IFoo/BpFoo/BnFoo std::string NdkFullClassName(const AidlDefinedType& type, cpp::ClassNames name); // Returns the corresponding Ndk type name for an AIDL type spec including // array modifiers. std::string NdkNameOf(const AidlTypenames& types, const AidlTypeSpecifier& aidl, StorageMode mode); struct CodeGeneratorContext { CodeWriter& writer; const AidlTypenames& types; const AidlTypeSpecifier& type; const string parcel; const string var; }; void WriteToParcelFor(const CodeGeneratorContext& c); void ReadFromParcelFor(const CodeGeneratorContext& c); // Returns argument list of a method where each arg is formatted by the fomatter std::string NdkArgList( const AidlTypenames& types, const AidlMethod& method, std::function formatter); inline std::string FormatArgForDecl(const std::string& type, const std::string& name, bool /*isOut*/) { return type + " " + name; } inline std::string FormatArgNameUnused(const std::string& type, const std::string& name, bool /*isOut*/) { return type + " /*" + name + "*/"; } inline std::string FormatArgForCall(const std::string& /*type*/, const std::string& name, bool isOut) { std::string reference_prefix = isOut ? "&" : ""; return reference_prefix + name; } inline std::string FormatArgNameOnly(const std::string& /*type*/, const std::string& name, bool /*isOut*/) { return name; } // -> 'status (class::)name(type name, ...)' for a method std::string NdkMethodDecl(const AidlTypenames& types, const AidlMethod& method, const std::string& clazz = ""); } // namespace ndk } // namespace aidl } // namespace android aidl_typenames.cpp0100644 0000000 0000000 00000014271 13755771705 013335 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "aidl_typenames.h" #include "aidl_language.h" #include "logging.h" #include #include #include #include #include #include #include using android::base::Split; using std::make_pair; using std::map; using std::pair; using std::set; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { // The built-in AIDL types.. static const set kBuiltinTypes = { "void", "boolean", "byte", "char", "int", "long", "float", "double", "String", "List", "Map", "IBinder", "FileDescriptor", "CharSequence", "ParcelFileDescriptor"}; static const set kPrimitiveTypes = {"void", "boolean", "byte", "char", "int", "long", "float", "double"}; // Note: these types may look wrong because they look like Java // types, but they have long been supported from the time when Java // was the only target language of this compiler. They are added here for // backwards compatibility, but we internally treat them as List and Map, // respectively. static const map kJavaLikeTypeToAidlType = { {"java.util.List", "List"}, {"java.util.Map", "Map"}, {"android.os.ParcelFileDescriptor", "ParcelFileDescriptor"}, }; // Package name and type name can't be one of these as they are keywords // in Java and C++. Using these names will eventually cause compilation error, // so checking this here is not a must have, but early detection of errors // is always better. static const set kInvalidNames = { "break", "case", "catch", "char", "class", "continue", "default", "do", "double", "else", "enum", "false", "float", "for", "goto", "if", "int", "long", "new", "private", "protected", "public", "return", "short", "static", "switch", "this", "throw", "true", "try", "void", "volatile", "while"}; static bool IsValidName(const string& name) { vector pieces = Split(name, "."); for (const auto& piece : pieces) { if (kInvalidNames.find(piece) != kInvalidNames.end()) { return false; } } return true; } bool AidlTypenames::AddDefinedType(unique_ptr type) { const string name = type->GetCanonicalName(); if (defined_types_.find(name) != defined_types_.end()) { return false; } if (!IsValidName(type->GetPackage()) || !IsValidName(type->GetName())) { return false; } defined_types_.emplace(name, std::move(type)); return true; } bool AidlTypenames::AddPreprocessedType(unique_ptr type) { const string name = type->GetCanonicalName(); if (preprocessed_types_.find(name) != preprocessed_types_.end()) { return false; } if (!IsValidName(type->GetPackage()) || !IsValidName(type->GetName())) { return false; } preprocessed_types_.insert(make_pair(name, std::move(type))); return true; } bool AidlTypenames::IsBuiltinTypename(const string& type_name) { return kBuiltinTypes.find(type_name) != kBuiltinTypes.end() || kJavaLikeTypeToAidlType.find(type_name) != kJavaLikeTypeToAidlType.end(); } bool AidlTypenames::IsPrimitiveTypename(const string& type_name) { return kPrimitiveTypes.find(type_name) != kPrimitiveTypes.end(); } const AidlDefinedType* AidlTypenames::TryGetDefinedType(const string& type_name) const { // Do the exact match first. auto found_def = defined_types_.find(type_name); if (found_def != defined_types_.end()) { return found_def->second.get(); } auto found_prep = preprocessed_types_.find(type_name); if (found_prep != preprocessed_types_.end()) { return found_prep->second.get(); } // Then match with the class name. Defined types has higher priority than // types from the preprocessed file. for (auto it = defined_types_.begin(); it != defined_types_.end(); it++) { if (it->second->GetName() == type_name) { return it->second.get(); } } for (auto it = preprocessed_types_.begin(); it != preprocessed_types_.end(); it++) { if (it->second->GetName() == type_name) { return it->second.get(); } } return nullptr; } pair AidlTypenames::ResolveTypename(const string& type_name) const { if (IsBuiltinTypename(type_name)) { auto found = kJavaLikeTypeToAidlType.find(type_name); if (found != kJavaLikeTypeToAidlType.end()) { return make_pair(found->second, true); } return make_pair(type_name, true); } const AidlDefinedType* defined_type = TryGetDefinedType(type_name); if (defined_type != nullptr) { return make_pair(defined_type->GetCanonicalName(), true); } else { return make_pair(type_name, false); } } // Only T[], List, Map, ParcelFileDescriptor and Parcelable can be an out parameter. bool AidlTypenames::CanBeOutParameter(const AidlTypeSpecifier& type) const { const string& name = type.GetName(); if (IsBuiltinTypename(name)) { return type.IsArray() || type.GetName() == "List" || type.GetName() == "Map" || type.GetName() == "ParcelFileDescriptor"; } const AidlDefinedType* t = TryGetDefinedType(type.GetName()); CHECK(t != nullptr) << "Unrecognized type: '" << type.GetName() << "'"; return t->AsParcelable() != nullptr; } void AidlTypenames::IterateTypes(const std::function& body) const { for (const auto& kv : defined_types_) { body(*kv.second); } for (const auto& kv : preprocessed_types_) { body(*kv.second); } } void AidlTypenames::Reset() { defined_types_.clear(); preprocessed_types_.clear(); } } // namespace aidl } // namespace android aidl_typenames.h0100644 0000000 0000000 00000004502 13755771705 012776 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include using std::map; using std::pair; using std::set; using std::string; using std::unique_ptr; using std::vector; class AidlDefinedType; class AidlTypeSpecifier; namespace android { namespace aidl { // AidlTypenames is a collection of AIDL types available to a compilation unit. // // Basic types (such as int, String, etc.) are added by default, while defined // types (such as IFoo, MyParcelable, etc.) and types from preprocessed inputs // are added as they are recognized by the parser. // // When AidlTypeSpecifier is encountered during parsing, parser defers the // resolution of it until the end of the parsing, where it uses AidlTypenames // to resolve type names in AidlTypeSpecifier. // // Note that nothing here is specific to either Java or C++. class AidlTypenames final { public: AidlTypenames() = default; void Reset(); bool AddDefinedType(unique_ptr type); bool AddPreprocessedType(unique_ptr type); static bool IsBuiltinTypename(const string& type_name); static bool IsPrimitiveTypename(const string& type_name); const AidlDefinedType* TryGetDefinedType(const string& type_name) const; pair ResolveTypename(const string& type_name) const; bool CanBeOutParameter(const AidlTypeSpecifier& type) const; // Iterates over all defined and then preprocessed types void IterateTypes(const std::function& body) const; private: map> defined_types_; map> preprocessed_types_; }; } // namespace aidl } // namespace android aidl_unittest.cpp0100644 0000000 0000000 00000156215 13755771705 013214 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_apicheck.h" #include "aidl_language.h" #include "aidl_to_cpp.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 kExpectedParcelableDeclarationDepFileContents[] = R"( : \ p/Foo.aidl p/Foo.aidl : )"; const char kExpectedStructuredParcelableDepFileContents[] = R"(place/for/output/p/Foo.java : \ p/Foo.aidl p/Foo.aidl : )"; const char kExepectedJavaParcelableOutputContests[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ @android.annotation.SystemApi public class Rect implements android.os.Parcelable { // Comment @android.annotation.SystemApi public int x = 5; @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi public int y; public static final android.os.Parcelable.Creator CREATOR = new android.os.Parcelable.Creator() { @Override public Rect createFromParcel(android.os.Parcel _aidl_source) { Rect _aidl_out = new Rect(); _aidl_out.readFromParcel(_aidl_source); return _aidl_out; } @Override public Rect[] newArray(int _aidl_size) { return new Rect[_aidl_size]; } }; @Override public final void writeToParcel(android.os.Parcel _aidl_parcel, int _aidl_flag) { int _aidl_start_pos = _aidl_parcel.dataPosition(); _aidl_parcel.writeInt(0); _aidl_parcel.writeInt(x); _aidl_parcel.writeInt(y); int _aidl_end_pos = _aidl_parcel.dataPosition(); _aidl_parcel.setDataPosition(_aidl_start_pos); _aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos); _aidl_parcel.setDataPosition(_aidl_end_pos); } public final void readFromParcel(android.os.Parcel _aidl_parcel) { int _aidl_start_pos = _aidl_parcel.dataPosition(); int _aidl_parcelable_size = _aidl_parcel.readInt(); if (_aidl_parcelable_size < 0) return; try { x = _aidl_parcel.readInt(); if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return; y = _aidl_parcel.readInt(); if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return; } finally { _aidl_parcel.setDataPosition(_aidl_start_pos + _aidl_parcelable_size); } } @Override public int describeContents() { return 0; } } )"; } // namespace class AidlTest : public ::testing::Test { protected: void SetUp() override { java_types_.Init(); cpp_types_.Init(); } AidlDefinedType* Parse(const string& path, const string& contents, TypeNamespace* types, AidlError* error = nullptr, const vector additional_arguments = {}) { io_delegate_.SetFileContents(path, contents); vector args; if (types == &java_types_) { args.emplace_back("aidl"); } else { args.emplace_back("aidl-cpp"); } for (const string& s : additional_arguments) { args.emplace_back(s); } for (const string& f : preprocessed_files_) { args.emplace_back("--preprocessed=" + f); } for (const string& i : import_paths_) { args.emplace_back("--include=" + i); } args.emplace_back(path); Options options = Options::From(args); vector defined_types; vector imported_files; ImportResolver import_resolver{io_delegate_, path, import_paths_, {}}; AidlError actual_error = ::android::aidl::internals::load_and_validate_aidl( path, options, io_delegate_, types, &defined_types, &imported_files); if (error != nullptr) { *error = actual_error; } if (actual_error != AidlError::OK) { return nullptr; } EXPECT_EQ(1ul, defined_types.size()); return defined_types.front(); } FakeIoDelegate io_delegate_; vector preprocessed_files_; set import_paths_; java::JavaTypeNamespace java_types_; cpp::TypeNamespace cpp_types_; }; TEST_F(AidlTest, AcceptMissingPackage) { EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &java_types_)); EXPECT_NE(nullptr, Parse("IFoo.aidl", "interface IFoo { }", &cpp_types_)); } TEST_F(AidlTest, RejectsArraysOfBinders) { import_paths_.emplace(""); 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, 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, RejectsDuplicatedArgumentNames) { string method = "package a; interface IFoo { void f(int a, int a); }"; EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", method, &cpp_types_)); EXPECT_EQ(nullptr, Parse("a/IFoo.aidl", 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); const AidlInterface* interface = parse_result->AsInterface(); ASSERT_NE(nullptr, interface); ASSERT_FALSE(interface->GetMethods().empty()); EXPECT_EQ(interface->GetMethods()[0]->GetType().IsNullable(), is_nullable); cpp_types_.typenames_.Reset(); } } 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); const AidlInterface* interface = parse_result->AsInterface(); ASSERT_NE(nullptr, interface); ASSERT_FALSE(interface->GetMethods().empty()); EXPECT_EQ(interface->GetMethods()[0]->GetType().IsUtf8InCpp(), is_utf8); cpp_types_.typenames_.Reset(); } } 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_, java_types_.typenames_)); 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_, java_types_.typenames_)); 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_.emplace(""); 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. AidlTypeSpecifier ambiguous_type(AIDL_LOCATION_HERE, "IBar", false, nullptr, ""); 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 {}"); vector args { "aidl", "--preprocess", "preprocessed", "p/Outer.aidl", "one/IBar.aidl"}; Options options = Options::From(args); 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, JavaParcelableOutput) { io_delegate_.SetFileContents("Rect.aidl", "@SystemApi\n" "parcelable Rect {\n" " // Comment\n" " @SystemApi\n" " int x=5;\n" " @SystemApi\n" " @UnsupportedAppUsage\n" " int y;\n" "}"); vector args{"aidl", "Rect.aidl"}; Options options = Options::From(args); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string output; EXPECT_TRUE(io_delegate_.GetWrittenContents("Rect.java", &output)); EXPECT_EQ(kExepectedJavaParcelableOutputContests, output); } TEST_F(AidlTest, RequireOuterClass) { io_delegate_.SetFileContents("p/Outer.aidl", "package p; parcelable Outer.Inner;"); import_paths_.emplace(""); 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) { io_delegate_.SetFileContents("p/IFoo.aidl", "package p; parcelable IFoo;"); // By default, we shouldn't fail on parcelable. Options options1 = Options::From("aidl p/IFoo.aidl"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options1, io_delegate_)); // -b considers this an error Options options2 = Options::From("aidl -b p/IFoo.aidl"); EXPECT_NE(0, ::android::aidl::compile_aidl(options2, io_delegate_)); io_delegate_.SetFileContents("p/IBar.aidl", "package p; parcelable Foo; interface IBar{}"); // Regardless of '-b', a parcelable and an interface should fail. Options options3 = Options::From("aidl p/IBar.aidl"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options3, io_delegate_)); Options options4 = Options::From("aidl -b p/IBar.aidl"); EXPECT_NE(0, ::android::aidl::compile_aidl(options4, io_delegate_)); } TEST_F(AidlTest, StructuredFailOnUnstructuredParcelable) { io_delegate_.SetFileContents("o/WhoKnowsWhat.aidl", "package o; parcelable WhoKnowsWhat;"); import_paths_.emplace(""); AidlError reported_error; auto parse_result = Parse("p/IFoo.aidl", "package p; import o.WhoKnowsWhat; interface IFoo { void f(in WhoKnowsWhat thisIs); }", &java_types_, &reported_error, {"--structured"}); EXPECT_EQ(nullptr, parse_result); EXPECT_EQ(AidlError::NOT_STRUCTURED, reported_error); } 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_TYPE, reported_error); } TEST_F(AidlTest, FailOnManyDefinedTypes) { AidlError reported_error; EXPECT_EQ(nullptr, Parse("p/IFoo.aidl", R"(package p; interface IFoo {} parcelable Bar; parcelable IBar {} parcelable StructuredParcelable {} interface IBaz {} )", &cpp_types_, &reported_error)); // Parse success is important for clear error handling even if the cases aren't // actually supported in code generation. EXPECT_EQ(AidlError::BAD_TYPE, reported_error); } TEST_F(AidlTest, FailOnNoDefinedTypes) { AidlError reported_error; EXPECT_EQ(nullptr, Parse("p/IFoo.aidl", R"(package p;)", &cpp_types_, &reported_error)); EXPECT_EQ(AidlError::PARSE_ERROR, 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_TYPE, 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 AidlInterface* interface = cpp_parse_result->AsInterface(); ASSERT_NE(nullptr, interface); const auto& cpp_constants = interface->GetConstantDeclarations(); EXPECT_EQ((size_t)1, cpp_constants.size()); EXPECT_EQ("POSITIVE_HEX_VALUE", cpp_constants[0]->GetName()); EXPECT_EQ("245", cpp_constants[0]->ValueString(cpp::ConstantValueDecorator)); } 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 AidlInterface* interface = cpp_parse_result->AsInterface(); ASSERT_NE(nullptr, interface); const auto& cpp_constants = interface->GetConstantDeclarations(); EXPECT_EQ((size_t)1, cpp_constants.size()); EXPECT_EQ("NEGATIVE_HEX_VALUE", cpp_constants[0]->GetName()); EXPECT_EQ("-1", cpp_constants[0]->ValueString(cpp::ConstantValueDecorator)); } TEST_F(AidlTest, UnderstandsNestedParcelables) { io_delegate_.SetFileContents( "p/Outer.aidl", "package p; parcelable Outer.Inner cpp_header \"baz/header\";"); import_paths_.emplace(""); 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_.emplace(""); 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. vector args = { "aidl", "-d dep/file/path", "-o place/for/output", "p/IFoo.aidl"}; Options options = Options::From(args); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.DependencyFile(), &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. vector args = { "aidl", "-d dep/file/path", "--ninja", "-o place/for/output", "p/IFoo.aidl"}; Options options = Options::From(args); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.DependencyFile(), &actual_dep_file_contents)); EXPECT_EQ(actual_dep_file_contents, kExpectedNinjaDepFileContents); } TEST_F(AidlTest, WritesTrivialDependencyFileForParcelableDeclaration) { // 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. vector args = { "aidl", "-o place/for/output", "-d dep/file/path", "p/Foo.aidl"}; Options options = Options::From(args); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; parcelable Foo;"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.DependencyFile(), &actual_dep_file_contents)); EXPECT_EQ(actual_dep_file_contents, kExpectedParcelableDeclarationDepFileContents); } TEST_F(AidlTest, WritesDependencyFileForStructuredParcelable) { vector args = { "aidl", "--structured", "-o place/for/output", "-d dep/file/path", "p/Foo.aidl"}; Options options = Options::From(args); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; parcelable Foo {int a;}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string actual_dep_file_contents; EXPECT_TRUE(io_delegate_.GetWrittenContents(options.DependencyFile(), &actual_dep_file_contents)); EXPECT_EQ(actual_dep_file_contents, kExpectedStructuredParcelableDepFileContents); } TEST_F(AidlTest, NoJavaOutputForParcelableDeclaration) { vector args = { "aidl", "--lang=java", "-o place/for/output", "p/Foo.aidl"}; Options options = Options::From(args); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; parcelable Foo;"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string output_file_contents; EXPECT_FALSE(io_delegate_.GetWrittenContents(options.OutputFile(), &output_file_contents)); } /* not working until type_namespace.h is fixed TEST_F(AidlTest, AcceptsNestedContainerType) { string nested_in_iface = "package a; interface IFoo {\n" " List> foo(); }"; string nested_in_parcelable = "package a; parcelable IData {\n" " List> foo;}"; EXPECT_NE(nullptr, Parse("a/IFoo.aidl", nested_in_iface, &java_types_)); EXPECT_NE(nullptr, Parse("a/IFoo.aidl", nested_in_iface, &cpp_types_)); EXPECT_NE(nullptr, Parse("a/IFoo.aidl", nested_in_parcelable, &java_types_)); EXPECT_NE(nullptr, Parse("a/IFoo.aidl", nested_in_parcelable, &cpp_types_)); } */ TEST_F(AidlTest, ApiDump) { io_delegate_.SetFileContents( "foo/bar/IFoo.aidl", "package foo.bar;\n" "import foo.bar.Data;\n" "// comment\n" "interface IFoo {\n" " int foo(out int[] a, String b, boolean c, inout List d);\n" " int foo2(@utf8InCpp String x, inout List y);\n" " IFoo foo3(IFoo foo);\n" " Data getData();\n" " const int A = 1;\n" " const String STR = \"Hello\";\n" "}\n"); io_delegate_.SetFileContents("foo/bar/Data.aidl", "package foo.bar;\n" "import foo.bar.IFoo;\n" "parcelable Data {\n" " int x = 10;\n" " int y;\n" " IFoo foo;\n" " List a;\n" " List b;\n" " @nullable String[] c;\n" "}\n"); io_delegate_.SetFileContents("api.aidl", ""); vector args = {"aidl", "--dumpapi", "--out=dump", "foo/bar/IFoo.aidl", "foo/bar/Data.aidl"}; Options options = Options::From(args); bool result = dump_api(options, io_delegate_); ASSERT_TRUE(result); string actual; EXPECT_TRUE(io_delegate_.GetWrittenContents("dump/foo/bar/IFoo.aidl", &actual)); EXPECT_EQ(actual, R"(package foo.bar; interface IFoo { int foo(out int[] a, String b, boolean c, inout List d); int foo2(@utf8InCpp String x, inout List y); foo.bar.IFoo foo3(foo.bar.IFoo foo); foo.bar.Data getData(); const int A = 1; const String STR = "Hello"; } )"); EXPECT_TRUE(io_delegate_.GetWrittenContents("dump/foo/bar/Data.aidl", &actual)); EXPECT_EQ(actual, R"(package foo.bar; parcelable Data { int x = 10; int y; foo.bar.IFoo foo; List a; List b; @nullable String[] c; } )"); } TEST_F(AidlTest, ApiDumpWithManualIds) { io_delegate_.SetFileContents( "foo/bar/IFoo.aidl", "package foo.bar;\n" "interface IFoo {\n" " int foo() = 1;\n" " int bar() = 2;\n" " int baz() = 10;\n" "}\n"); vector args = {"aidl", "--dumpapi", "-o dump", "foo/bar/IFoo.aidl"}; Options options = Options::From(args); bool result = dump_api(options, io_delegate_); ASSERT_TRUE(result); string actual; EXPECT_TRUE(io_delegate_.GetWrittenContents("dump/foo/bar/IFoo.aidl", &actual)); EXPECT_EQ(actual, R"(package foo.bar; interface IFoo { int foo() = 1; int bar() = 2; int baz() = 10; } )"); } TEST_F(AidlTest, ApiDumpWithManualIdsOnlyOnSomeMethods) { io_delegate_.SetFileContents( "foo/bar/IFoo.aidl", "package foo.bar;\n" "interface IFoo {\n" " int foo() = 1;\n" " int bar();\n" " int baz() = 10;\n" "}\n"); vector args = {"aidl", "--dumpapi", "-o dump", "foo/bar/IFoo.aidl"}; Options options = Options::From(args); EXPECT_FALSE(dump_api(options, io_delegate_)); } TEST_F(AidlTest, CheckNumGenericTypeSecifier) { Options options = Options::From("aidl p/IFoo.aidl IFoo.java"); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {" "void foo(List a);}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {" "void foo(Map a);}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); Options options2 = Options::From("aidl p/Data.aidl Data.java"); io_delegate_.SetFileContents(options2.InputFiles().front(), "package p; parcelable Data {" "List foo;}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options2, io_delegate_)); io_delegate_.SetFileContents(options2.InputFiles().front(), "package p; parcelable Data {" "Map foo;}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options2, io_delegate_)); } TEST_F(AidlTest, MultipleTypesInSingleFile) { Options options = Options::From("aidl --lang=java -o out foo/bar/Foo.aidl"); io_delegate_.SetFileContents(options.InputFiles().front(), "package foo.bar;\n" "interface IFoo1 { int foo(); }\n" "interface IFoo2 { int foo(); }\n" "parcelable Data { int a; int b;}\n"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string content; for (const auto file : {"out/foo/bar/IFoo1.java", "out/foo/bar/IFoo2.java", "out/foo/bar/Data.java"}) { content.clear(); EXPECT_TRUE(io_delegate_.GetWrittenContents(file, &content)); EXPECT_FALSE(content.empty()); } } TEST_F(AidlTest, MultipleTypesInSingleFileCpp) { Options options = Options::From("aidl --lang=cpp -o out -h out/include foo/bar/Foo.aidl"); io_delegate_.SetFileContents(options.InputFiles().front(), "package foo.bar;\n" "interface IFoo1 { int foo(); }\n" "interface IFoo2 { int foo(); }\n" "parcelable Data { int a; int b;}\n"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string content; for (const auto file : { "out/foo/bar/IFoo1.cpp", "out/foo/bar/IFoo2.cpp", "out/foo/bar/Data.cpp", "out/include/foo/bar/IFoo1.h", "out/include/foo/bar/IFoo2.h", "out/include/foo/bar/Data.h", "out/include/foo/bar/BpFoo1.h", "out/include/foo/bar/BpFoo2.h", "out/include/foo/bar/BpData.h", "out/include/foo/bar/BnFoo1.h", "out/include/foo/bar/BnFoo2.h", "out/include/foo/bar/BnData.h"}) { content.clear(); EXPECT_TRUE(io_delegate_.GetWrittenContents(file, &content)); EXPECT_FALSE(content.empty()); } } TEST_F(AidlTest, MultipleInputFiles) { Options options = Options::From( "aidl --lang=java -o out foo/bar/IFoo.aidl foo/bar/Data.aidl"); io_delegate_.SetFileContents(options.InputFiles().at(0), "package foo.bar;\n" "import foo.bar.Data;\n" "interface IFoo { Data getData(); }\n"); io_delegate_.SetFileContents(options.InputFiles().at(1), "package foo.bar;\n" "import foo.bar.IFoo;\n" "parcelable Data { IFoo foo; }\n"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string content; for (const auto file : { "out/foo/bar/IFoo.java", "out/foo/bar/Data.java"}) { content.clear(); EXPECT_TRUE(io_delegate_.GetWrittenContents(file, &content)); EXPECT_FALSE(content.empty()); } } TEST_F(AidlTest, MultipleInputFilesCpp) { Options options = Options::From("aidl --lang=cpp -o out -h out/include " "foo/bar/IFoo.aidl foo/bar/Data.aidl"); io_delegate_.SetFileContents(options.InputFiles().at(0), "package foo.bar;\n" "import foo.bar.Data;\n" "interface IFoo { Data getData(); }\n"); io_delegate_.SetFileContents(options.InputFiles().at(1), "package foo.bar;\n" "import foo.bar.IFoo;\n" "parcelable Data { IFoo foo; }\n"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); string content; for (const auto file : { "out/foo/bar/IFoo.cpp", "out/foo/bar/Data.cpp", "out/include/foo/bar/IFoo.h", "out/include/foo/bar/Data.h", "out/include/foo/bar/BpFoo.h", "out/include/foo/bar/BpData.h", "out/include/foo/bar/BnFoo.h", "out/include/foo/bar/BnData.h"}) { content.clear(); EXPECT_TRUE(io_delegate_.GetWrittenContents(file, &content)); EXPECT_FALSE(content.empty()); } } TEST_F(AidlTest, ConflictWithMetaTransactions) { Options options = Options::From("aidl --lang=java -o place/for/output p/IFoo.aidl"); // int getInterfaceVersion() is one of the meta transactions io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {" "int getInterfaceVersion(); }"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); // boolean getInterfaceVersion() is not, but should be prevented // because return type is not part of a method signature io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {" "boolean getInterfaceVersion(); }"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); // this is another reserved name io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {" "String getTransactionName(int code); }"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); // this is not a meta interface method as it differs type arguments io_delegate_.SetFileContents(options.InputFiles().front(), "package p; interface IFoo {" "String getTransactionName(); }"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); } TEST_F(AidlTest, DiffrentOrderAnnotationsInCheckAPI) { Options options = Options::From("aidl --checkapi old new"); io_delegate_.SetFileContents("old/p/IFoo.aidl", "package p; interface IFoo{ @utf8InCpp @nullable String foo();}"); io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p; interface IFoo{ @nullable @utf8InCpp String foo();}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); } TEST_F(AidlTest, SuccessOnIdenticalApiDumps) { Options options = Options::From("aidl --checkapi old new"); io_delegate_.SetFileContents("old/p/IFoo.aidl", "package p; interface IFoo{ void foo();}"); io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p; interface IFoo{ void foo();}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); } TEST_F(AidlTest, SuccessOnCompatibleChanges) { Options options = Options::From("aidl --checkapi old new"); io_delegate_.SetFileContents("old/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(int a);" "}"); io_delegate_.SetFileContents("old/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" "}"); // new type io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(int a);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" "}"); io_delegate_.SetFileContents("new/p/IBar.aidl", "package p;" "interface IBar {" " void bar();" "}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); io_delegate_.SetFileContents("new/p/IBar.aidl", ""); // new method io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(int a);" " void bar();" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" "}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // new field io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(int a);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // new package io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(int a);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" "}"); io_delegate_.SetFileContents("new/q/IFoo.aidl", "package q;" "interface IFoo {" " void foo(int a);" "}"); io_delegate_.SetFileContents("new/q/Data.aidl", "package q;" "parcelable Data {" " int foo;" "}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); io_delegate_.SetFileContents("new/q/IFoo.aidl", ""); io_delegate_.SetFileContents("new/q/Data.aidl", ""); // arg name change io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(int b);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" "}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); io_delegate_.SetFileContents("old/p/IFoo.aidl", ""); io_delegate_.SetFileContents("old/p/Data.aidl", ""); // added const value io_delegate_.SetFileContents("old/p/I.aidl", "package p; interface I {" "const int A = 1; }"); io_delegate_.SetFileContents("new/p/I.aidl", "package p ; interface I {" "const int A = 1; const int B = 2;}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("old/p/I.aidl", ""); io_delegate_.SetFileContents("new/p/I.aidl", ""); // changed const value order io_delegate_.SetFileContents("old/p/I.aidl", "package p; interface I {" "const int A = 1; const int B = 2;}"); io_delegate_.SetFileContents("new/p/I.aidl", "package p ; interface I {" "const int B = 2; const int A = 1;}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); } TEST_F(AidlTest, FailOnIncompatibleChanges) { Options options = Options::From("aidl --checkapi old new"); io_delegate_.SetFileContents("old/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("old/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); // removed type io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar(@utf8InCpp String str);" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); // removed method io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // removed field io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // renamed method io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar2(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // renamed field io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar2;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // renamed type io_delegate_.SetFileContents("new/p/IFoo2.aidl", "package p;" "interface IFoo2 {" " void foo(in String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo2.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // reorderd method io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void bar(@utf8InCpp String str);" " void foo(in String[] str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // reorderd field io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int bar;" " int foo;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // changed direction specifier io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(out String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // added annotation io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in @utf8InCpp String[] str);" " void bar(@utf8InCpp String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // removed annotation io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p;" "interface IFoo {" " void foo(in String[] str);" " void bar(String str);" "}"); io_delegate_.SetFileContents("new/p/Data.aidl", "package p;" "parcelable Data {" " int foo;" " int bar;" "}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/Data.aidl", ""); // removed package io_delegate_.SetFileContents("old/p/Data.aidl", ""); io_delegate_.SetFileContents("old/p/IFoo.aidl", "package p; interface IFoo{}"); io_delegate_.SetFileContents("old/q/IFoo.aidl", "package q; interface IFoo{}"); io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p; interface IFoo{}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("old/p/IFoo.aidl", ""); io_delegate_.SetFileContents("old/q/IFoo.aidl", ""); io_delegate_.SetFileContents("new/p/IFoo.aidl", ""); // changed default value io_delegate_.SetFileContents("old/p/D.aidl", "package p; parcelable D { int a = 1; }"); io_delegate_.SetFileContents("new/p/D.aidl", "package p; parcelable D { int a = 2; }"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("old/p/D.aidl", ""); io_delegate_.SetFileContents("new/p/D.aidl", ""); // removed const value io_delegate_.SetFileContents("old/p/I.aidl", "package p; interface I {" "const int A = 1; const int B = 2;}"); io_delegate_.SetFileContents("new/p/I.aidl", "package p; interface I { const int A = 1; }"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("old/p/I.aidl", ""); io_delegate_.SetFileContents("new/p/I.aidl", ""); // changed const value io_delegate_.SetFileContents("old/p/I.aidl", "package p; interface I { const int A = 1; }"); io_delegate_.SetFileContents("new/p/I.aidl", "package p; interface I { const int A = 2; }"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("old/p/I.aidl", ""); io_delegate_.SetFileContents("new/p/I.aidl", ""); } TEST_F(AidlTest, RejectAmbiguousImports) { Options options = Options::From("aidl --lang=java -o out -I dir1 -I dir2 p/IFoo.aidl"); io_delegate_.SetFileContents("p/IFoo.aidl", "package p; import q.IBar; interface IFoo{}"); io_delegate_.SetFileContents("dir1/q/IBar.aidl", "package q; interface IBar{}"); io_delegate_.SetFileContents("dir2/q/IBar.aidl", "package q; interface IBar{}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); } TEST_F(AidlTest, HandleManualIdAssignments) { Options options = Options::From("aidl --checkapi old new"); io_delegate_.SetFileContents("old/p/IFoo.aidl", "package p; interface IFoo{ void foo() = 10;}"); io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p; interface IFoo{ void foo() = 10;}"); EXPECT_TRUE(::android::aidl::check_api(options, io_delegate_)); io_delegate_.SetFileContents("new/p/IFoo.aidl", "package p; interface IFoo{ void foo() = 11;}"); EXPECT_FALSE(::android::aidl::check_api(options, io_delegate_)); } TEST_F(AidlTest, ParcelFileDescriptorIsBuiltinType) { Options javaOptions = Options::From("aidl --lang=java -o out p/IFoo.aidl"); Options cppOptions = Options::From("aidl --lang=cpp -h out -o out p/IFoo.aidl"); // use without import io_delegate_.SetFileContents("p/IFoo.aidl", "package p; interface IFoo{ void foo(in ParcelFileDescriptor fd);}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(javaOptions, io_delegate_)); EXPECT_EQ(0, ::android::aidl::compile_aidl(cppOptions, io_delegate_)); // use without impot but with full name io_delegate_.SetFileContents( "p/IFoo.aidl", "package p; interface IFoo{ void foo(in android.os.ParcelFileDescriptor fd);}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(javaOptions, io_delegate_)); EXPECT_EQ(0, ::android::aidl::compile_aidl(cppOptions, io_delegate_)); // use with import (as before) io_delegate_.SetFileContents("p/IFoo.aidl", "package p;" "import android.os.ParcelFileDescriptor;" "interface IFoo{" " void foo(in ParcelFileDescriptor fd);" "}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(javaOptions, io_delegate_)); EXPECT_EQ(0, ::android::aidl::compile_aidl(cppOptions, io_delegate_)); } TEST_F(AidlTest, ManualIds) { Options options = Options::From("aidl --lang=java -o out IFoo.aidl"); io_delegate_.SetFileContents("IFoo.aidl", "interface IFoo {\n" " void foo() = 0;\n" " void bar() = 1;\n" "}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); } TEST_F(AidlTest, ManualIdsWithMetaTransactions) { Options options = Options::From("aidl --lang=java --version 10 -o out IFoo.aidl"); io_delegate_.SetFileContents("IFoo.aidl", "interface IFoo {\n" " void foo() = 0;\n" " void bar() = 1;\n" "}"); EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); } TEST_F(AidlTest, FailOnDuplicatedIds) { Options options = Options::From("aidl --lang=java --version 10 -o out IFoo.aidl"); io_delegate_.SetFileContents("IFoo.aidl", "interface IFoo {\n" " void foo() = 3;\n" " void bar() = 3;\n" "}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); } TEST_F(AidlTest, FailOnOutOfRangeIds) { // 16777115 is kLastMetaMethodId + 1 Options options = Options::From("aidl --lang=java --version 10 -o out IFoo.aidl"); io_delegate_.SetFileContents("IFoo.aidl", "interface IFoo {\n" " void foo() = 3;\n" " void bar() = 16777115;\n" "}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); } TEST_F(AidlTest, FailOnPartiallyAssignedIds) { Options options = Options::From("aidl --lang=java --version 10 -o out IFoo.aidl"); io_delegate_.SetFileContents("IFoo.aidl", "interface IFoo {\n" " void foo() = 3;\n" " void bar();\n" "}"); EXPECT_NE(0, ::android::aidl::compile_aidl(options, io_delegate_)); } class AidlOutputPathTest : public AidlTest { protected: void SetUp() override { AidlTest::SetUp(); io_delegate_.SetFileContents("sub/dir/foo/bar/IFoo.aidl", "package foo.bar; interface IFoo {}"); } void Test(const Options& options, const std::string expected_output_path) { EXPECT_EQ(0, ::android::aidl::compile_aidl(options, io_delegate_)); // check the existence EXPECT_TRUE(io_delegate_.GetWrittenContents(expected_output_path, nullptr)); } }; TEST_F(AidlOutputPathTest, OutDirWithNoOutputFile) { // / / .java Test(Options::From("aidl -o out sub/dir/foo/bar/IFoo.aidl"), "out/foo/bar/IFoo.java"); } TEST_F(AidlOutputPathTest, OutDirWithOutputFile) { // when output file is explicitly set, it is always respected. -o option is // ignored. Test(Options::From("aidl -o out sub/dir/foo/bar/IFoo.aidl output/IFoo.java"), "output/IFoo.java"); } TEST_F(AidlOutputPathTest, NoOutDirWithOutputFile) { Test(Options::From("aidl -o out sub/dir/foo/bar/IFoo.aidl output/IFoo.java"), "output/IFoo.java"); } TEST_F(AidlOutputPathTest, NoOutDirWithNoOutputFile) { // output is the same as the input file except for the suffix Test(Options::From("aidl sub/dir/foo/bar/IFoo.aidl"), "sub/dir/foo/bar/IFoo.java"); } } // namespace aidl } // namespace android ast_cpp.cpp0100644 0000000 0000000 00000032130 13755771705 011762 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 { std::string AstNode::ToString() { std::string str; Write(CodeWriter::ForString(&str).get()); return str; } LiteralDecl::LiteralDecl(const std::string& expression) : expression_(expression) {} void LiteralDecl::Write(CodeWriter* to) const { to->Write("%s", expression_.c_str()); } ClassDecl::ClassDecl(const std::string& name, const std::string& parent) : name_(name), parent_(parent) {} 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"); to->Indent(); for (const auto& dec : public_members_) dec->Write(to); to->Dedent(); if (!private_members_.empty()) to->Write("private:\n"); to->Indent(); for (const auto& dec : private_members_) dec->Write(to); to->Dedent(); 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()); } to->Indent(); 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->Dedent(); 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) noexcept : 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), is_final_(modifiers & IS_FINAL) {} 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_final_) to->Write(" final"); 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"); to->Indent(); for (const auto& statement : statements_) { statement->Write(to); } to->Dedent(); 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, std::vector> declarations) : include_list_(include_list), declarations_(std::move(declarations)) {} void Document::Write(CodeWriter* to) const { for (const auto& include : include_list_) { to->Write("#include <%s>\n", include.c_str()); } to->Write("\n"); for (const auto& declaration : declarations_) { declaration->Write(to); } } CppHeader::CppHeader(const std::string& include_guard, const std::vector& include_list, std::vector> declarations) : Document(include_list, std::move(declarations)), 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, std::vector> declarations) : Document(include_list, std::move(declarations)) {} } // namespace cpp } // namespace aidl } // namespace android ast_cpp.h0100644 0000000 0000000 00000027262 13755771705 011441 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. */ #pragma once #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; std::string ToString(); }; // class AstNode class Declaration : public AstNode { public: Declaration() = default; virtual ~Declaration() = default; private: DISALLOW_COPY_AND_ASSIGN(Declaration); }; // class Declaration class LiteralDecl : public Declaration { public: explicit LiteralDecl(const std::string& expression); ~LiteralDecl() = default; void Write(CodeWriter* to) const override; private: const std::string expression_; DISALLOW_COPY_AND_ASSIGN(LiteralDecl); }; // class LiteralDecl class ClassDecl : public Declaration { public: ClassDecl(const std::string& name, 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) noexcept; 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, IS_FINAL = 1 << 5, }; 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; bool is_final_ = false; 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::vector> declarations); void Write(CodeWriter* to) const override; private: std::vector include_list_; std::vector> declarations_; 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::vector> declarations); 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::vector> declarations); private: DISALLOW_COPY_AND_ASSIGN(CppSource); }; // class CppSource } // namespace cpp } // namespace aidl } // namespace android ast_cpp_unittest.cpp0100644 0000000 0000000 00000016047 13755771705 013732 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; node.Write(CodeWriter::ForString(&actual_output).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) }}; vector> test_ns_globals; test_ns_globals.push_back(std::move(android_ns)); CppHeader cpp_header{"HEADER_INCLUDE_GUARD_H_", {"string", "memory"}, std::move(test_ns_globals)}; 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, "{\n foo;\n bar;\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) {\n on true1;\n}\nelse {\n on false;\n}\n"); IfStatement s2(new LiteralExpression("bar")); s2.OnTrue()->AddLiteral("on true1"); CompareGeneratedCode(s2, "if (bar) {\n on 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); } TEST_F(AstCppTests, ToString) { std::string literal = "void foo() {}"; LiteralDecl decl(literal); std::string actual = decl.ToString(); EXPECT_EQ(literal, actual); std::string written; decl.Write(CodeWriter::ForString(&written).get()); EXPECT_EQ(literal, written); } } // namespace cpp } // namespace aidl } // namespace android ast_java.cpp0100644 0000000 0000000 00000027602 13755771705 012131 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" using std::vector; using std::string; template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...)->overloaded; namespace android { namespace aidl { namespace java { std::string AstNode::ToString() { std::string str; Write(CodeWriter::ForString(&str).get()); return str; } 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()); } for (const auto& a : this->annotations) { to->Write("%s\n", a.c_str()); } WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE); this->variable->WriteDeclaration(to); 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 string& t, const string& n) : type(t), name(n), dimension(0) {} Variable::Variable(const string& 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.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) : receiver(o), name(n) {} FieldVariable::FieldVariable(const string& c, const string& n) : receiver(c), name(n) {} void FieldVariable::Write(CodeWriter* to) const { visit( overloaded{[&](Expression* e) { e->Write(to); }, [&](const std::string& s) { to->Write("%s", s.c_str()); }, [](std::monostate) {}}, this->receiver); to->Write(".%s", name.c_str()); } LiteralStatement::LiteralStatement(const std::string& value) : value_(value) {} void LiteralStatement::Write(CodeWriter* to) const { to->Write("%s", value_.c_str()); } void StatementBlock::Write(CodeWriter* to) const { to->Write("{\n"); to->Indent(); int N = this->statements.size(); for (int i = 0; i < N; i++) { this->statements[i]->Write(to); } to->Dedent(); 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) {} Assignment::Assignment(Variable* l, Expression* r, string c) : lvalue(l), rvalue(r), cast(c) {} void Assignment::Write(CodeWriter* to) const { this->lvalue->Write(to); to->Write(" = "); if (this->cast) { to->Write("(%s)", this->cast->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) : receiver(o), name(n) {} MethodCall::MethodCall(const std::string& t, const string& n) : receiver(t), name(n) {} MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...) : receiver(o), name(n) { va_list args; va_start(args, argc); init(argc, args); va_end(args); } MethodCall::MethodCall(const std::string& t, const string& n, int argc = 0, ...) : receiver(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 { visit( overloaded{[&](Expression* e) { e->Write(to); to->Write("."); }, [&](const std::string& s) { to->Write("%s.", s.c_str()); }, [](std::monostate) {}}, this->receiver); 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 std::string& n) : instantiableName(n) {} NewExpression::NewExpression(const std::string& n, int argc = 0, ...) : instantiableName(n) { 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->instantiableName.c_str()); WriteArgumentList(to, this->arguments); to->Write(")"); } NewArrayExpression::NewArrayExpression(const std::string& t, Expression* s) : type(t), size(s) {} void NewArrayExpression::Write(CodeWriter* to) const { to->Write("new %s[", this->type.c_str()); size->Write(to); to->Write("]"); } Cast::Cast(const std::string& t, Expression* e) : type(t), expression(e) {} void Cast::Write(CodeWriter* to) const { to->Write("((%s)", this->type.c_str()); expression->Write(to); to->Write(")"); } VariableDeclaration::VariableDeclaration(Variable* l, Expression* r) : lvalue(l), rvalue(r) {} VariableDeclaration::VariableDeclaration(Variable* l) : lvalue(l) {} void VariableDeclaration::Write(CodeWriter* to) const { this->lvalue->WriteDeclaration(to); if (this->rvalue != nullptr) { to->Write(" = "); this->rvalue->Write(to); } to->Write(";\n"); } void IfStatement::Write(CodeWriter* to) const { if (this->expression != nullptr) { to->Write("if ("); this->expression->Write(to); to->Write(") "); } this->statements->Write(to); if (this->elseif != nullptr) { 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); } 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"); to->Indent(); int N = this->cases.size(); for (int i = 0; i < N; i++) { this->cases[i]->Write(to); } to->Dedent(); to->Write("}\n"); } void Method::Write(CodeWriter* to) const { size_t N, i; if (this->comment.length() != 0) { to->Write("%s\n", this->comment.c_str()); } for (const auto& a : this->annotations) { to->Write("%s\n", a.c_str()); } WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE); if (this->returnType) { string dim; for (i = 0; i < this->returnTypeDimension; i++) { dim += "[]"; } to->Write("%s%s ", this->returnType->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].c_str()); } if (this->statements == nullptr) { to->Write(";\n"); } else { to->Write("\n"); this->statements->Write(to); } } void LiteralClassElement::Write(CodeWriter* to) const { to->Write("%s", element.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()); } for (const auto& a : this->annotations) { to->Write("%s\n", a.c_str()); } WriteModifiers(to, this->modifiers, ALL_MODIFIERS); if (this->what == Class::CLASS) { to->Write("class "); } else { to->Write("interface "); } string name = this->type; size_t pos = name.rfind('.'); if (pos != string::npos) { name = name.c_str() + pos + 1; } to->Write("%s", name.c_str()); if (this->extends) { to->Write(" extends %s", this->extends->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].c_str()); } } to->Write("\n"); to->Write("{\n"); to->Indent(); N = this->elements.size(); for (i = 0; i < N; i++) { this->elements[i]->Write(to); } to->Dedent(); to->Write("}\n"); } Document::Document(const std::string& comment, const std::string& package, std::unique_ptr clazz) : comment_(comment), package_(package), 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" " */\n"); 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 00000022316 13755771705 011573 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. */ #pragma once #include #include #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 { // Write the modifiers that are set in both mod and mask void WriteModifiers(CodeWriter* to, int mod, int mask); struct AstNode { AstNode() = default; virtual ~AstNode() = default; virtual void Write(CodeWriter* to) const = 0; std::string ToString(); }; struct ClassElement : public AstNode { ClassElement() = default; virtual ~ClassElement() = default; }; struct Expression : public AstNode { virtual ~Expression() = default; }; 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 std::string type; std::string name; int dimension = 0; Variable() = default; Variable(const std::string& type, const std::string& name); Variable(const std::string& type, const std::string& name, int dimension); virtual ~Variable() = default; void WriteDeclaration(CodeWriter* to) const; void Write(CodeWriter* to) const; }; struct FieldVariable : public Expression { std::variant receiver; std::string name; FieldVariable(Expression* object, const std::string& name); FieldVariable(const std::string& clazz, const std::string& name); virtual ~FieldVariable() = default; void Write(CodeWriter* to) const; }; struct Field : public ClassElement { std::string comment; std::vector annotations; 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 : public AstNode { virtual ~Statement() = default; }; struct LiteralStatement : public Statement { public: LiteralStatement(const std::string& value); virtual ~LiteralStatement() = default; void Write(CodeWriter* to) const override; private: const std::string value_; }; 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; std::optional cast = std::nullopt; Assignment(Variable* lvalue, Expression* rvalue); Assignment(Variable* lvalue, Expression* rvalue, std::string cast); virtual ~Assignment() = default; void Write(CodeWriter* to) const override; }; struct MethodCall : public Expression { std::variant receiver; 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 std::string& clazz, const std::string& name); MethodCall(Expression* obj, const std::string& name, int argc, ...); MethodCall(const std::string&, 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 std::string instantiableName; std::vector arguments; explicit NewExpression(const std::string& name); NewExpression(const std::string& name, int argc, ...); virtual ~NewExpression() = default; void Write(CodeWriter* to) const override; private: void init(int n, va_list args); }; struct NewArrayExpression : public Expression { const std::string type; Expression* size; NewArrayExpression(const std::string& type, Expression* size); virtual ~NewArrayExpression() = default; void Write(CodeWriter* to) const override; }; struct Cast : public Expression { const std::string type; Expression* expression = nullptr; Cast() = default; Cast(const std::string& type, Expression* expression); virtual ~Cast() = default; void Write(CodeWriter* to) const override; }; struct VariableDeclaration : public Statement { Variable* lvalue = nullptr; Expression* rvalue = nullptr; explicit VariableDeclaration(Variable* lvalue); VariableDeclaration(Variable* lvalue, Expression* rvalue); 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 FinallyStatement : public Statement { StatementBlock* statements = new StatementBlock; FinallyStatement() = default; virtual ~FinallyStatement() = default; void Write(CodeWriter* to) const override; }; struct Case : public AstNode { std::vector cases; StatementBlock* statements = new StatementBlock; Case() = default; explicit Case(const std::string& c); virtual ~Case() = default; void Write(CodeWriter* to) const override; }; struct SwitchStatement : public Statement { Expression* expression; std::vector cases; explicit SwitchStatement(Expression* expression); virtual ~SwitchStatement() = default; void Write(CodeWriter* to) const override; }; struct Method : public ClassElement { std::string comment; std::vector annotations; int modifiers = 0; std::optional returnType = std::nullopt; // nullopt 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 LiteralClassElement : public ClassElement { std::string element; LiteralClassElement(std::string e) : element(e) {} virtual ~LiteralClassElement() = default; void Write(CodeWriter* to) const override; }; struct Class : public ClassElement { enum { CLASS, INTERFACE }; std::string comment; std::vector annotations; int modifiers = 0; int what = CLASS; // CLASS or INTERFACE std::string type; std::optional extends = std::nullopt; std::vector interfaces; std::vector elements; Class() = default; virtual ~Class() = default; void Write(CodeWriter* to) const override; }; class Document : public AstNode { public: Document(const std::string& comment, const std::string& package, std::unique_ptr clazz); virtual ~Document() = default; void Write(CodeWriter* to) const override; private: std::string comment_; std::string package_; std::unique_ptr clazz_; }; } // namespace java } // namespace aidl } // namespace android ast_java_unittest.cpp0100644 0000000 0000000 00000003546 13755771705 014071 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); Type extend_type(&types, "SuperClass", ValidatableType::KIND_BUILT_IN, false); Class a_class; a_class.comment = "// class comment"; a_class.modifiers = FINAL; a_class.what = Class::CLASS; a_class.type = class_type.JavaType(); a_class.extends = extend_type.JavaType(); string actual_output; a_class.Write(CodeWriter::ForString(&actual_output).get()); EXPECT_EQ(string(kExpectedClassOutput), actual_output); } TEST(AstJavaTests, ToString) { std::string literal = "public void foo() {}"; LiteralClassElement ce(literal); std::string actual = ce.ToString(); EXPECT_EQ(literal, actual); std::string written; ce.Write(CodeWriter::ForString(&written).get()); EXPECT_EQ(literal, written); } } // namespace java } // namespace aidl } // namespace android build/0040755 0000000 0000000 00000000000 13755771705 010730 5ustar000000000 0000000 build/Android.bp0100644 0000000 0000000 00000005437 13755771705 012641 0ustar000000000 0000000 // Copyright (C) 2018 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. bootstrap_go_package { name: "aidl-soong-rules", pkgPath: "android/soong/aidl", deps: [ "blueprint", "soong", "soong-android", "soong-cc", "soong-genrule", "soong-phony", "soong-java", ], srcs: [ "aidl_interface.go", "properties.go", ], pluginFor: ["soong_build"], } // These configurations are inherited by all aidl-gen modules cc_defaults { name: "aidl-cpp-module-defaults", cflags: [ "-Wall", "-Werror", "-Wextra-semi", ], } java_defaults { name: "aidl-java-module-defaults", } // Tests // Copy of test-piece-1 as test only. Creating a separate library because 'vendor_available' is // contagious. aidl_interface { name: "test-vendor", local_include_dir: "tests_1", vendor_available: true, srcs: [ "tests_1/some_package/IFoo.aidl", "tests_1/some_package/Thing.aidl", "tests_1/some_package/sub_package/*.aidl", ], } aidl_interface { name: "test-piece-1", local_include_dir: "tests_1", srcs: [ "tests_1/some_package/IFoo.aidl", "tests_1/some_package/Thing.aidl", "tests_1/some_package/sub_package/*.aidl", ], api_dir: "api/test-piece-1", versions: ["1"], } aidl_interface { name: "test-piece-2", local_include_dir: "tests_1", srcs: [ "tests_1/INoPackage.aidl", "tests_1/some_package/IBar.aidl", ], imports: [ "test-piece-1", ], api_dir: "api/test-piece-2", versions: ["1"], } aidl_interface { name: "test-piece-3", local_include_dir: "tests_1", srcs: [ "tests_1/other_package/IBaz.aidl", ], imports: [ "test-piece-2", ], api_dir: "api/test-piece-3", versions: ["1"], } aidl_interface { name: "test-piece-4", local_include_dir: "tests_2", srcs: [ "tests_2/another_package/IFaz.aidl", ], imports: [ "test-piece-1", ], api_dir: "api/test-piece-4", versions: ["1"], } aidl_interface { name: "test-root-package", srcs: [ "test_package/IBaz.aidl", ], imports: [ "test-piece-2", ], versions: ["1", "2"], } build/aidl_interface.go0100644 0000000 0000000 00000101232 13755771705 014204 0ustar000000000 0000000 // Copyright (C) 2018 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package aidl import ( "android/soong/android" "android/soong/cc" "android/soong/genrule" "android/soong/java" "android/soong/phony" "fmt" "io" "path/filepath" "strconv" "strings" "sync" "github.com/google/blueprint" "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) var ( aidlInterfaceSuffix = "_interface" aidlApiSuffix = "-api" langCpp = "cpp" langJava = "java" langNdk = "ndk" langNdkPlatform = "ndk_platform" futureVersion = "10000" pctx = android.NewPackageContext("android/aidl") aidlDirPrepareRule = pctx.StaticRule("aidlDirPrepareRule", blueprint.RuleParams{ Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` + `touch ${out}`, Description: "create ${out}", }, "outDir") aidlCppRule = pctx.StaticRule("aidlCppRule", blueprint.RuleParams{ Command: `mkdir -p "${headerDir}" && ` + `${aidlCmd} --lang=${lang} ${optionalFlags} --structured --ninja -d ${out}.d ` + `-h ${headerDir} -o ${outDir} ${imports} ${in}`, Depfile: "${out}.d", Deps: blueprint.DepsGCC, CommandDeps: []string{"${aidlCmd}"}, Description: "AIDL ${lang} ${in}", }, "imports", "lang", "headerDir", "outDir", "optionalFlags") aidlJavaRule = pctx.StaticRule("aidlJavaRule", blueprint.RuleParams{ Command: `${aidlCmd} --lang=java ${optionalFlags} --structured --ninja -d ${out}.d ` + `-o ${outDir} ${imports} ${in}`, Depfile: "${out}.d", Deps: blueprint.DepsGCC, CommandDeps: []string{"${aidlCmd}"}, Description: "AIDL Java ${in}", }, "imports", "outDir", "optionalFlags") aidlDumpApiRule = pctx.StaticRule("aidlDumpApiRule", blueprint.RuleParams{ Command: `rm -rf "${out}" && mkdir -p "${out}" && ` + `${aidlCmd} --dumpapi --structured ${imports} --out ${out} ${in}`, CommandDeps: []string{"${aidlCmd}"}, }, "imports") aidlDumpMappingsRule = pctx.StaticRule("aidlDumpMappingsRule", blueprint.RuleParams{ Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` + `${aidlCmd} --apimapping ${outDir}/intermediate.txt ${in} ${imports} && ` + `${aidlToJniCmd} ${outDir}/intermediate.txt ${out}`, CommandDeps: []string{"${aidlCmd}"}, }, "imports", "outDir") aidlFreezeApiRule = pctx.AndroidStaticRule("aidlFreezeApiRule", blueprint.RuleParams{ Command: `mkdir -p ${to} && rm -rf ${to}/* && ` + `${bpmodifyCmd} -w -m ${name} -parameter versions -a ${version} ${bp} && ` + `cp -rf ${in}/* ${to} && ` + `find ${to} -type f -exec bash -c ` + `"cat ${apiPreamble} {} > {}.temp; mv {}.temp {}" \; && ` + `touch ${out}`, CommandDeps: []string{"${bpmodifyCmd}"}, }, "to", "name", "version", "bp", "apiPreamble") aidlCheckApiRule = pctx.StaticRule("aidlCheckApiRule", blueprint.RuleParams{ Command: `(${aidlCmd} --checkapi ${old} ${new} && touch ${out}) || ` + `(cat ${messageFile} && exit 1)`, CommandDeps: []string{"${aidlCmd}"}, Description: "AIDL CHECK API: ${new} against ${old}", }, "old", "new", "messageFile") aidlDiffApiRule = pctx.StaticRule("aidlDiffApiRule", blueprint.RuleParams{ Command: `(diff -r -B -I '//.*' ${old} ${new} && touch ${out}) || ` + `(cat ${messageFile} && exit 1)`, Description: "Check equality of ${new} and ${old}", }, "old", "new", "messageFile") ) func init() { pctx.HostBinToolVariable("aidlCmd", "aidl") pctx.HostBinToolVariable("bpmodifyCmd", "bpmodify") pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py") android.RegisterModuleType("aidl_interface", aidlInterfaceFactory) android.RegisterModuleType("aidl_mapping", aidlMappingFactory) } // wrap(p, a, s) = [p + v + s for v in a] func wrap(prefix string, strs []string, suffix string) []string { ret := make([]string, len(strs)) for i, v := range strs { ret[i] = prefix + v + suffix } return ret } // concat(a...) = sum((i for i in a), []) func concat(sstrs ...[]string) []string { var ret []string for _, v := range sstrs { ret = append(ret, v...) } return ret } func isRelativePath(path string) bool { if path == "" { return true } return filepath.Clean(path) == path && path != ".." && !strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/") } type aidlGenProperties struct { Srcs []string AidlRoot string // base directory for the input aidl file Imports []string Lang string // target language [java|cpp|ndk] BaseName string GenLog bool Version string } type aidlGenRule struct { android.ModuleBase properties aidlGenProperties implicitInputs android.Paths importFlags string genOutDir android.ModuleGenPath genHeaderDir android.ModuleGenPath genOutputs android.WritablePaths } var _ android.SourceFileProducer = (*aidlGenRule)(nil) var _ genrule.SourceFileGenerator = (*aidlGenRule)(nil) func (g *aidlGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { genDirTimestamp := android.PathForModuleGen(ctx, "timestamp") g.implicitInputs = append(g.implicitInputs, genDirTimestamp) var importPaths []string ctx.VisitDirectDeps(func(dep android.Module) { if importedAidl, ok := dep.(*aidlInterface); ok { importPaths = append(importPaths, importedAidl.properties.Full_import_paths...) } else if api, ok := dep.(*aidlApi); ok { // When compiling an AIDL interface, also make sure that each // version of the interface is compatible with its previous version for _, path := range api.checkApiTimestamps { g.implicitInputs = append(g.implicitInputs, path) } } }) g.importFlags = strings.Join(wrap("-I", importPaths, ""), " ") srcs := android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, g.properties.Srcs), g.properties.AidlRoot) g.genOutDir = android.PathForModuleGen(ctx) g.genHeaderDir = android.PathForModuleGen(ctx, "include") for _, src := range srcs { g.genOutputs = append(g.genOutputs, g.generateBuildActionsForSingleAidl(ctx, src)) } // This is to clean genOutDir before generating any file ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlDirPrepareRule, Implicits: srcs, Output: genDirTimestamp, Args: map[string]string{ "outDir": g.genOutDir.String(), }, }) } func (g *aidlGenRule) generateBuildActionsForSingleAidl(ctx android.ModuleContext, src android.Path) android.WritablePath { var outFile android.WritablePath if g.properties.Lang == langJava { outFile = android.PathForModuleGen(ctx, pathtools.ReplaceExtension(src.Rel(), "java")) } else { outFile = android.PathForModuleGen(ctx, pathtools.ReplaceExtension(src.Rel(), "cpp")) } var optionalFlags []string if g.properties.Version != "" { optionalFlags = append(optionalFlags, "--version "+g.properties.Version) } if g.properties.Lang == langJava { ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlJavaRule, Input: src, Implicits: g.implicitInputs, Output: outFile, Args: map[string]string{ "imports": g.importFlags, "outDir": g.genOutDir.String(), "optionalFlags": strings.Join(optionalFlags, " "), }, }) } else { typeName := strings.TrimSuffix(filepath.Base(src.Rel()), ".aidl") packagePath := filepath.Dir(src.Rel()) baseName := typeName // TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if // an interface name has a leading I. Those same heuristics have been // moved here. if len(baseName) >= 2 && baseName[0] == 'I' && strings.ToUpper(baseName)[1] == baseName[1] { baseName = strings.TrimPrefix(typeName, "I") } prefix := "" if g.properties.Lang == langNdk || g.properties.Lang == langNdkPlatform { prefix = "aidl" } var headers android.WritablePaths headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath, typeName+".h")) headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath, "Bp"+baseName+".h")) headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath, "Bn"+baseName+".h")) if g.properties.GenLog { optionalFlags = append(optionalFlags, "--log") } aidlLang := g.properties.Lang if aidlLang == langNdkPlatform { aidlLang = "ndk" } ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlCppRule, Input: src, Implicits: g.implicitInputs, Output: outFile, ImplicitOutputs: headers, Args: map[string]string{ "imports": g.importFlags, "lang": aidlLang, "headerDir": g.genHeaderDir.String(), "outDir": g.genOutDir.String(), "optionalFlags": strings.Join(optionalFlags, " "), }, }) } return outFile } func (g *aidlGenRule) GeneratedSourceFiles() android.Paths { return g.genOutputs.Paths() } func (g *aidlGenRule) Srcs() android.Paths { return g.genOutputs.Paths() } func (g *aidlGenRule) GeneratedDeps() android.Paths { return g.genOutputs.Paths() } func (g *aidlGenRule) GeneratedHeaderDirs() android.Paths { return android.Paths{g.genHeaderDir} } func (g *aidlGenRule) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), nil, wrap("", g.properties.Imports, aidlInterfaceSuffix)...) ctx.AddDependency(ctx.Module(), nil, g.properties.BaseName+aidlApiSuffix) } func aidlGenFactory() android.Module { g := &aidlGenRule{} g.AddProperties(&g.properties) android.InitAndroidModule(g) return g } type aidlApiProperties struct { BaseName string Inputs []string Imports []string Api_dir *string Versions []string AidlRoot string // base directory for the input aidl file } type aidlApi struct { android.ModuleBase properties aidlApiProperties // for triggering api check for version X against version X-1 checkApiTimestamps android.WritablePaths // for triggering freezing API as the new version freezeApiTimestamp android.WritablePath } func (m *aidlApi) apiDir() string { if m.properties.Api_dir != nil { return *(m.properties.Api_dir) } else { return "api" } } // Version of the interface at ToT if it is frozen func (m *aidlApi) validateCurrentVersion(ctx android.ModuleContext) string { if len(m.properties.Versions) == 0 { return "1" } else { latestVersion := m.properties.Versions[len(m.properties.Versions)-1] i, err := strconv.ParseInt(latestVersion, 10, 64) if err != nil { ctx.PropertyErrorf("versions", "must be integers") return "" } return strconv.FormatInt(i+1, 10) } } func (m *aidlApi) createApiDumpFromSource(ctx android.ModuleContext) (apiDir android.WritablePath, apiFiles android.WritablePaths) { var importPaths []string ctx.VisitDirectDeps(func(dep android.Module) { if importedAidl, ok := dep.(*aidlInterface); ok { importPaths = append(importPaths, importedAidl.properties.Full_import_paths...) } }) var srcs android.Paths for _, input := range m.properties.Inputs { path := android.PathForModuleSrc(ctx, input) path = android.PathWithModuleSrcSubDir(ctx, path, m.properties.AidlRoot) srcs = append(srcs, path) } apiDir = android.PathForModuleOut(ctx, "dump") for _, src := range srcs { apiFiles = append(apiFiles, android.PathForModuleOut(ctx, "dump", src.Rel())) } imports := strings.Join(wrap("-I", importPaths, ""), " ") ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlDumpApiRule, Inputs: srcs, Output: apiDir, ImplicitOutputs: apiFiles, Args: map[string]string{ "imports": imports, }, }) return apiDir, apiFiles } func (m *aidlApi) freezeApiDumpAsVersion(ctx android.ModuleContext, apiDumpDir android.Path, apiFiles android.Paths, version string) android.WritablePath { timestampFile := android.PathForModuleOut(ctx, "freezeapi_"+version+".timestamp") modulePath := android.PathForModuleSrc(ctx).String() var implicits android.Paths implicits = append(implicits, apiFiles...) apiPreamble := android.PathForSource(ctx, "system/tools/aidl/build/api_preamble.txt") implicits = append(implicits, apiPreamble) ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlFreezeApiRule, Description: "Freezing AIDL API of " + m.properties.BaseName + " as version " + version, Implicits: implicits, Output: timestampFile, Args: map[string]string{ "to": filepath.Join(modulePath, m.apiDir(), version), "name": m.properties.BaseName, "version": version, "bp": android.PathForModuleSrc(ctx, "Android.bp").String(), "apiPreamble": apiPreamble.String(), }, }) return timestampFile } func (m *aidlApi) checkCompatibility(ctx android.ModuleContext, oldApiDir android.Path, oldApiFiles android.Paths, newApiDir android.Path, newApiFiles android.Paths) android.WritablePath { newVersion := newApiDir.Base() timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp") messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_compatibility.txt") var implicits android.Paths implicits = append(implicits, oldApiFiles...) implicits = append(implicits, newApiFiles...) implicits = append(implicits, messageFile) ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlCheckApiRule, Implicits: implicits, Output: timestampFile, Args: map[string]string{ "old": oldApiDir.String(), "new": newApiDir.String(), "messageFile": messageFile.String(), }, }) return timestampFile } func (m *aidlApi) checkEquality(ctx android.ModuleContext, oldApiDir android.Path, oldApiFiles android.Paths, newApiDir android.Path, newApiFiles android.Paths) android.WritablePath { newVersion := newApiDir.Base() timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp") messageFile := android.PathForSource(ctx, "system/tools/aidl/build/message_check_equality.txt") var implicits android.Paths implicits = append(implicits, oldApiFiles...) implicits = append(implicits, newApiFiles...) implicits = append(implicits, messageFile) ctx.ModuleBuild(pctx, android.ModuleBuildParams{ Rule: aidlDiffApiRule, Implicits: implicits, Output: timestampFile, Args: map[string]string{ "old": oldApiDir.String(), "new": newApiDir.String(), "messageFile": messageFile.String(), }, }) return timestampFile } func (m *aidlApi) GenerateAndroidBuildActions(ctx android.ModuleContext) { currentVersion := m.validateCurrentVersion(ctx) if ctx.Failed() { return } currentDumpDir, currentApiFiles := m.createApiDumpFromSource(ctx) m.freezeApiTimestamp = m.freezeApiDumpAsVersion(ctx, currentDumpDir, currentApiFiles.Paths(), currentVersion) apiDirs := make(map[string]android.Path) apiFiles := make(map[string]android.Paths) for _, ver := range m.properties.Versions { apiDir := android.PathForModuleSrc(ctx, m.apiDir(), ver) apiDirs[ver] = apiDir apiFiles[ver] = ctx.Glob(filepath.Join(apiDir.String(), "**/*.aidl"), nil) } apiDirs[currentVersion] = currentDumpDir apiFiles[currentVersion] = currentApiFiles.Paths() // Check that version X is backward compatible with version X-1 for i, newVersion := range m.properties.Versions { if i != 0 { oldVersion := m.properties.Versions[i-1] checkApiTimestamp := m.checkCompatibility(ctx, apiDirs[oldVersion], apiFiles[oldVersion], apiDirs[newVersion], apiFiles[newVersion]) m.checkApiTimestamps = append(m.checkApiTimestamps, checkApiTimestamp) } } // ... and that the currentVersion (ToT) is backwards compatible with or // equal to the latest frozen version if len(m.properties.Versions) >= 1 { latestVersion := m.properties.Versions[len(m.properties.Versions)-1] var checkApiTimestamp android.WritablePath if ctx.Config().DefaultAppTargetSdkInt() != android.FutureApiLevel { // If API is frozen, don't allow any change to the API checkApiTimestamp = m.checkEquality(ctx, apiDirs[latestVersion], apiFiles[latestVersion], apiDirs[currentVersion], apiFiles[currentVersion]) } else { // If not, allow backwards compatible changes to the API checkApiTimestamp = m.checkCompatibility(ctx, apiDirs[latestVersion], apiFiles[latestVersion], apiDirs[currentVersion], apiFiles[currentVersion]) } m.checkApiTimestamps = append(m.checkApiTimestamps, checkApiTimestamp) } } func (m *aidlApi) AndroidMk() android.AndroidMkData { return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { android.WriteAndroidMkData(w, data) targetName := m.properties.BaseName + "-freeze-api" fmt.Fprintln(w, ".PHONY:", targetName) fmt.Fprintln(w, targetName+":", m.freezeApiTimestamp.String()) }, } } func (m *aidlApi) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), nil, wrap("", m.properties.Imports, aidlInterfaceSuffix)...) } func aidlApiFactory() android.Module { m := &aidlApi{} m.AddProperties(&m.properties) android.InitAndroidModule(m) return m } type aidlInterfaceProperties struct { // Vndk properties for interface library only. cc.VndkProperties // Whether the library can be installed on the vendor image. Vendor_available *bool // Top level directories for includes. // TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl Include_dirs []string // Relative path for includes. By default assumes AIDL path is relative to current directory. // TODO(b/111117220): automatically compute by letting AIDL parse multiple files simultaneously Local_include_dir string // The owner of the module Owner *string // List of .aidl files which compose this interface. These may be globbed. Srcs []string Imports []string // Used by gen dependency to fill out aidl include path Full_import_paths []string `blueprint:"mutated"` // Directory where API dumps are. Default is "api". Api_dir *string // Previous API versions that are now frozen. The version that is last in // the list is considered as the most recent version. Versions []string Backend struct { Java struct { // Whether to generate Java code using Java binder APIs // Default: true Enabled *bool // Set to the version of the sdk to compile against // Default: system_current Sdk_version *string } Cpp struct { // Whether to generate C++ code using C++ binder APIs // Default: true Enabled *bool // Whether to generate additional code for gathering information // about the transactions // Default: false Gen_log *bool } Ndk struct { // Whether to generate C++ code using NDK binder APIs // Default: true Enabled *bool // Whether to generate additional code for gathering information // about the transactions // Default: false Gen_log *bool } } } type aidlInterface struct { android.ModuleBase properties aidlInterfaceProperties // Unglobbed sources rawSrcs []string } func (i *aidlInterface) shouldGenerateJavaBackend() bool { // explicitly true if not specified to give early warning to devs return i.properties.Backend.Java.Enabled == nil || *i.properties.Backend.Java.Enabled } func (i *aidlInterface) shouldGenerateCppBackend() bool { // explicitly true if not specified to give early warning to devs return i.properties.Backend.Cpp.Enabled == nil || *i.properties.Backend.Cpp.Enabled } func (i *aidlInterface) shouldGenerateNdkBackend() bool { // explicitly true if not specified to give early warning to devs return i.properties.Backend.Ndk.Enabled == nil || *i.properties.Backend.Ndk.Enabled } func (i *aidlInterface) checkAndUpdateSources(mctx android.LoadHookContext) { prefix := mctx.ModuleDir() for _, source := range i.properties.Srcs { if pathtools.IsGlob(source) { globbedSrcFiles, err := mctx.GlobWithDeps(filepath.Join(prefix, source), nil) if err != nil { mctx.ModuleErrorf("glob: %s", err.Error()) } for _, globbedSrc := range globbedSrcFiles { relativeGlobbedSrc, err := filepath.Rel(prefix, globbedSrc) if err != nil { panic(err) } i.rawSrcs = append(i.rawSrcs, relativeGlobbedSrc) } } else { i.rawSrcs = append(i.rawSrcs, source) } } if len(i.rawSrcs) == 0 { mctx.PropertyErrorf("srcs", "No sources provided.") } for _, source := range i.rawSrcs { if !strings.HasSuffix(source, ".aidl") { mctx.PropertyErrorf("srcs", "Source must be a .aidl file: "+source) continue } relativePath, err := filepath.Rel(i.properties.Local_include_dir, source) if err != nil || !isRelativePath(relativePath) { mctx.PropertyErrorf("srcs", "Source is not in local_include_dir: "+source) } } } func (i *aidlInterface) checkImports(mctx android.LoadHookContext) { for _, anImport := range i.properties.Imports { other := lookupInterface(anImport) if other == nil { mctx.PropertyErrorf("imports", "Import does not exist: "+anImport) } if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() { mctx.PropertyErrorf("backend.cpp.enabled", "C++ backend not enabled in the imported AIDL interface %q", anImport) } if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() { mctx.PropertyErrorf("backend.ndk.enabled", "NDK backend not enabled in the imported AIDL interface %q", anImport) } } } func (i *aidlInterface) versionedName(version string) string { name := i.ModuleBase.Name() if version != futureVersion && version != "" { name = name + "-V" + version } return name } func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, base string) { if version == futureVersion || version == "" { return i.rawSrcs, i.properties.Local_include_dir } else { var apiDir string if i.properties.Api_dir != nil { apiDir = *(i.properties.Api_dir) } else { apiDir = "api" } base = filepath.Join(apiDir, version) full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), base, "**/*.aidl"), nil) if err != nil { panic(err) } for _, path := range full_paths { // Here, we need path local to the module srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/")) } return srcs, base } } func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) { if !isRelativePath(i.properties.Local_include_dir) { mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir) } var importPaths []string importPaths = append(importPaths, filepath.Join(mctx.ModuleDir(), i.properties.Local_include_dir)) importPaths = append(importPaths, i.properties.Include_dirs...) i.properties.Full_import_paths = importPaths i.checkAndUpdateSources(mctx) i.checkImports(mctx) if mctx.Failed() { return } var libs []string currentVersion := "" if len(i.properties.Versions) > 0 { currentVersion = futureVersion } if i.shouldGenerateCppBackend() { libs = append(libs, addCppLibrary(mctx, i, currentVersion, langCpp)) for _, version := range i.properties.Versions { addCppLibrary(mctx, i, version, langCpp) } } if i.shouldGenerateNdkBackend() { // TODO(b/119771576): inherit properties and export 'is vendor' computation from cc.go if !proptools.Bool(i.properties.Vendor_available) { libs = append(libs, addCppLibrary(mctx, i, currentVersion, langNdk)) for _, version := range i.properties.Versions { addCppLibrary(mctx, i, version, langNdk) } } // TODO(b/121157555): combine with '-ndk' variant libs = append(libs, addCppLibrary(mctx, i, currentVersion, langNdkPlatform)) for _, version := range i.properties.Versions { addCppLibrary(mctx, i, version, langNdkPlatform) } } libs = append(libs, addJavaLibrary(mctx, i, currentVersion)) for _, version := range i.properties.Versions { addJavaLibrary(mctx, i, version) } addApiModule(mctx, i) // Reserve this module name for future use mctx.CreateModule(android.ModuleFactoryAdaptor(phony.PhonyFactory), &phonyProperties{ Name: proptools.StringPtr(i.ModuleBase.Name()), Required: libs, }) } func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string) string { cppSourceGen := i.versionedName(version) + "-" + lang + "-source" cppModuleGen := i.versionedName(version) + "-" + lang srcs, base := i.srcsForVersion(mctx, version) if len(srcs) == 0 { // This can happen when the version is about to be frozen; the version // directory is created but API dump hasn't been copied there. // Don't create a library for the yet-to-be-frozen version. return "" } genLog := false if lang == langCpp { genLog = proptools.Bool(i.properties.Backend.Cpp.Gen_log) } else if lang == langNdk || lang == langNdkPlatform { genLog = proptools.Bool(i.properties.Backend.Ndk.Gen_log) } mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{ Name: proptools.StringPtr(cppSourceGen), }, &aidlGenProperties{ Srcs: srcs, AidlRoot: base, Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), Lang: lang, BaseName: i.ModuleBase.Name(), GenLog: genLog, Version: version, }) importExportDependencies := wrap("", i.properties.Imports, "-"+lang) var libJSONCppDependency []string var staticLibDependency []string var sdkVersion *string var stl *string var cpp_std *string if lang == langCpp { importExportDependencies = append(importExportDependencies, "libbinder", "libutils") if genLog { libJSONCppDependency = []string{"libjsoncpp"} } sdkVersion = nil stl = nil cpp_std = nil } else if lang == langNdk { importExportDependencies = append(importExportDependencies, "libbinder_ndk") if genLog { staticLibDependency = []string{"libjsoncpp_ndk"} } sdkVersion = proptools.StringPtr("current") stl = proptools.StringPtr("c++_shared") } else if lang == langNdkPlatform { importExportDependencies = append(importExportDependencies, "libbinder_ndk") if genLog { libJSONCppDependency = []string{"libjsoncpp"} } } else { panic("Unrecognized language: " + lang) } mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{ Name: proptools.StringPtr(cppModuleGen), Owner: i.properties.Owner, Vendor_available: i.properties.Vendor_available, Defaults: []string{"aidl-cpp-module-defaults"}, Generated_sources: []string{cppSourceGen}, Generated_headers: []string{cppSourceGen}, Export_generated_headers: []string{cppSourceGen}, Static: staticLib{Whole_static_libs: libJSONCppDependency}, Shared: sharedLib{Shared_libs: libJSONCppDependency, Export_shared_lib_headers: libJSONCppDependency}, Static_libs: staticLibDependency, Shared_libs: importExportDependencies, Export_shared_lib_headers: importExportDependencies, Sdk_version: sdkVersion, Stl: stl, Cpp_std: cpp_std, Cflags: []string{"-Wextra", "-Wall", "-Werror"}, }, &i.properties.VndkProperties) return cppModuleGen } func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, version string) string { javaSourceGen := i.versionedName(version) + "-java-source" javaModuleGen := i.versionedName(version) + "-java" srcs, base := i.srcsForVersion(mctx, version) if len(srcs) == 0 { // This can happen when the version is about to be frozen; the version // directory is created but API dump hasn't been copied there. // Don't create a library for the yet-to-be-frozen version. return "" } sdkVersion := proptools.StringDefault(i.properties.Backend.Java.Sdk_version, "system_current") mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{ Name: proptools.StringPtr(javaSourceGen), }, &aidlGenProperties{ Srcs: srcs, AidlRoot: base, Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), Lang: langJava, BaseName: i.ModuleBase.Name(), Version: version, }) mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProperties{ Name: proptools.StringPtr(javaModuleGen), Owner: i.properties.Owner, Installable: proptools.BoolPtr(true), Defaults: []string{"aidl-java-module-defaults"}, No_framework_libs: proptools.BoolPtr(true), Sdk_version: proptools.StringPtr(sdkVersion), Static_libs: wrap("", i.properties.Imports, "-java"), Srcs: []string{":" + javaSourceGen}, }) return javaModuleGen } func addApiModule(mctx android.LoadHookContext, i *aidlInterface) string { apiModule := i.ModuleBase.Name() + aidlApiSuffix mctx.CreateModule(android.ModuleFactoryAdaptor(aidlApiFactory), &nameProperties{ Name: proptools.StringPtr(apiModule), }, &aidlApiProperties{ BaseName: i.ModuleBase.Name(), Inputs: i.rawSrcs, Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), Api_dir: i.properties.Api_dir, AidlRoot: i.properties.Local_include_dir, Versions: i.properties.Versions, }) return apiModule } func (i *aidlInterface) Name() string { return i.ModuleBase.Name() + aidlInterfaceSuffix } func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) { } func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) { } var aidlInterfaceMutex sync.Mutex var aidlInterfaces []*aidlInterface func aidlInterfaceFactory() android.Module { i := &aidlInterface{} i.AddProperties(&i.properties) android.InitAndroidModule(i) android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) }) aidlInterfaceMutex.Lock() aidlInterfaces = append(aidlInterfaces, i) aidlInterfaceMutex.Unlock() return i } func lookupInterface(name string) *aidlInterface { for _, i := range aidlInterfaces { if i.ModuleBase.Name() == name { return i } } return nil } type aidlMappingProperties struct { // Source file of this prebuilt. Srcs []string `android:"arch_variant"` Output string } type aidlMapping struct { android.ModuleBase properties aidlMappingProperties outputFilePath android.WritablePath } func (s *aidlMapping) DepsMutator(ctx android.BottomUpMutatorContext) { android.ExtractSourcesDeps(ctx, s.properties.Srcs) } func addItemsToMap(dest map[string]bool, src []string) { for _, item := range src { dest[item] = true } } func (s *aidlMapping) GenerateAndroidBuildActions(ctx android.ModuleContext) { var srcs android.Paths var all_import_dirs map[string]bool = make(map[string]bool) ctx.VisitDirectDeps(func(module android.Module) { for _, property := range module.GetProperties() { if jproperty, ok := property.(*java.CompilerProperties); ok { for _, src := range jproperty.Srcs { if strings.HasSuffix(src, ".aidl") { full_path := android.PathForModuleSrc(ctx, src) srcs = append(srcs, full_path) all_import_dirs[filepath.Dir(full_path.String())] = true } else if pathtools.IsGlob(src) { globbedSrcFiles, err := ctx.GlobWithDeps(src, nil) if err == nil { for _, globbedSrc := range globbedSrcFiles { full_path := android.PathForModuleSrc(ctx, globbedSrc) all_import_dirs[full_path.String()] = true } } } } } else if jproperty, ok := property.(*java.CompilerDeviceProperties); ok { addItemsToMap(all_import_dirs, jproperty.Aidl.Include_dirs) for _, include_dir := range jproperty.Aidl.Export_include_dirs { var full_path = filepath.Join(ctx.ModuleDir(), include_dir) all_import_dirs[full_path] = true } for _, include_dir := range jproperty.Aidl.Local_include_dirs { var full_path = filepath.Join(ctx.ModuleSubDir(), include_dir) all_import_dirs[full_path] = true } } } }) var import_dirs []string for dir := range all_import_dirs { import_dirs = append(import_dirs, dir) } imports := strings.Join(wrap("-I", import_dirs, ""), " ") s.outputFilePath = android.PathForModuleOut(ctx, s.properties.Output) outDir := android.PathForModuleGen(ctx) ctx.Build(pctx, android.BuildParams{ Rule: aidlDumpMappingsRule, Inputs: srcs, Output: s.outputFilePath, Args: map[string]string{ "imports": imports, "outDir": outDir.String(), }, }) } func InitAidlMappingModule(s *aidlMapping) { s.AddProperties(&s.properties) } func aidlMappingFactory() android.Module { module := &aidlMapping{} InitAidlMappingModule(module) android.InitAndroidModule(module) return module } func (m *aidlMapping) AndroidMk() android.AndroidMkData { return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { android.WriteAndroidMkData(w, data) targetName := m.Name() fmt.Fprintln(w, ".PHONY:", targetName) fmt.Fprintln(w, targetName+":", m.outputFilePath.String()) }, } } build/aidl_to_jni.py0100755 0000000 0000000 00000005443 13755771705 013563 0ustar000000000 0000000 #!/usr/bin/env python3 # # Copyright (C) 2019 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import sys DEFAULT_TYPES_TO_JNI = { "boolean": "Z", "byte": "B", "char": "C", "short": "S", "int": "I", "long": "J", "float": "F", "double": "D", "void": "V", "String": "Ljava/lang/String;" } class AIDLMalformedSignatureException(Exception): """Line containing AIDL signature is invalid""" def convert_type(aidl_type): if aidl_type.endswith("[]"): return "[" + convert_type(aidl_type[:-2]) if aidl_type in DEFAULT_TYPES_TO_JNI: return DEFAULT_TYPES_TO_JNI[aidl_type] elif aidl_type.startswith("List<") | aidl_type.startswith("java.util.List<"): return "Ljava/util/List;" else: return "L" + aidl_type.replace(".", "/") + ";" def convert_method(aidl_signature): aidl_signature = aidl_signature.split("|") if len(aidl_signature) != 4: raise AIDLMalformedSignatureException() class_name, method_name, args, return_type = aidl_signature # Filter out empty arguments since there will be trailing commas args = [x for x in args.split(",") if x] jni_signature = convert_type(class_name) jni_signature += "->" jni_signature += method_name jni_signature += "(" params = [convert_type(x) for x in args] jni_signature += "".join(params) jni_signature += ")" jni_signature += convert_type(return_type) return jni_signature def main(argv): if len(argv) != 3: print("Usage: %s " % argv[0]) return -1 aidl_mappings, jni_signature_mappings = argv[1:] line_index = 0 skip_line = False with open(aidl_mappings) as input_file: with open(jni_signature_mappings, "w") as output_file: for line in input_file: if skip_line: skip_line = False elif line_index % 2 == 1: output_file.write(line) else: try: stripped_line = line.strip() output_file.write(convert_method(line.strip())) output_file.write("\n") except AIDLMalformedSignatureException: print("Malformed signature %s . Skipping..." % stripped_line) # The next line contains the location, need to skip it skip_line = True line_index += 1 if __name__ == "__main__": sys.exit(main(sys.argv)) build/api/0040755 0000000 0000000 00000000000 13755771705 011501 5ustar000000000 0000000 build/api/1/0040755 0000000 0000000 00000000000 13755771705 011641 5ustar000000000 0000000 build/api/1/test_package/0040755 0000000 0000000 00000000000 13755771705 014273 5ustar000000000 0000000 build/api/1/test_package/IBaz.aidl0100644 0000000 0000000 00000000150 13755771705 015744 0ustar000000000 0000000 package test_package; interface IBaz { oneway void CanYouDealWithThisBar(in some_package.IBar bar); } build/api/2/0040755 0000000 0000000 00000000000 13755771705 011642 5ustar000000000 0000000 build/api/2/test_package/0040755 0000000 0000000 00000000000 13755771705 014274 5ustar000000000 0000000 build/api/2/test_package/IBaz.aidl0100644 0000000 0000000 00000000413 13755771705 015747 0ustar000000000 0000000 package test_package; interface IBaz { oneway void CanYouDealWithThisBar(in some_package.IBar bar); void MethodAddedInVersion2(); ParcelFileDescriptor readPFD(); void writePFD(in ParcelFileDescriptor fd); void readWritePFD(inout ParcelFileDescriptor fd); } build/api/test-piece-1/0040755 0000000 0000000 00000000000 13755771705 013701 5ustar000000000 0000000 build/api/test-piece-1/1/0040755 0000000 0000000 00000000000 13755771705 014041 5ustar000000000 0000000 build/api/test-piece-1/1/some_package/0040755 0000000 0000000 00000000000 13755771705 016457 5ustar000000000 0000000 build/api/test-piece-1/1/some_package/IFoo.aidl0100644 0000000 0000000 00000000275 13755771705 020147 0ustar000000000 0000000 package some_package; interface IFoo { void CanYouDealWithThisThing(inout some_package.Thing parcel); void CanYouDealWithThisSubThing(inout some_package.sub_package.SubThing parcel); } build/api/test-piece-1/1/some_package/Thing.aidl0100644 0000000 0000000 00000000075 13755771705 020362 0ustar000000000 0000000 package some_package; parcelable Thing { int a; int b; } build/api/test-piece-1/1/some_package/sub_package/0040755 0000000 0000000 00000000000 13755771705 020723 5ustar000000000 0000000 build/api/test-piece-1/1/some_package/sub_package/IFoo.aidl0100644 0000000 0000000 00000000311 13755771705 022402 0ustar000000000 0000000 package some_package.sub_package; interface IFoo { void CanYouDealWithThisThing(inout some_package.Thing parcel); void CanYouDealWithThisSubThing(inout some_package.sub_package.SubThing parcel); } build/api/test-piece-1/1/some_package/sub_package/SubThing.aidl0100644 0000000 0000000 00000000114 13755771705 023272 0ustar000000000 0000000 package some_package.sub_package; parcelable SubThing { int a; int b; } build/api/test-piece-2/0040755 0000000 0000000 00000000000 13755771705 013702 5ustar000000000 0000000 build/api/test-piece-2/1/0040755 0000000 0000000 00000000000 13755771705 014042 5ustar000000000 0000000 build/api/test-piece-2/1/INoPackage.aidl0100644 0000000 0000000 00000000121 13755771705 016625 0ustar000000000 0000000 interface INoPackage { void CanYouDealWithThisBar(in some_package.IBar bar); } build/api/test-piece-2/1/some_package/0040755 0000000 0000000 00000000000 13755771705 016460 5ustar000000000 0000000 build/api/test-piece-2/1/some_package/IBar.aidl0100644 0000000 0000000 00000000150 13755771705 020121 0ustar000000000 0000000 package some_package; interface IBar { oneway void CanYouDealWithThisFoo(in some_package.IFoo foo); } build/api/test-piece-3/0040755 0000000 0000000 00000000000 13755771705 013703 5ustar000000000 0000000 build/api/test-piece-3/1/0040755 0000000 0000000 00000000000 13755771705 014043 5ustar000000000 0000000 build/api/test-piece-3/1/other_package/0040755 0000000 0000000 00000000000 13755771705 016637 5ustar000000000 0000000 build/api/test-piece-3/1/other_package/IBaz.aidl0100644 0000000 0000000 00000000142 13755771705 020311 0ustar000000000 0000000 package other_package; interface IBaz { void CanYouDealWithThisBar(in some_package.IBar bar); } build/api/test-piece-4/0040755 0000000 0000000 00000000000 13755771705 013704 5ustar000000000 0000000 build/api/test-piece-4/1/0040755 0000000 0000000 00000000000 13755771705 014044 5ustar000000000 0000000 build/api/test-piece-4/1/another_package/0040755 0000000 0000000 00000000000 13755771705 017157 5ustar000000000 0000000 build/api/test-piece-4/1/another_package/IFaz.aidl0100644 0000000 0000000 00000000144 13755771705 020637 0ustar000000000 0000000 package another_package; interface IFaz { void CanYouDealWithThisFoo(in some_package.IFoo foo); } build/api_preamble.txt0100644 0000000 0000000 00000002034 13755771705 014105 0ustar000000000 0000000 /////////////////////////////////////////////////////////////////////////////// // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // /////////////////////////////////////////////////////////////////////////////// // This file is a frozen snapshot of an AIDL interface (or parcelable). Do not // try to edit this file. It looks like you are doing that because you have // modified an AIDL interface in a backward-incompatible way, e.g., deleting a // function from an interface or a field from a parcelable and it broke the // build. That breakage is intended. // // You must not make a backward incompatible changes to the AIDL files built // with the aidl_interface module type with versions property set. The module // type is used to build AIDL files in a way that they can be used across // independently updatable components of the system. If a device is shipped // with such a backward incompatible change, it has a high risk of breaking // later when a module using the interface is updated, e.g., Mainline modules. build/message_check_compatibility.txt0100644 0000000 0000000 00000001044 13755771705 017177 0ustar000000000 0000000 ############################################################################### # ERROR: Backward incompatible change detected on AIDL API # ############################################################################### Above AIDL file(s) has changed in a backward-incompatible way, e.g. removing a method from an interface or a field from a parcelable. If a device is shipped with this change by ignoring this message, it has a high risk of breaking later when a module using the interface is updated, e.g., Maineline modules. build/message_check_equality.txt0100644 0000000 0000000 00000001027 13755771705 016164 0ustar000000000 0000000 ############################################################################### # ERROR: AIDL API change detected on a released platform # ############################################################################### Above AIDL file(s) has changed and this is NEVER allowed on a release platform (i.e., PLATFORM_VERSION_CODENAME is REL). If a device is shipped with this change by ignoring this message, it has a high risk of breaking later when a module using the interface is updated, e.g., Maineline modules. build/properties.go0100644 0000000 0000000 00000003315 13755771705 013452 0ustar000000000 0000000 // Copyright (C) 2017 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package aidl type nameProperties struct { Name *string } type staticLib struct { Whole_static_libs []string } type sharedLib struct { Shared_libs []string Export_shared_lib_headers []string } type ccProperties struct { Name *string Owner *string Defaults []string Vendor_available *bool Generated_sources []string Generated_headers []string Shared sharedLib Static staticLib Static_libs []string Shared_libs []string Export_shared_lib_headers []string Export_generated_headers []string Sdk_version *string Stl *string Cpp_std *string Cflags []string } type javaProperties struct { Name *string Owner *string Defaults []string Installable *bool No_framework_libs *bool Sdk_version *string Srcs []string Static_libs []string } type phonyProperties struct { Name *string Required []string } build/test_package/0040755 0000000 0000000 00000000000 13755771705 013362 5ustar000000000 0000000 build/test_package/IBaz.aidl0100644 0000000 0000000 00000002244 13755771705 015041 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package test_package; import some_package.IBar; interface IBaz { oneway void CanYouDealWithThisBar(in IBar bar); void MethodAddedInVersion2(); ParcelFileDescriptor readPFD(); void writePFD(in ParcelFileDescriptor fd); void readWritePFD(inout ParcelFileDescriptor fd); // TODO(b/112664205) uncomment these when we have the support for array type in // the ndk backend //ParcelFileDescriptor[] readPFDArray(); //void writePFDArray(in ParcelFileDescriptor[] fds); //void readWritePFDArray(inout ParcelFileDescriptor[] fds); } build/tests_1/0040755 0000000 0000000 00000000000 13755771705 012312 5ustar000000000 0000000 build/tests_1/INoPackage.aidl0100644 0000000 0000000 00000001316 13755771705 015104 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import some_package.IBar; interface INoPackage { void CanYouDealWithThisBar(in IBar bar); } build/tests_1/other_package/0040755 0000000 0000000 00000000000 13755771705 015106 5ustar000000000 0000000 build/tests_1/other_package/IBaz.aidl0100644 0000000 0000000 00000001340 13755771705 016561 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package other_package; import some_package.IBar; interface IBaz { void CanYouDealWithThisBar(in IBar bar); } build/tests_1/some_package/0040755 0000000 0000000 00000000000 13755771705 014730 5ustar000000000 0000000 build/tests_1/some_package/IBar.aidl0100644 0000000 0000000 00000001346 13755771705 016401 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package some_package; import some_package.IFoo; oneway interface IBar { void CanYouDealWithThisFoo(in IFoo foo); } build/tests_1/some_package/IFoo.aidl0100644 0000000 0000000 00000001517 13755771705 016420 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package some_package; import some_package.Thing; import some_package.sub_package.SubThing; interface IFoo { void CanYouDealWithThisThing(inout Thing parcel); void CanYouDealWithThisSubThing(inout SubThing parcel); } build/tests_1/some_package/Thing.aidl0100644 0000000 0000000 00000001257 13755771705 016636 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package some_package; parcelable Thing { int a; int b; } build/tests_1/some_package/sub_package/0040755 0000000 0000000 00000000000 13755771705 017174 5ustar000000000 0000000 build/tests_1/some_package/sub_package/IFoo.aidl0100644 0000000 0000000 00000001533 13755771705 020662 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package some_package.sub_package; import some_package.Thing; import some_package.sub_package.SubThing; interface IFoo { void CanYouDealWithThisThing(inout Thing parcel); void CanYouDealWithThisSubThing(inout SubThing parcel); } build/tests_1/some_package/sub_package/SubThing.aidl0100644 0000000 0000000 00000001276 13755771705 021555 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package some_package.sub_package; parcelable SubThing { int a; int b; } build/tests_2/0040755 0000000 0000000 00000000000 13755771705 012313 5ustar000000000 0000000 build/tests_2/another_package/0040755 0000000 0000000 00000000000 13755771705 015426 5ustar000000000 0000000 build/tests_2/another_package/IFaz.aidl0100644 0000000 0000000 00000001342 13755771705 017107 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package another_package; import some_package.IFoo; interface IFaz { void CanYouDealWithThisFoo(in IFoo foo); } code_writer.cpp0100644 0000000 0000000 00000007337 13755771705 012652 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 #include #include #include #include namespace android { namespace aidl { CodeWriter::CodeWriter(std::unique_ptr ostream) : ostream_(std::move(ostream)) {} std::string CodeWriter::ApplyIndent(const std::string& str) { std::string output; if (!start_of_line_ || str == "\n") { output = str; } else { output = std::string(indent_level_ * 2, ' ') + str; } start_of_line_ = !output.empty() && output.back() == '\n'; return output; } bool CodeWriter::Write(const char* format, ...) { va_list ap; va_start(ap, format); std::string formatted; android::base::StringAppendV(&formatted, format, ap); va_end(ap); // extract lines. empty line is preserved. std::vector lines; size_t pos = 0; while (pos < formatted.size()) { size_t line_end = formatted.find('\n', pos); if (line_end != std::string::npos) { lines.push_back(formatted.substr(pos, (line_end - pos) + 1)); pos = line_end + 1; } else { lines.push_back(formatted.substr(pos)); break; } } std::string indented; for (const auto& line : lines) { indented.append(ApplyIndent(line)); } (*ostream_) << indented; return !ostream_->fail(); } void CodeWriter::Indent() { indent_level_++; } void CodeWriter::Dedent() { CHECK(indent_level_ > 0); indent_level_--; } bool CodeWriter::Close() { if (ostream_.get()->rdbuf() != std::cout.rdbuf()) { // if the steam is for file (not stdout), do the close. static_cast(ostream_.get())->close(); return !ostream_->fail(); } return true; } CodeWriter& CodeWriter::operator<<(const char* s) { Write(s); return *this; } CodeWriter& CodeWriter::operator<<(const std::string& str) { Write(str.c_str()); return *this; } CodeWriterPtr CodeWriter::ForFile(const std::string& filename) { std::unique_ptr stream; if (filename == "-") { stream = std::unique_ptr(new std::ostream(std::cout.rdbuf())); } else { stream = std::unique_ptr( new std::fstream(filename, std::fstream::out | std::fstream::binary)); } return CodeWriterPtr(new CodeWriter(std::move(stream))); } CodeWriterPtr CodeWriter::ForString(std::string* buf) { // This class is defined inside this static function of CodeWriter // in order to have access to private constructor and private member // ostream_. class StringCodeWriter : public CodeWriter { public: StringCodeWriter(std::string* buf) : CodeWriter(std::unique_ptr(new std::stringstream())), buf_(buf) {} ~StringCodeWriter() override { Close(); } bool Close() override { // extract whats written to the stringstream to the external buffer. // we are sure that ostream_ is indeed stringstream. *buf_ = static_cast(ostream_.get())->str(); return true; } private: std::string* buf_; }; return CodeWriterPtr(new StringCodeWriter(buf)); } } // namespace aidl } // namespace android code_writer.h0100644 0000000 0000000 00000003541 13755771705 012310 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. */ #pragma once #include #include #include #include #include namespace android { namespace aidl { class CodeWriter; using CodeWriterPtr = std::unique_ptr; class CodeWriter { public: // Get a CodeWriter that writes to a file. When filename is "-", // it is written to stdout. static CodeWriterPtr ForFile(const std::string& filename); // Get a CodeWriter that writes to a string buffer. // The buffer gets updated only after Close() is called or the CodeWriter // is deleted -- much like a real file. static CodeWriterPtr ForString(std::string* buf); // Write a formatted string to this writer in the usual printf sense. // Returns false on error. virtual bool Write(const char* format, ...); void Indent(); void Dedent(); virtual bool Close(); virtual ~CodeWriter() = default; CodeWriter() = default; CodeWriter& operator<<(const char* s); CodeWriter& operator<<(const std::string& str); private: CodeWriter(std::unique_ptr ostream); std::string ApplyIndent(const std::string& str); const std::unique_ptr ostream_; int indent_level_ {0}; bool start_of_line_ {true}; }; } // namespace aidl } // namespace android code_writer_unittest.cpp0100644 0000000 0000000 00000002431 13755771705 014577 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "code_writer.h" #include #include using android::aidl::CodeWriter; using std::string; using std::unique_ptr; namespace android { namespace aidl { TEST(CodeWriterTest, AppendOperator) { string str; CodeWriterPtr ptr = CodeWriter::ForString(&str); CodeWriter& writer = *ptr; writer << "Write this"; writer.Close(); EXPECT_EQ(str, "Write this"); } TEST(CodeWriterTest, AppendOperatorCascade) { string str; CodeWriterPtr ptr = CodeWriter::ForString(&str); CodeWriter& writer = *ptr; writer << "Write this " << "and that"; writer.Close(); EXPECT_EQ(str, "Write this and that"); } } // namespace aidl } // namespace android docs/0040755 0000000 0000000 00000000000 13755771705 010561 5ustar000000000 0000000 docs/aidl-cpp.md0100644 0000000 0000000 00000027040 13755771705 012574 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 13755771705 013115 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 13755771705 013746 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_aidl_mappings.cpp0100644 0000000 0000000 00000003207 13755771705 015015 0ustar000000000 0000000 /* * Copyright (C) 2019, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "generate_aidl_mappings.h" #include "type_java.h" #include namespace android { namespace aidl { namespace mappings { std::string dump_location(const AidlNode& method) { return method.PrintLocation(); } SignatureMap generate_mappings(const AidlDefinedType* defined_type) { const AidlInterface* interface = defined_type->AsInterface(); SignatureMap mappings; if (interface == nullptr) { return mappings; } for (const auto& method : interface->GetMethods()) { if (method->IsUserDefined()) { std::stringstream signature; signature << interface->GetCanonicalName() << "|"; signature << method->GetName() << "|"; for (const auto& arg : method->GetArguments()) { signature << arg->GetType().ToString() << ","; } signature << "|"; signature << method->GetType().GetLanguageType()->JavaType(); mappings[signature.str()] = dump_location(*method); } } return mappings; } } // namespace mappings } // namespace aidl } // namespace android generate_aidl_mappings.h0100644 0000000 0000000 00000001705 13755771705 014463 0ustar000000000 0000000 /* * Copyright (C) 2019, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "aidl_language.h" namespace android { namespace aidl { namespace mappings { using SignatureMap = std::unordered_map; SignatureMap generate_mappings(const AidlDefinedType* iface); } // namespace mappings } // namespace aidl } // namespace android generate_cpp.cpp0100644 0000000 0000000 00000142367 13755771705 013003 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 "aidl.h" #include #include #include #include #include #include #include #include "aidl_language.h" #include "aidl_to_cpp.h" #include "ast_cpp.h" #include "code_writer.h" #include "logging.h" #include "os.h" using android::base::Join; using android::base::StringPrintf; using std::set; using std::string; using std::unique_ptr; using std::vector; 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 kTraceVarName[] = "_aidl_trace"; 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 kTraceHeader[] = "utils/Trace.h"; const char kStrongPointerHeader[] = "utils/StrongPointer.h"; const char kAndroidBaseMacrosHeader[] = "android-base/macros.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); } ArgList BuildArgList(const TypeNamespace& types, const AidlMethod& method, bool for_declaration, bool type_name_only = false) { // 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 + "&"; } } if (!type_name_only) { 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(), type_name_only ? "" : 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 BuildMetaMethodDecl(const AidlMethod& method, const TypeNamespace&, const Options& options, bool for_interface) { CHECK(!method.IsUserDefined()); if (method.GetName() == kGetInterfaceVersion && options.Version()) { std::ostringstream code; if (for_interface) { code << "virtual "; } code << "int32_t " << kGetInterfaceVersion << "()"; if (for_interface) { code << " = 0;\n"; } else { code << " override;\n"; } return unique_ptr(new LiteralDecl(code.str())); } return nullptr; } std::vector> NestInNamespaces(vector> decls, const vector& package) { auto it = package.crbegin(); // Iterate over the namespaces inner to outer for (; it != package.crend(); ++it) { vector> inner; inner.emplace_back(unique_ptr{new CppNamespace{*it, std::move(decls)}}); decls = std::move(inner); } return decls; } std::vector> NestInNamespaces(unique_ptr decl, const vector& package) { vector> decls; decls.push_back(std::move(decl)); return NestInNamespaces(std::move(decls), package); } bool DeclareLocalVariable(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 BuildHeaderGuard(const AidlDefinedType& defined_type, ClassNames header_type) { string class_name = ClassName(defined_type, header_type); for (size_t i = 1; i < class_name.size(); ++i) { if (isupper(class_name[i])) { class_name.insert(i, "_"); ++i; } } string ret = StringPrintf("AIDL_GENERATED_%s_%s_H_", defined_type.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 Options& options) { 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)); if (options.GenTraces()) { b->AddLiteral( StringPrintf("ScopedTrace %s(ATRACE_TAG_AIDL, \"%s::%s::cppClient\")", kTraceVarName, interface.GetName().c_str(), method.GetName().c_str())); } if (options.GenLog()) { b->AddLiteral(GenLogBeforeExecute(bp_name, method, false /* isServer */, false /* isNdk */), false /* no semicolon */); } // 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 = GetTransactionIdFor(method); vector args = {transaction_code, kDataVarName, StringPrintf("&%s", kReplyVarName)}; if (method.IsOneway()) { args.push_back("::android::IBinder::FLAG_ONEWAY"); } b->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall("remote()->transact", ArgList(args)))); // If the method is not implemented in the remote side, try to call the // default implementation, if provided. vector arg_names; for (const auto& a : method.GetArguments()) { arg_names.emplace_back(a->GetName()); } if (method.GetType().GetLanguageType() != types.VoidType()) { arg_names.emplace_back(kReturnVarName); } b->AddLiteral(StringPrintf("if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && " "%s::getDefaultImpl())) {\n" " return %s::getDefaultImpl()->%s(%s);\n" "}\n", i_name.c_str(), i_name.c_str(), method.GetName().c_str(), Join(arg_names, ", ").c_str()), false /* no semicolon */); b->AddStatement(GotoErrorOnBadStatus()); if (!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)); if (options.GenLog()) { b->AddLiteral(GenLogAfterExecute(bp_name, interface, method, kStatusVarName, kReturnVarName, false /* isServer */, false /* isNdk */), false /* no semicolon */); } b->AddLiteral(StringPrintf("return %s", kStatusVarName)); return unique_ptr(ret.release()); } unique_ptr DefineClientMetaTransaction(const TypeNamespace&, const AidlInterface& interface, const AidlMethod& method, const Options& options) { CHECK(!method.IsUserDefined()); if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) { const string iface = ClassName(interface, ClassNames::INTERFACE); const string proxy = ClassName(interface, ClassNames::CLIENT); // Note: race condition can happen here, but no locking is required // because 1) writing an interger is atomic and 2) this transaction // will always return the same value, i.e., competing threads will // give write the same value to cached_version_. std::ostringstream code; code << "int32_t " << proxy << "::" << kGetInterfaceVersion << "() {\n" << " if (cached_version_ == -1) {\n" << " ::android::Parcel data;\n" << " ::android::Parcel reply;\n" << " data.writeInterfaceToken(getInterfaceDescriptor());\n" << " ::android::status_t err = remote()->transact(" << GetTransactionIdFor(method) << ", data, &reply);\n" << " if (err == ::android::OK) {\n" << " ::android::binder::Status _aidl_status;\n" << " err = _aidl_status.readFromParcel(reply);\n" << " if (err == ::android::OK && _aidl_status.isOk()) {\n" << " cached_version_ = reply.readInt32();\n" << " }\n" << " }\n" << " }\n" << " return cached_version_;\n" << "}\n"; return unique_ptr(new LiteralDecl(code.str())); } return nullptr; } } // namespace unique_ptr BuildClientSource(const TypeNamespace& types, const AidlInterface& interface, const Options& options) { vector include_list = { HeaderFile(interface, ClassNames::CLIENT, false), kParcelHeader, kAndroidBaseMacrosHeader }; if (options.GenLog()) { include_list.emplace_back("chrono"); include_list.emplace_back("functional"); include_list.emplace_back("json/value.h"); } 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 + ")" }}}); if (options.GenLog()) { string code; ClassName(interface, ClassNames::CLIENT); CodeWriterPtr writer = CodeWriter::ForString(&code); (*writer) << "std::function " << ClassName(interface, ClassNames::CLIENT) << "::logFunc;\n"; writer->Close(); file_decls.push_back(unique_ptr(new LiteralDecl(code))); } // Clients define a method per transaction. for (const auto& method : interface.GetMethods()) { unique_ptr m; if (method->IsUserDefined()) { m = DefineClientTransaction(types, interface, *method, options); } else { m = DefineClientMetaTransaction(types, interface, *method, options); } 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 AidlInterface& interface, const AidlMethod& method, const Options& options, 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(*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()); } } if (options.GenTraces()) { b->AddStatement(new Statement(new MethodCall("atrace_begin", ArgList{{"ATRACE_TAG_AIDL", StringPrintf("\"%s::%s::cppServer\"", interface.GetName().c_str(), method.GetName().c_str())}}))); } const string bn_name = ClassName(interface, ClassNames::SERVER); if (options.GenLog()) { b->AddLiteral(GenLogBeforeExecute(bn_name, method, true /* isServer */, false /* isNdk */), false); } // 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))))); if (options.GenTraces()) { b->AddStatement(new Statement(new MethodCall("atrace_end", "ATRACE_TAG_AIDL"))); } if (options.GenLog()) { b->AddLiteral(GenLogAfterExecute(bn_name, interface, method, kStatusVarName, kReturnVarName, true /* isServer */, false /* isNdk */), false); } // 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; } bool HandleServerMetaTransaction(const TypeNamespace&, const AidlInterface& interface, const AidlMethod& method, const Options& options, StatementBlock* b) { CHECK(!method.IsUserDefined()); if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) { std::ostringstream code; code << "_aidl_data.checkInterface(this);\n" << "_aidl_reply->writeNoException();\n" << "_aidl_reply->writeInt32(" << ClassName(interface, ClassNames::INTERFACE) << "::VERSION)"; b->AddLiteral(code.str()); return true; } return false; } } // namespace unique_ptr BuildServerSource(const TypeNamespace& types, const AidlInterface& interface, const Options& options) { const string bn_name = ClassName(interface, ClassNames::SERVER); vector include_list{ HeaderFile(interface, ClassNames::SERVER, false), kParcelHeader }; if (options.GenLog()) { include_list.emplace_back("chrono"); include_list.emplace_back("functional"); include_list.emplace_back("json/value.h"); } 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(GetTransactionIdFor(*method)); if (!b) { return nullptr; } bool success = false; if (method->IsUserDefined()) { success = HandleServerTransaction(types, interface, *method, options, b); } else { success = HandleServerMetaTransaction(types, interface, *method, options, b); } if (!success) { 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)); vector> decls; decls.push_back(std::move(on_transact)); if (options.Version() > 0) { std::ostringstream code; code << "int32_t " << bn_name << "::" << kGetInterfaceVersion << "() {\n" << " return " << ClassName(interface, ClassNames::INTERFACE) << "::VERSION;\n" << "}\n"; decls.emplace_back(new LiteralDecl(code.str())); } if (options.GenLog()) { string code; ClassName(interface, ClassNames::SERVER); CodeWriterPtr writer = CodeWriter::ForString(&code); (*writer) << "std::function " << ClassName(interface, ClassNames::SERVER) << "::logFunc;\n"; writer->Close(); decls.push_back(unique_ptr(new LiteralDecl(code))); } return unique_ptr{ new CppSource{include_list, NestInNamespaces(std::move(decls), interface.GetSplitPackage())}}; } unique_ptr BuildInterfaceSource(const TypeNamespace& types, const AidlInterface& interface, const Options& options) { vector include_list{ HeaderFile(interface, ClassNames::RAW, 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.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); if (value.GetType() != AidlConstantValue::Type::STRING) continue; std::string cppType = constant->GetType().GetLanguageType()->CppType(); unique_ptr getter(new MethodImpl("const " + cppType + "&", ClassName(interface, ClassNames::INTERFACE), constant->GetName(), {})); getter->GetStatementBlock()->AddLiteral( StringPrintf("static const %s value(%s)", cppType.c_str(), constant->ValueString(ConstantValueDecorator).c_str())); getter->GetStatementBlock()->AddLiteral("return value"); decls.push_back(std::move(getter)); } // Implement the default impl class. // onAsBinder returns nullptr as this interface is not associated with a // real binder. const string default_impl(ClassName(interface, ClassNames::DEFAULT_IMPL)); decls.emplace_back( new LiteralDecl(StringPrintf("::android::IBinder* %s::onAsBinder() {\n" " return nullptr;\n" "}\n", default_impl.c_str()))); // Each interface method by default returns UNKNOWN_TRANSACTION with is // the same status that is returned by transact() when the method is // not implemented in the server side. In other words, these default // methods do nothing; they only exist to aid making a real default // impl class without having to override all methods in an interface. for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { std::ostringstream code; code << "::android::binder::Status " << default_impl << "::" << method->GetName() << BuildArgList(types, *method, true, true).ToString() << " {\n" << " return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION);\n" << "}\n"; decls.emplace_back(new LiteralDecl(code.str())); } else { if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { std::ostringstream code; code << "int32_t " << default_impl << "::" << kGetInterfaceVersion << "() {\n" << " return 0;\n" << "}\n"; decls.emplace_back(new LiteralDecl(code.str())); } } } return unique_ptr{new CppSource{ include_list, NestInNamespaces(std::move(decls), interface.GetSplitPackage())}}; } unique_ptr BuildClientHeader(const TypeNamespace& types, const AidlInterface& interface, const Options& options) { const string i_name = ClassName(interface, ClassNames::INTERFACE); const string bp_name = ClassName(interface, ClassNames::CLIENT); vector includes = {kIBinderHeader, kIInterfaceHeader, "utils/Errors.h", HeaderFile(interface, ClassNames::RAW, false)}; 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()) { if (method->IsUserDefined()) { publics.push_back(BuildMethodDecl(*method, types, false)); } else { publics.push_back(BuildMetaMethodDecl(*method, types, options, false)); } } if (options.GenLog()) { includes.emplace_back("chrono"); // for std::chrono::steady_clock includes.emplace_back("functional"); // for std::function includes.emplace_back("json/value.h"); publics.emplace_back( new LiteralDecl{"static std::function logFunc;\n"}); } vector> privates; if (options.Version() > 0) { privates.emplace_back(new LiteralDecl("int32_t cached_version_ = -1;\n")); } unique_ptr bp_class{new ClassDecl{ bp_name, "::android::BpInterface<" + i_name + ">", std::move(publics), std::move(privates), }}; return unique_ptr{ new CppHeader{BuildHeaderGuard(interface, ClassNames::CLIENT), includes, NestInNamespaces(std::move(bp_class), interface.GetSplitPackage())}}; } unique_ptr BuildServerHeader(const TypeNamespace& /* types */, const AidlInterface& interface, const Options& options) { 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", kFlagsVarName)}}, MethodDecl::IS_OVERRIDE }}; vector includes = {"binder/IInterface.h", HeaderFile(interface, ClassNames::RAW, false)}; vector> publics; publics.push_back(std::move(on_transact)); if (options.Version() > 0) { std::ostringstream code; code << "int32_t " << kGetInterfaceVersion << "() final override;\n"; publics.emplace_back(new LiteralDecl(code.str())); } if (options.GenLog()) { includes.emplace_back("chrono"); // for std::chrono::steady_clock includes.emplace_back("functional"); // for std::function includes.emplace_back("json/value.h"); publics.emplace_back( new LiteralDecl{"static std::function logFunc;\n"}); } unique_ptr bn_class{ new ClassDecl{bn_name, "::android::BnInterface<" + i_name + ">", std::move(publics), {} }}; return unique_ptr{ new CppHeader{BuildHeaderGuard(interface, ClassNames::SERVER), includes, NestInNamespaces(std::move(bn_class), interface.GetSplitPackage())}}; } unique_ptr BuildInterfaceHeader(const TypeNamespace& types, const AidlInterface& interface, const Options& options) { 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(); if (return_type != nullptr) { return_type->GetHeaders(&includes); } } const string i_name = ClassName(interface, ClassNames::INTERFACE); unique_ptr if_class{new ClassDecl{i_name, "::android::IInterface"}}; if_class->AddPublic(unique_ptr{new MacroDecl{ "DECLARE_META_INTERFACE", ArgList{vector{ClassName(interface, ClassNames::BASE)}}}}); if (options.Version() > 0) { std::ostringstream code; code << "const int32_t VERSION = " << options.Version() << ";\n"; if_class->AddPublic(unique_ptr(new LiteralDecl(code.str()))); } std::vector> string_constants; unique_ptr int_constant_enum{new Enum{"", "int32_t"}}; for (const auto& constant : interface.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); switch (value.GetType()) { case AidlConstantValue::Type::STRING: { std::string cppType = constant->GetType().GetLanguageType()->CppType(); unique_ptr getter(new MethodDecl("const " + cppType + "&", constant->GetName(), {}, MethodDecl::IS_STATIC)); string_constants.push_back(std::move(getter)); break; } case AidlConstantValue::Type::INTEGRAL: case AidlConstantValue::Type::HEXIDECIMAL: { int_constant_enum->AddValue(constant->GetName(), constant->ValueString(ConstantValueDecorator)); break; } default: { LOG(FATAL) << "Unrecognized constant type: " << static_cast(value.GetType()); } } } if (int_constant_enum->HasValues()) { if_class->AddPublic(std::move(int_constant_enum)); } if (!string_constants.empty()) { includes.insert(kString16Header); for (auto& string_constant : string_constants) { if_class->AddPublic(std::move(string_constant)); } } if (options.GenTraces()) { includes.insert(kTraceHeader); } if (!interface.GetMethods().empty()) { for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { // Each method gets an enum entry and pure virtual declaration. if_class->AddPublic(BuildMethodDecl(*method, types, true)); } else { if_class->AddPublic(BuildMetaMethodDecl(*method, types, options, true)); } } } vector> decls; decls.emplace_back(std::move(if_class)); // Base class for the default implementation. vector method_decls; for (const auto& method : interface.GetMethods()) { if (method->IsUserDefined()) { method_decls.emplace_back(BuildMethodDecl(*method, types, false)->ToString()); } else { method_decls.emplace_back(BuildMetaMethodDecl(*method, types, options, false)->ToString()); } } decls.emplace_back(new LiteralDecl( android::base::StringPrintf("class %s : public %s {\n" "public:\n" " ::android::IBinder* onAsBinder() override;\n" " %s\n" "};\n", ClassName(interface, ClassNames::DEFAULT_IMPL).c_str(), i_name.c_str(), Join(method_decls, " ").c_str()))); return unique_ptr{ new CppHeader{BuildHeaderGuard(interface, ClassNames::INTERFACE), vector(includes.begin(), includes.end()), NestInNamespaces(std::move(decls), interface.GetSplitPackage())}}; } std::unique_ptr BuildParcelHeader(const TypeNamespace& /*types*/, const AidlStructuredParcelable& parcel, const Options&) { unique_ptr parcel_class{new ClassDecl{parcel.GetName(), "::android::Parcelable"}}; set includes = {kStatusHeader, kParcelHeader}; for (const auto& variable : parcel.GetFields()) { const Type* type = variable->GetType().GetLanguageType(); type->GetHeaders(&includes); } for (const auto& variable : parcel.GetFields()) { const Type* type = variable->GetType().GetLanguageType(); std::ostringstream out; out << type->CppType().c_str() << " " << variable->GetName().c_str(); if (variable->GetDefaultValue()) { out << " = " << type->CppType().c_str() << "(" << variable->ValueString(ConstantValueDecorator) << ")"; } out << ";\n"; parcel_class->AddPublic(std::unique_ptr(new LiteralDecl(out.str()))); } unique_ptr read(new MethodDecl(kAndroidStatusLiteral, "readFromParcel", ArgList("const ::android::Parcel* _aidl_parcel"), MethodDecl::IS_OVERRIDE | MethodDecl::IS_FINAL)); parcel_class->AddPublic(std::move(read)); unique_ptr write(new MethodDecl( kAndroidStatusLiteral, "writeToParcel", ArgList("::android::Parcel* _aidl_parcel"), MethodDecl::IS_OVERRIDE | MethodDecl::IS_CONST | MethodDecl::IS_FINAL)); parcel_class->AddPublic(std::move(write)); return unique_ptr{new CppHeader{ BuildHeaderGuard(parcel, ClassNames::BASE), vector(includes.begin(), includes.end()), NestInNamespaces(std::move(parcel_class), parcel.GetSplitPackage())}}; } std::unique_ptr BuildParcelSource(const TypeNamespace& /*types*/, const AidlStructuredParcelable& parcel, const Options&) { unique_ptr read{new MethodImpl{kAndroidStatusLiteral, parcel.GetName(), "readFromParcel", ArgList("const ::android::Parcel* _aidl_parcel")}}; StatementBlock* read_block = read->GetStatementBlock(); read_block->AddLiteral( StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk)); read_block->AddLiteral( "size_t _aidl_start_pos = _aidl_parcel->dataPosition();\n" "int32_t _aidl_parcelable_raw_size = _aidl_parcel->readInt32();\n" "if (_aidl_parcelable_raw_size < 0) return ::android::BAD_VALUE;\n" "size_t _aidl_parcelable_size = static_cast(_aidl_parcelable_raw_size);\n"); for (const auto& variable : parcel.GetFields()) { string method = variable->GetType().GetLanguageType()->ReadFromParcelMethod(); read_block->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("_aidl_parcel->%s", method.c_str()), ArgList("&" + variable->GetName())))); read_block->AddStatement(ReturnOnStatusNotOk()); read_block->AddLiteral(StringPrintf( "if (_aidl_parcel->dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) {\n" " _aidl_parcel->setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n" " return %s;\n" "}", kAndroidStatusVarName)); } read_block->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName)); unique_ptr write{ new MethodImpl{kAndroidStatusLiteral, parcel.GetName(), "writeToParcel", ArgList("::android::Parcel* _aidl_parcel"), true /*const*/}}; StatementBlock* write_block = write->GetStatementBlock(); write_block->AddLiteral( StringPrintf("%s %s = %s", kAndroidStatusLiteral, kAndroidStatusVarName, kAndroidStatusOk)); write_block->AddLiteral( "auto _aidl_start_pos = _aidl_parcel->dataPosition();\n" "_aidl_parcel->writeInt32(0);"); for (const auto& variable : parcel.GetFields()) { string method = variable->GetType().GetLanguageType()->WriteToParcelMethod(); write_block->AddStatement(new Assignment( kAndroidStatusVarName, new MethodCall(StringPrintf("_aidl_parcel->%s", method.c_str()), ArgList(variable->GetName())))); write_block->AddStatement(ReturnOnStatusNotOk()); } write_block->AddLiteral( "auto _aidl_end_pos = _aidl_parcel->dataPosition();\n" "_aidl_parcel->setDataPosition(_aidl_start_pos);\n" "_aidl_parcel->writeInt32(_aidl_end_pos - _aidl_start_pos);\n" "_aidl_parcel->setDataPosition(_aidl_end_pos);"); write_block->AddLiteral(StringPrintf("return %s", kAndroidStatusVarName)); vector> file_decls; file_decls.push_back(std::move(read)); file_decls.push_back(std::move(write)); set includes = {}; parcel.GetLanguageType()->GetHeaders(&includes); return unique_ptr{ new CppSource{vector(includes.begin(), includes.end()), NestInNamespaces(std::move(file_decls), parcel.GetSplitPackage())}}; } bool WriteHeader(const Options& 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, options); header_type = ClassNames::RAW; break; case ClassNames::CLIENT: header = BuildClientHeader(types, interface, options); break; case ClassNames::SERVER: header = BuildServerHeader(types, interface, options); 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() + 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; bool GenerateCppInterface(const string& output_file, const Options& options, const TypeNamespace& types, const AidlInterface& interface, const IoDelegate& io_delegate) { auto interface_src = BuildInterfaceSource(types, interface, options); auto client_src = BuildClientSource(types, interface, options); auto server_src = BuildServerSource(types, interface, options); if (!interface_src || !client_src || !server_src) { 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(output_file); 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(output_file); } return success; } bool GenerateCppParcel(const string& output_file, const Options& options, const cpp::TypeNamespace& types, const AidlStructuredParcelable& parcelable, const IoDelegate& io_delegate) { auto header = BuildParcelHeader(types, parcelable, options); auto source = BuildParcelSource(types, parcelable, options); if (!header || !source) { return false; } const string header_path = options.OutputHeaderDir() + HeaderFile(parcelable, ClassNames::RAW); unique_ptr header_writer(io_delegate.GetCodeWriter(header_path)); header->Write(header_writer.get()); CHECK(header_writer->Close()); // TODO(b/111362593): no unecessary files just to have consistent output with interfaces const string bp_header = options.OutputHeaderDir() + HeaderFile(parcelable, ClassNames::CLIENT); unique_ptr bp_writer(io_delegate.GetCodeWriter(bp_header)); bp_writer->Write("#error TODO(b/111362593) parcelables do not have bp classes"); CHECK(bp_writer->Close()); const string bn_header = options.OutputHeaderDir() + HeaderFile(parcelable, ClassNames::SERVER); unique_ptr bn_writer(io_delegate.GetCodeWriter(bn_header)); bn_writer->Write("#error TODO(b/111362593) parcelables do not have bn classes"); CHECK(bn_writer->Close()); unique_ptr source_writer = io_delegate.GetCodeWriter(output_file); source->Write(source_writer.get()); CHECK(source_writer->Close()); return true; } bool GenerateCppParcelDeclaration(const std::string& filename, const IoDelegate& io_delegate) { CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); *code_writer << "// This file is intentionally left blank as placeholder for parcel declaration.\n"; return true; } bool GenerateCpp(const string& output_file, const Options& options, const TypeNamespace& types, const AidlDefinedType& defined_type, const IoDelegate& io_delegate) { const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable(); if (parcelable != nullptr) { return GenerateCppParcel(output_file, options, types, *parcelable, io_delegate); } const AidlParcelable* parcelable_decl = defined_type.AsParcelable(); if (parcelable_decl != nullptr) { return GenerateCppParcelDeclaration(output_file, io_delegate); } const AidlInterface* interface = defined_type.AsInterface(); if (interface != nullptr) { return GenerateCppInterface(output_file, options, types, *interface, io_delegate); } CHECK(false) << "Unrecognized type sent for cpp generation."; return false; } } // namespace cpp } // namespace aidl } // namespace android generate_cpp.h0100644 0000000 0000000 00000005567 13755771705 012450 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. */ #pragma once #include #include #include "aidl_language.h" #include "aidl_to_cpp.h" #include "aidl_to_cpp_common.h" #include "ast_cpp.h" #include "options.h" #include "type_cpp.h" namespace android { namespace aidl { namespace cpp { bool GenerateCpp(const string& output_file, const Options& options, const cpp::TypeNamespace& types, const AidlDefinedType& parsed_doc, const IoDelegate& io_delegate); namespace internals { std::unique_ptr BuildClientSource(const TypeNamespace& types, const AidlInterface& parsed_doc, const Options& options); std::unique_ptr BuildServerSource(const TypeNamespace& types, const AidlInterface& parsed_doc, const Options& options); std::unique_ptr BuildInterfaceSource(const TypeNamespace& types, const AidlInterface& parsed_doc, const Options& options); std::unique_ptr BuildClientHeader(const TypeNamespace& types, const AidlInterface& parsed_doc, const Options& options); std::unique_ptr BuildServerHeader(const TypeNamespace& types, const AidlInterface& parsed_doc, const Options& options); std::unique_ptr BuildInterfaceHeader(const TypeNamespace& types, const AidlInterface& parsed_doc, const Options& options); std::unique_ptr BuildParcelHeader(const TypeNamespace& types, const AidlStructuredParcelable& parsed_doc, const Options& options); std::unique_ptr BuildParcelSource(const TypeNamespace& types, const AidlStructuredParcelable& parsed_doc, const Options& options); } } // namespace cpp } // namespace aidl } // namespace android generate_cpp_unittest.cpp0100644 0000000 0000000 00000165536 13755771705 014745 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 #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(::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* Send */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->Send(goes_in, goes_in_and_out, goes_out, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* Piff */, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->Piff(times); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* TakesABinder */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->TakesABinder(f, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* NullableBinder */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->NullableBinder(_aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 4 /* StringListMethod */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->StringListMethod(input, output, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 5 /* BinderListMethod */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->BinderListMethod(input, output, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 6 /* TakesAFileDescriptor */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->TakesAFileDescriptor(f, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 7 /* TakesAFileDescriptorArray */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->TakesAFileDescriptorArray(f, _aidl_return); } 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 kExpectedComplexTypeClientWithTraceSourceOutput[] = R"(#include #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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::Send::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* Send */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->Send(goes_in, goes_in_and_out, goes_out, _aidl_return); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::Piff::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* Piff */, _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->Piff(times); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesABinder::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* TakesABinder */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->TakesABinder(f, _aidl_return); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::NullableBinder::cppClient"); _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor()); if (((_aidl_ret_status) != (::android::OK))) { goto _aidl_error; } _aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* NullableBinder */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->NullableBinder(_aidl_return); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::StringListMethod::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 4 /* StringListMethod */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->StringListMethod(input, output, _aidl_return); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::BinderListMethod::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 5 /* BinderListMethod */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->BinderListMethod(input, output, _aidl_return); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptor::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 6 /* TakesAFileDescriptor */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->TakesAFileDescriptor(f, _aidl_return); } 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; ScopedTrace _aidl_trace(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptorArray::cppClient"); _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(::android::IBinder::FIRST_CALL_TRANSACTION + 7 /* TakesAFileDescriptorArray */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IComplexTypeInterface::getDefaultImpl())) { return IComplexTypeInterface::getDefaultImpl()->TakesAFileDescriptorArray(f, _aidl_return); } 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) 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 4 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 5 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 6 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 7 /* 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 kExpectedComplexTypeServerWithTraceSourceOutput[] = 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::Send::cppServer"); ::android::binder::Status _aidl_status(Send(in_goes_in, &in_goes_in_and_out, &out_goes_out, &_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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 ::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::Piff::cppServer"); ::android::binder::Status _aidl_status(Piff(in_times)); atrace_end(ATRACE_TAG_AIDL); } break; case ::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesABinder::cppServer"); ::android::binder::Status _aidl_status(TakesABinder(in_f, &_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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 ::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* NullableBinder */: { ::android::sp<::foo::IFooType> _aidl_return; if (!(_aidl_data.checkInterface(this))) { _aidl_ret_status = ::android::BAD_TYPE; break; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::NullableBinder::cppServer"); ::android::binder::Status _aidl_status(NullableBinder(&_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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 ::android::IBinder::FIRST_CALL_TRANSACTION + 4 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::StringListMethod::cppServer"); ::android::binder::Status _aidl_status(StringListMethod(in_input, &out_output, &_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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 ::android::IBinder::FIRST_CALL_TRANSACTION + 5 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::BinderListMethod::cppServer"); ::android::binder::Status _aidl_status(BinderListMethod(in_input, &out_output, &_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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 ::android::IBinder::FIRST_CALL_TRANSACTION + 6 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptor::cppServer"); ::android::binder::Status _aidl_status(TakesAFileDescriptor(in_f, &_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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 ::android::IBinder::FIRST_CALL_TRANSACTION + 7 /* 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; } atrace_begin(ATRACE_TAG_AIDL, "IComplexTypeInterface::TakesAFileDescriptorArray::cppServer"); ::android::binder::Status _aidl_status(TakesAFileDescriptorArray(in_f, &_aidl_return)); atrace_end(ATRACE_TAG_AIDL); _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; }; // class IComplexTypeInterface class IComplexTypeInterfaceDefault : public IComplexTypeInterface { public: ::android::IBinder* onAsBinder() override; ::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; }; } // 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") ::android::IBinder* IComplexTypeInterfaceDefault::onAsBinder() { return nullptr; } ::android::binder::Status IComplexTypeInterfaceDefault::Send(const ::std::unique_ptr<::std::vector>&, ::std::vector*, ::std::vector*, ::std::vector* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::Piff(int32_t) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::TakesABinder(const ::android::sp<::foo::IFooType>&, ::android::sp<::foo::IFooType>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::NullableBinder(::android::sp<::foo::IFooType>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::StringListMethod(const ::std::vector<::android::String16>&, ::std::vector<::android::String16>*, ::std::vector<::android::String16>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::BinderListMethod(const ::std::vector<::android::sp<::android::IBinder>>&, ::std::vector<::android::sp<::android::IBinder>>*, ::std::vector<::android::sp<::android::IBinder>>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::TakesAFileDescriptor(const ::android::base::unique_fd&, ::android::base::unique_fd* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IComplexTypeInterfaceDefault::TakesAFileDescriptorArray(const ::std::vector<::android::base::unique_fd>&, ::std::vector<::android::base::unique_fd>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } } // namespace os } // namespace android )"; } // namespace class ASTTest : public ::testing::Test { protected: ASTTest(const string& cmdline, const string& file_contents) : options_(Options::From(cmdline)), file_contents_(file_contents) { types_.Init(); } AidlInterface* ParseSingleInterface() { io_delegate_.SetFileContents(options_.InputFiles().at(0), file_contents_); vector defined_types; vector imported_files; ImportResolver import_resolver{io_delegate_, options_.InputFiles().at(0), {"."}, {}}; AidlError err = ::android::aidl::internals::load_and_validate_aidl( options_.InputFiles().front(), options_, io_delegate_, &types_, &defined_types, &imported_files); if (err != AidlError::OK) { return nullptr; } EXPECT_EQ(1ul, defined_types.size()); EXPECT_NE(nullptr, defined_types.front()->AsInterface()); return defined_types.front()->AsInterface(); } void Compare(Document* doc, const char* expected) { string output; doc->Write(CodeWriter::ForString(&output).get()); if (expected == output) { return; // Success } test::PrintDiff(expected, output); FAIL() << "Document contents did not match expected contents"; } const Options options_; const string file_contents_; FakeIoDelegate io_delegate_; TypeNamespace types_; }; class ComplexTypeInterfaceASTTest : public ASTTest { public: ComplexTypeInterfaceASTTest() : ASTTest("aidl --lang=cpp -I . -o out android/os/IComplexTypeInterface.aidl", kComplexTypeInterfaceAIDL) { io_delegate_.SetFileContents("foo/IFooType.aidl", "package foo; interface IFooType {}"); } }; TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientHeader) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildClientHeader(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeClientHeaderOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesClientSource) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildClientSource(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeClientSourceOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerHeader) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildServerHeader(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeServerHeaderOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesServerSource) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildServerSource(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeServerSourceOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceHeader) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildInterfaceHeader(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeInterfaceHeaderOutput); } TEST_F(ComplexTypeInterfaceASTTest, GeneratesInterfaceSource) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildInterfaceSource(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeInterfaceSourceOutput); } class ComplexTypeInterfaceASTTestWithTrace : public ASTTest { public: ComplexTypeInterfaceASTTestWithTrace() : ASTTest("aidl --lang=cpp -t -I . -o out android/os/IComplexTypeInterface.aidl", kComplexTypeInterfaceAIDL) { io_delegate_.SetFileContents("foo/IFooType.aidl", "package foo; interface IFooType {}"); } }; TEST_F(ComplexTypeInterfaceASTTestWithTrace, GeneratesClientSource) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildClientSource(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeClientWithTraceSourceOutput); } TEST_F(ComplexTypeInterfaceASTTestWithTrace, GeneratesServerSource) { AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); unique_ptr doc = internals::BuildServerSource(types_, *interface, options_); Compare(doc.get(), kExpectedComplexTypeServerWithTraceSourceOutput); } 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"; const string kCmdline = string("aidl-cpp ") + kInputPath + " " + kHeaderDir + " " + kOutputPath; } // namespace test_io_handling class IoErrorHandlingTest : public ASTTest { public: IoErrorHandlingTest() : ASTTest(test_io_handling::kCmdline, "package a; interface IFoo {}") {} }; TEST_F(IoErrorHandlingTest, GenerateCorrectlyAbsentErrors) { // Confirm that this is working correctly without I/O problems. AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); ASSERT_TRUE(GenerateCpp(options_.OutputFile(), options_, types_, *interface, io_delegate_)); } TEST_F(IoErrorHandlingTest, HandlesBadHeaderWrite) { using namespace test_io_handling; AidlInterface* interface = ParseSingleInterface(); 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_.OutputFile(), 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; AidlInterface* interface = ParseSingleInterface(); ASSERT_NE(interface, nullptr); // Simulate issues closing the cpp file. io_delegate_.AddBrokenFilePath(kOutputPath); ASSERT_FALSE(GenerateCpp(options_.OutputFile(), 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 00000021133 13755771705 013125 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 #include "aidl_to_java.h" #include "code_writer.h" #include "type_java.h" using std::unique_ptr; using ::android::aidl::java::Variable; using std::string; namespace android { namespace aidl { namespace java { bool generate_java_interface(const string& filename, const AidlInterface* iface, JavaTypeNamespace* types, const IoDelegate& io_delegate, const Options& options) { Class* cl = generate_binder_interface_class(iface, types, options); Document* document = new Document("" /* no comment */, iface->GetPackage(), unique_ptr(cl)); CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); document->Write(code_writer.get()); return true; } bool generate_java_parcel(const std::string& filename, const AidlStructuredParcelable* parcel, AidlTypenames& typenames, const IoDelegate& io_delegate) { Class* cl = generate_parcel_class(parcel, typenames); Document* document = new Document("" /* no comment */, parcel->GetPackage(), unique_ptr(cl)); CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); document->Write(code_writer.get()); return true; } bool generate_java(const std::string& filename, const AidlDefinedType* defined_type, JavaTypeNamespace* types, const IoDelegate& io_delegate, const Options& options) { const AidlStructuredParcelable* parcelable = defined_type->AsStructuredParcelable(); if (parcelable != nullptr) { return generate_java_parcel(filename, parcelable, types->typenames_, io_delegate); } const AidlInterface* interface = defined_type->AsInterface(); if (interface != nullptr) { return generate_java_interface(filename, interface, types, io_delegate, options); } CHECK(false) << "Unrecognized type sent for cpp generation."; return false; } android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel, AidlTypenames& typenames) { Class* parcel_class = new Class; parcel_class->comment = parcel->GetComments(); parcel_class->modifiers = PUBLIC; parcel_class->what = Class::CLASS; parcel_class->type = parcel->GetCanonicalName(); parcel_class->interfaces.push_back("android.os.Parcelable"); parcel_class->annotations = generate_java_annotations(*parcel); for (const auto& variable : parcel->GetFields()) { const Type* type = variable->GetType().GetLanguageType(); std::ostringstream out; out << variable->GetType().GetComments() << "\n"; for (const auto& a : generate_java_annotations(variable->GetType())) { out << a << "\n"; } out << "public " << type->JavaType() << (variable->GetType().IsArray() ? "[]" : "") << " " << variable->GetName(); if (variable->GetDefaultValue()) { out << " = " << variable->ValueString(AidlConstantValueDecorator); } out << ";\n"; parcel_class->elements.push_back(new LiteralClassElement(out.str())); } std::ostringstream out; out << "public static final android.os.Parcelable.Creator<" << parcel->GetName() << "> CREATOR = " << "new android.os.Parcelable.Creator<" << parcel->GetName() << ">() {\n"; out << " @Override\n"; out << " public " << parcel->GetName() << " createFromParcel(android.os.Parcel _aidl_source) {\n"; out << " " << parcel->GetName() << " _aidl_out = new " << parcel->GetName() << "();\n"; out << " _aidl_out.readFromParcel(_aidl_source);\n"; out << " return _aidl_out;\n"; out << " }\n"; out << " @Override\n"; out << " public " << parcel->GetName() << "[] newArray(int _aidl_size) {\n"; out << " return new " << parcel->GetName() << "[_aidl_size];\n"; out << " }\n"; out << "};\n"; parcel_class->elements.push_back(new LiteralClassElement(out.str())); Variable* flag_variable = new Variable("int", "_aidl_flag"); Variable* parcel_variable = new Variable("android.os.Parcel", "_aidl_parcel"); Method* write_method = new Method; write_method->modifiers = PUBLIC | OVERRIDE | FINAL; write_method->returnType = "void"; write_method->name = "writeToParcel"; write_method->parameters.push_back(parcel_variable); write_method->parameters.push_back(flag_variable); write_method->statements = new StatementBlock(); out.str(""); out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n" << "_aidl_parcel.writeInt(0);\n"; write_method->statements->Add(new LiteralStatement(out.str())); for (const auto& field : parcel->GetFields()) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); CodeGeneratorContext context{ .writer = *(writer.get()), .typenames = typenames, .type = field->GetType(), .var = field->GetName(), .parcel = parcel_variable->name, .is_return_value = false, }; WriteToParcelFor(context); writer->Close(); write_method->statements->Add(new LiteralStatement(code)); } out.str(""); out << "int _aidl_end_pos = _aidl_parcel.dataPosition();\n" << "_aidl_parcel.setDataPosition(_aidl_start_pos);\n" << "_aidl_parcel.writeInt(_aidl_end_pos - _aidl_start_pos);\n" << "_aidl_parcel.setDataPosition(_aidl_end_pos);\n"; write_method->statements->Add(new LiteralStatement(out.str())); parcel_class->elements.push_back(write_method); Method* read_method = new Method; read_method->modifiers = PUBLIC | FINAL; read_method->returnType = "void"; read_method->name = "readFromParcel"; read_method->parameters.push_back(parcel_variable); read_method->statements = new StatementBlock(); out.str(""); out << "int _aidl_start_pos = _aidl_parcel.dataPosition();\n" << "int _aidl_parcelable_size = _aidl_parcel.readInt();\n" << "if (_aidl_parcelable_size < 0) return;\n" << "try {\n"; read_method->statements->Add(new LiteralStatement(out.str())); out.str(""); out << " if (_aidl_parcel.dataPosition() - _aidl_start_pos >= _aidl_parcelable_size) return;\n"; LiteralStatement* sizeCheck = nullptr; // keep this across different fields in order to create the classloader // at most once. bool is_classloader_created = false; for (const auto& field : parcel->GetFields()) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); CodeGeneratorContext context{ .writer = *(writer.get()), .typenames = typenames, .type = field->GetType(), .var = field->GetName(), .parcel = parcel_variable->name, .is_classloader_created = &is_classloader_created, }; context.writer.Indent(); CreateFromParcelFor(context); writer->Close(); read_method->statements->Add(new LiteralStatement(code)); if (!sizeCheck) sizeCheck = new LiteralStatement(out.str()); read_method->statements->Add(sizeCheck); } out.str(""); out << "} finally {\n" << " _aidl_parcel.setDataPosition(_aidl_start_pos + _aidl_parcelable_size);\n" << "}\n"; read_method->statements->Add(new LiteralStatement(out.str())); parcel_class->elements.push_back(read_method); Method* describe_contents_method = new Method; describe_contents_method->modifiers = PUBLIC | OVERRIDE; describe_contents_method->returnType = "int"; describe_contents_method->name = "describeContents"; describe_contents_method->statements = new StatementBlock(); describe_contents_method->statements->Add(new LiteralStatement("return 0;\n")); parcel_class->elements.push_back(describe_contents_method); return parcel_class; } std::vector generate_java_annotations(const AidlAnnotatable& a) { std::vector result; if (a.IsUnsupportedAppUsage()) { result.emplace_back("@android.annotation.UnsupportedAppUsage"); } if (a.IsSystemApi()) { result.emplace_back("@android.annotation.SystemApi"); } return result; } } // namespace java } // namespace android } // namespace aidl generate_java.h0100644 0000000 0000000 00000003114 13755771705 012571 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. */ #pragma once #include "aidl_language.h" #include "ast_java.h" #include "io_delegate.h" #include "options.h" #include "type_java.h" #include namespace android { namespace aidl { namespace java { bool generate_java(const std::string& filename, const AidlDefinedType* iface, java::JavaTypeNamespace* types, const IoDelegate& io_delegate, const Options& options); android::aidl::java::Class* generate_binder_interface_class(const AidlInterface* iface, java::JavaTypeNamespace* types, const Options& options); android::aidl::java::Class* generate_parcel_class(const AidlStructuredParcelable* parcel, AidlTypenames& typenames); std::vector generate_java_annotations(const AidlAnnotatable& a); } // namespace java } // namespace android } // namespace aidl generate_java_binder.cpp0100644 0000000 0000000 00000127421 13755771705 014457 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.h" #include "aidl_to_java.h" #include "generate_java.h" #include "options.h" #include "type_java.h" #include #include #include #include #include #include #include #include #include using android::base::Join; using android::base::StringPrintf; using std::string; using std::unique_ptr; using std::vector; namespace android { namespace aidl { namespace java { // ================================================= class VariableFactory { public: using Variable = ::android::aidl::java::Variable; using Type = ::android::aidl::java::Type; explicit VariableFactory(const std::string& base) : base_(base), index_(0) {} Variable* Get(const Type* type) { Variable* v = new Variable(type->JavaType(), StringPrintf("%s%d", base_.c_str(), index_)); vars_.push_back(v); index_++; return v; } Variable* Get(int index) { return vars_[index]; } private: std::vector vars_; std::string base_; int index_; DISALLOW_COPY_AND_ASSIGN(VariableFactory); }; // ================================================= class StubClass : public Class { public: StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types, const Options& options); ~StubClass() override = default; Variable* transact_code; Variable* transact_data; Variable* transact_reply; Variable* transact_flags; SwitchStatement* transact_switch; StatementBlock* transact_statements; SwitchStatement* code_to_method_name_switch; // Where onTransact cases should be generated as separate methods. bool transact_outline; // Specific methods that should be outlined when transact_outline is true. std::unordered_set outline_methods; // Number of all methods. size_t all_method_count; // Finish generation. This will add a default case to the switch. void finish(); Expression* get_transact_descriptor(const JavaTypeNamespace* types, const AidlMethod* method); private: void make_as_interface(const InterfaceType* interfaceType, JavaTypeNamespace* types); Variable* transact_descriptor; const Options& options_; DISALLOW_COPY_AND_ASSIGN(StubClass); }; StubClass::StubClass(const Type* type, const InterfaceType* interfaceType, JavaTypeNamespace* types, const Options& options) : Class(), options_(options) { transact_descriptor = nullptr; transact_outline = false; all_method_count = 0; // Will be set when outlining may be enabled. this->comment = "/** Local-side IPC implementation stub class. */"; this->modifiers = PUBLIC | ABSTRACT | STATIC; this->what = Class::CLASS; this->type = type->JavaType(); this->extends = types->BinderNativeType()->JavaType(); this->interfaces.push_back(interfaceType->JavaType()); // descriptor Field* descriptor = new Field(STATIC | FINAL | PRIVATE, new Variable(types->StringType()->JavaType(), "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()->JavaType(); asBinder->name = "asBinder"; asBinder->statements = new StatementBlock; asBinder->statements->Add(new ReturnStatement(THIS_VALUE)); this->elements.push_back(asBinder); if (options_.GenTransactionNames()) { // getDefaultTransactionName Method* getDefaultTransactionName = new Method; getDefaultTransactionName->comment = "/** @hide */"; getDefaultTransactionName->modifiers = PUBLIC | STATIC; getDefaultTransactionName->returnType = types->StringType()->JavaType(); getDefaultTransactionName->name = "getDefaultTransactionName"; Variable* code = new Variable(types->IntType()->JavaType(), "transactionCode"); getDefaultTransactionName->parameters.push_back(code); getDefaultTransactionName->statements = new StatementBlock; this->code_to_method_name_switch = new SwitchStatement(code); getDefaultTransactionName->statements->Add(this->code_to_method_name_switch); this->elements.push_back(getDefaultTransactionName); // getTransactionName Method* getTransactionName = new Method; getTransactionName->comment = "/** @hide */"; getTransactionName->modifiers = PUBLIC; getTransactionName->returnType = types->StringType()->JavaType(); getTransactionName->name = "getTransactionName"; Variable* code2 = new Variable(types->IntType()->JavaType(), "transactionCode"); getTransactionName->parameters.push_back(code2); getTransactionName->statements = new StatementBlock; getTransactionName->statements->Add( new ReturnStatement(new MethodCall(THIS_VALUE, "getDefaultTransactionName", 1, code2))); this->elements.push_back(getTransactionName); } // onTransact this->transact_code = new Variable(types->IntType()->JavaType(), "code"); this->transact_data = new Variable(types->ParcelType()->JavaType(), "data"); this->transact_reply = new Variable(types->ParcelType()->JavaType(), "reply"); this->transact_flags = new Variable(types->IntType()->JavaType(), "flags"); Method* onTransact = new Method; onTransact->modifiers = PUBLIC | OVERRIDE; onTransact->returnType = types->BoolType()->JavaType(); 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; transact_statements = onTransact->statements; onTransact->exceptions.push_back(types->RemoteExceptionType()->JavaType()); this->elements.push_back(onTransact); this->transact_switch = new SwitchStatement(this->transact_code); } void StubClass::finish() { Case* default_case = new Case; MethodCall* superCall = new MethodCall( SUPER_VALUE, "onTransact", 4, this->transact_code, this->transact_data, this->transact_reply, this->transact_flags); default_case->statements->Add(new ReturnStatement(superCall)); transact_switch->cases.push_back(default_case); transact_statements->Add(this->transact_switch); // getTransactionName if (options_.GenTransactionNames()) { // Some transaction codes are common, e.g. INTERFACE_TRANSACTION or DUMP_TRANSACTION. // Common transaction codes will not be resolved to a string by getTransactionName. The method // will return NULL in this case. Case* code_switch_default_case = new Case; code_switch_default_case->statements->Add(new ReturnStatement(NULL_VALUE)); this->code_to_method_name_switch->cases.push_back(code_switch_default_case); } } // The the expression for the interface's descriptor to be used when // generating code for the given method. Null is acceptable for method // and stands for synthetic cases. Expression* StubClass::get_transact_descriptor(const JavaTypeNamespace* types, const AidlMethod* method) { if (transact_outline) { if (method != nullptr) { // When outlining, each outlined method needs its own literal. if (outline_methods.count(method) != 0) { return new LiteralExpression("DESCRIPTOR"); } } else { // Synthetic case. A small number is assumed. Use its own descriptor // if there are only synthetic cases. if (outline_methods.size() == all_method_count) { return new LiteralExpression("DESCRIPTOR"); } } } // When not outlining, store the descriptor literal into a local variable, in // an effort to save const-string instructions in each switch case. if (transact_descriptor == nullptr) { transact_descriptor = new Variable(types->StringType()->JavaType(), "descriptor"); transact_statements->Add( new VariableDeclaration(transact_descriptor, new LiteralExpression("DESCRIPTOR"))); } return transact_descriptor; } void StubClass::make_as_interface(const InterfaceType* interfaceType, JavaTypeNamespace* types) { Variable* obj = new Variable(types->IBinderType()->JavaType(), "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->JavaType(); 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(types); Variable* iin = new Variable(iinType.JavaType(), "iin"); VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface); 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->JavaType(), iin))); m->statements->Add(instOfStatement); NewExpression* ne = new NewExpression(interfaceType->GetProxy()->InstantiableName()); 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, const Options& options); ~ProxyClass() override; Variable* mRemote; }; ProxyClass::ProxyClass(const JavaTypeNamespace* types, const Type* type, const InterfaceType* interfaceType, const Options& options) : Class() { this->modifiers = PRIVATE | STATIC; this->what = Class::CLASS; this->type = type->JavaType(); this->interfaces.push_back(interfaceType->JavaType()); // IBinder mRemote mRemote = new Variable(types->IBinderType()->JavaType(), "mRemote"); this->elements.push_back(new Field(PRIVATE, mRemote)); // Proxy() Variable* remote = new Variable(types->IBinderType()->JavaType(), "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); if (options.Version() > 0) { std::ostringstream code; code << "private int mCachedVersion = -1;\n"; this->elements.emplace_back(new LiteralClassElement(code.str())); } // IBinder asBinder() Method* asBinder = new Method; asBinder->modifiers = PUBLIC | OVERRIDE; asBinder->returnType = types->IBinderType()->JavaType(); 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()->JavaType(), 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->JavaType(), len))); addTo->Add(lencheck); } static void generate_write_to_parcel(const AidlTypeSpecifier& type, StatementBlock* addTo, Variable* v, Variable* parcel, bool is_return_value, const AidlTypenames& typenames) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); CodeGeneratorContext context{ .writer = *(writer.get()), .typenames = typenames, .type = type, .var = v->name, .parcel = parcel->name, .is_return_value = is_return_value, }; WriteToParcelFor(context); writer->Close(); addTo->Add(new LiteralStatement(code)); } static void generate_int_constant(Class* interface, const std::string& name, const std::string& value) { auto code = StringPrintf("public static final int %s = %s;\n", name.c_str(), value.c_str()); interface->elements.push_back(new LiteralClassElement(code)); } static void generate_string_constant(Class* interface, const std::string& name, const std::string& value) { auto code = StringPrintf("public static final String %s = %s;\n", name.c_str(), value.c_str()); interface->elements.push_back(new LiteralClassElement(code)); } static std::unique_ptr generate_interface_method( const AidlMethod& method, JavaTypeNamespace* types) { std::unique_ptr decl(new Method); decl->comment = method.GetComments(); decl->modifiers = PUBLIC; decl->returnType = method.GetType().GetLanguageType()->JavaType(); decl->returnTypeDimension = method.GetType().IsArray() ? 1 : 0; decl->name = method.GetName(); decl->annotations = generate_java_annotations(method.GetType()); for (const std::unique_ptr& arg : method.GetArguments()) { decl->parameters.push_back(new Variable(arg->GetType().GetLanguageType()->JavaType(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0)); } decl->exceptions.push_back(types->RemoteExceptionType()->JavaType()); return decl; } static void generate_stub_code(const AidlInterface& iface, const AidlMethod& method, bool oneway, Variable* transact_data, Variable* transact_reply, JavaTypeNamespace* types, StatementBlock* statements, StubClass* stubClass, const Options& options) { TryStatement* tryStatement = nullptr; FinallyStatement* finallyStatement = nullptr; MethodCall* realCall = new MethodCall(THIS_VALUE, method.GetName()); // interface token validation is the very first thing we do statements->Add(new MethodCall(transact_data, "enforceInterface", 1, stubClass->get_transact_descriptor(types, &method))); // args VariableFactory stubArgs("_arg"); { // keep this across different args in order to create the classloader // at most once. bool is_classloader_created = false; 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; statements->Add(new VariableDeclaration(v)); if (arg->GetDirection() & AidlArgument::IN_DIR) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); CodeGeneratorContext context{.writer = *(writer.get()), .typenames = types->typenames_, .type = arg->GetType(), .var = v->name, .parcel = transact_data->name, .is_classloader_created = &is_classloader_created}; CreateFromParcelFor(context); writer->Close(); statements->Add(new LiteralStatement(code)); } else { if (!arg->GetType().IsArray()) { statements->Add(new Assignment(v, new NewExpression(t->InstantiableName()))); } else { generate_new_array(t, statements, v, transact_data, types); } } realCall->arguments.push_back(v); } } if (options.GenTraces()) { // try and finally, but only when generating trace code tryStatement = new TryStatement(); finallyStatement = new FinallyStatement(); tryStatement->statements->Add(new MethodCall( new LiteralExpression("android.os.Trace"), "traceBegin", 2, new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"), new StringLiteralExpression(iface.GetName() + "::" + method.GetName() + "::server"))); finallyStatement->statements->Add(new MethodCall( new LiteralExpression("android.os.Trace"), "traceEnd", 1, new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"))); } // the real call if (method.GetType().GetName() == "void") { if (options.GenTraces()) { statements->Add(tryStatement); tryStatement->statements->Add(realCall); statements->Add(finallyStatement); } else { statements->Add(realCall); } if (!oneway) { // report that there were no exceptions MethodCall* ex = new MethodCall(transact_reply, "writeNoException", 0); statements->Add(ex); } } else { Variable* _result = new Variable(method.GetType().GetLanguageType()->JavaType(), "_result", method.GetType().IsArray() ? 1 : 0); if (options.GenTraces()) { statements->Add(new VariableDeclaration(_result)); statements->Add(tryStatement); tryStatement->statements->Add(new Assignment(_result, realCall)); statements->Add(finallyStatement); } else { statements->Add(new VariableDeclaration(_result, realCall)); } if (!oneway) { // report that there were no exceptions MethodCall* ex = new MethodCall(transact_reply, "writeNoException", 0); statements->Add(ex); } // marshall the return value generate_write_to_parcel(method.GetType(), statements, _result, transact_reply, true, types->typenames_); } // out parameters int i = 0; for (const std::unique_ptr& arg : method.GetArguments()) { Variable* v = stubArgs.Get(i++); if (arg->GetDirection() & AidlArgument::OUT_DIR) { generate_write_to_parcel(arg->GetType(), statements, v, transact_reply, true, types->typenames_); } } // return true statements->Add(new ReturnStatement(TRUE_VALUE)); } static void generate_stub_case(const AidlInterface& iface, const AidlMethod& method, const std::string& transactCodeName, bool oneway, StubClass* stubClass, JavaTypeNamespace* types, const Options& options) { Case* c = new Case(transactCodeName); generate_stub_code(iface, method, oneway, stubClass->transact_data, stubClass->transact_reply, types, c->statements, stubClass, options); stubClass->transact_switch->cases.push_back(c); } static void generate_stub_case_outline(const AidlInterface& iface, const AidlMethod& method, const std::string& transactCodeName, bool oneway, StubClass* stubClass, JavaTypeNamespace* types, const Options& options) { std::string outline_name = "onTransact$" + method.GetName() + "$"; // Generate an "outlined" method with the actual code. { Variable* transact_data = new Variable(types->ParcelType()->JavaType(), "data"); Variable* transact_reply = new Variable(types->ParcelType()->JavaType(), "reply"); Method* onTransact_case = new Method; onTransact_case->modifiers = PRIVATE; onTransact_case->returnType = types->BoolType()->JavaType(); onTransact_case->name = outline_name; onTransact_case->parameters.push_back(transact_data); onTransact_case->parameters.push_back(transact_reply); onTransact_case->statements = new StatementBlock; onTransact_case->exceptions.push_back(types->RemoteExceptionType()->JavaType()); stubClass->elements.push_back(onTransact_case); generate_stub_code(iface, method, oneway, transact_data, transact_reply, types, onTransact_case->statements, stubClass, options); } // Generate the case dispatch. { Case* c = new Case(transactCodeName); MethodCall* helper_call = new MethodCall(THIS_VALUE, outline_name, 2, stubClass->transact_data, stubClass->transact_reply); c->statements->Add(new ReturnStatement(helper_call)); stubClass->transact_switch->cases.push_back(c); } } static std::unique_ptr generate_proxy_method( const AidlInterface& iface, const AidlMethod& method, const std::string& transactCodeName, bool oneway, ProxyClass* proxyClass, JavaTypeNamespace* types, const Options& options) { std::unique_ptr proxy(new Method); proxy->comment = method.GetComments(); proxy->modifiers = PUBLIC | OVERRIDE; proxy->returnType = method.GetType().GetLanguageType()->JavaType(); 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()->JavaType(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0)); } proxy->exceptions.push_back(types->RemoteExceptionType()->JavaType()); // the parcels Variable* _data = new Variable(types->ParcelType()->JavaType(), "_data"); proxy->statements->Add( new VariableDeclaration(_data, new MethodCall(types->ParcelType()->JavaType(), "obtain"))); Variable* _reply = nullptr; if (!oneway) { _reply = new Variable(types->ParcelType()->JavaType(), "_reply"); proxy->statements->Add( new VariableDeclaration(_reply, new MethodCall(types->ParcelType()->JavaType(), "obtain"))); } // the return value Variable* _result = nullptr; 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); if (options.GenTraces()) { tryStatement->statements->Add(new MethodCall( new LiteralExpression("android.os.Trace"), "traceBegin", 2, new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"), new StringLiteralExpression(iface.GetName() + "::" + method.GetName() + "::client"))); } // 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->JavaType(), 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(arg->GetType(), tryStatement->statements, v, _data, false, types->typenames_); } else { delete v; } } // the transact call unique_ptr 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"))); unique_ptr _status(new Variable(types->BoolType()->JavaType(), "_status")); tryStatement->statements->Add(new VariableDeclaration(_status.release(), call.release())); // If the transaction returns false, which means UNKNOWN_TRANSACTION, fall // back to the local method in the default impl, if set before. vector arg_names; for (const auto& arg : method.GetArguments()) { arg_names.emplace_back(arg->GetName()); } bool has_return_type = method.GetType().GetName() != "void"; tryStatement->statements->Add(new LiteralStatement( android::base::StringPrintf(has_return_type ? "if (!_status && getDefaultImpl() != null) {\n" " return getDefaultImpl().%s(%s);\n" "}\n" : "if (!_status && getDefaultImpl() != null) {\n" " getDefaultImpl().%s(%s);\n" " return;\n" "}\n", method.GetName().c_str(), Join(arg_names, ", ").c_str()))); // throw back exceptions. if (_reply) { MethodCall* ex = new MethodCall(_reply, "readException", 0); tryStatement->statements->Add(ex); } // returning and cleanup if (_reply != nullptr) { // keep this across return value and arguments in order to create the // classloader at most once. bool is_classloader_created = false; if (_result != nullptr) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); CodeGeneratorContext context{.writer = *(writer.get()), .typenames = types->typenames_, .type = method.GetType(), .var = _result->name, .parcel = _reply->name, .is_classloader_created = &is_classloader_created}; CreateFromParcelFor(context); writer->Close(); tryStatement->statements->Add(new LiteralStatement(code)); } // the out/inout parameters for (const std::unique_ptr& arg : method.GetArguments()) { if (arg->GetDirection() & AidlArgument::OUT_DIR) { string code; CodeWriterPtr writer = CodeWriter::ForString(&code); CodeGeneratorContext context{.writer = *(writer.get()), .typenames = types->typenames_, .type = arg->GetType(), .var = arg->GetName(), .parcel = _reply->name, .is_classloader_created = &is_classloader_created}; ReadFromParcelFor(context); writer->Close(); tryStatement->statements->Add(new LiteralStatement(code)); } } finallyStatement->statements->Add(new MethodCall(_reply, "recycle")); } finallyStatement->statements->Add(new MethodCall(_data, "recycle")); if (options.GenTraces()) { finallyStatement->statements->Add(new MethodCall( new LiteralExpression("android.os.Trace"), "traceEnd", 1, new LiteralExpression("android.os.Trace.TRACE_TAG_AIDL"))); } if (_result != nullptr) { proxy->statements->Add(new ReturnStatement(_result)); } return proxy; } static void generate_methods(const AidlInterface& iface, const AidlMethod& method, Class* interface, StubClass* stubClass, ProxyClass* proxyClass, int index, JavaTypeNamespace* types, const Options& options) { const bool oneway = method.IsOneway(); // == the TRANSACT_ constant ============================================= string transactCodeName = "TRANSACTION_"; transactCodeName += method.GetName(); Field* transactCode = new Field(STATIC | FINAL, new Variable(types->IntType()->JavaType(), transactCodeName)); transactCode->value = StringPrintf("(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index); stubClass->elements.push_back(transactCode); // getTransactionName if (options.GenTransactionNames()) { Case* c = new Case(transactCodeName); c->statements->Add(new ReturnStatement(new StringLiteralExpression(method.GetName()))); stubClass->code_to_method_name_switch->cases.push_back(c); } // == the declaration in the interface =================================== ClassElement* decl; if (method.IsUserDefined()) { decl = generate_interface_method(method, types).release(); } else { if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) { std::ostringstream code; code << "public int " << kGetInterfaceVersion << "() " << "throws android.os.RemoteException;\n"; decl = new LiteralClassElement(code.str()); } } interface->elements.push_back(decl); // == the stub method ==================================================== if (method.IsUserDefined()) { bool outline_stub = stubClass->transact_outline && stubClass->outline_methods.count(&method) != 0; if (outline_stub) { generate_stub_case_outline(iface, method, transactCodeName, oneway, stubClass, types, options); } else { generate_stub_case(iface, method, transactCodeName, oneway, stubClass, types, options); } } else { if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) { Case* c = new Case(transactCodeName); std::ostringstream code; code << "data.enforceInterface(descriptor);\n" << "reply.writeNoException();\n" << "reply.writeInt(" << kGetInterfaceVersion << "());\n" << "return true;\n"; c->statements->Add(new LiteralStatement(code.str())); stubClass->transact_switch->cases.push_back(c); } } // == the proxy method =================================================== ClassElement* proxy = nullptr; if (method.IsUserDefined()) { proxy = generate_proxy_method(iface, method, transactCodeName, oneway, proxyClass, types, options) .release(); } else { if (method.GetName() == kGetInterfaceVersion && options.Version() > 0) { std::ostringstream code; code << "@Override\n" << "public int " << kGetInterfaceVersion << "()" << " throws " << "android.os.RemoteException {\n" << " if (mCachedVersion == -1) {\n" << " android.os.Parcel data = android.os.Parcel.obtain();\n" << " android.os.Parcel reply = android.os.Parcel.obtain();\n" << " try {\n" << " data.writeInterfaceToken(DESCRIPTOR);\n" << " mRemote.transact(Stub." << transactCodeName << ", " << "data, reply, 0);\n" << " reply.readException();\n" << " mCachedVersion = reply.readInt();\n" << " } finally {\n" << " reply.recycle();\n" << " data.recycle();\n" << " }\n" << " }\n" << " return mCachedVersion;\n" << "}\n"; proxy = new LiteralClassElement(code.str()); } } if (proxy != nullptr) { proxyClass->elements.push_back(proxy); } } 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, stub->get_transact_descriptor(types, nullptr))); 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()->JavaType(); getDesc->returnTypeDimension = 0; getDesc->name = "getInterfaceDescriptor"; getDesc->statements = new StatementBlock; getDesc->statements->Add( new ReturnStatement(new LiteralExpression("DESCRIPTOR"))); proxy->elements.push_back(getDesc); } // Check whether (some) methods in this interface should be "outlined," that // is, have specific onTransact methods for certain cases. Set up StubClass // metadata accordingly. // // Outlining will be enabled if the interface has more than outline_threshold // methods. In that case, the methods are sorted by number of arguments // (so that more "complex" methods come later), and the first non_outline_count // number of methods not outlined (are kept in the onTransact() method). // // Requirements: non_outline_count <= outline_threshold. static void compute_outline_methods(const AidlInterface* iface, StubClass* stub, size_t outline_threshold, size_t non_outline_count) { CHECK_LE(non_outline_count, outline_threshold); // We'll outline (create sub methods) if there are more than min_methods // cases. stub->transact_outline = iface->GetMethods().size() > outline_threshold; if (stub->transact_outline) { stub->all_method_count = iface->GetMethods().size(); std::vector methods; methods.reserve(iface->GetMethods().size()); for (const std::unique_ptr& ptr : iface->GetMethods()) { methods.push_back(ptr.get()); } std::stable_sort( methods.begin(), methods.end(), [](const AidlMethod* m1, const AidlMethod* m2) { return m1->GetArguments().size() < m2->GetArguments().size(); }); stub->outline_methods.insert(methods.begin() + non_outline_count, methods.end()); } } static unique_ptr generate_default_impl_method(const AidlMethod& method) { unique_ptr default_method(new Method); default_method->comment = method.GetComments(); default_method->modifiers = PUBLIC | OVERRIDE; default_method->returnType = method.GetType().GetLanguageType()->JavaType(); default_method->returnTypeDimension = method.GetType().IsArray() ? 1 : 0; default_method->name = method.GetName(); default_method->statements = new StatementBlock; for (const auto& arg : method.GetArguments()) { default_method->parameters.push_back( new Variable(arg->GetType().GetLanguageType()->JavaType(), arg->GetName(), arg->GetType().IsArray() ? 1 : 0)); } default_method->exceptions.push_back(method.GetType() .GetLanguageType() ->GetTypeNamespace() ->RemoteExceptionType() ->JavaType()); if (method.GetType().GetName() != "void") { const string& defaultValue = DefaultJavaValueOf(method.GetType()); default_method->statements->Add( new LiteralStatement(StringPrintf("return %s;\n", defaultValue.c_str()))); } return default_method; } static unique_ptr generate_default_impl_class(const AidlInterface& iface, const Options& options) { unique_ptr default_class(new Class); default_class->comment = "/** Default implementation for " + iface.GetName() + ". */"; default_class->modifiers = PUBLIC | STATIC; default_class->what = Class::CLASS; default_class->type = iface.GetLanguageType()->GetDefaultImpl()->JavaType(); default_class->interfaces.emplace_back(iface.GetLanguageType()->JavaType()); for (const auto& m : iface.GetMethods()) { if (m->IsUserDefined()) { default_class->elements.emplace_back(generate_default_impl_method(*(m.get())).release()); } else { if (m->GetName() == kGetInterfaceVersion && options.Version() > 0) { // This is called only when the remote side is not implementing this // method, which is impossible in normal case, because this method is // automatically declared in the interface class and not implementing // it in the remote side is causing compilation error. But if the remote // side somehow managed to not implement it, that's an error and we // report the case by returning -1 here. std::ostringstream code; code << "@Override\n" << "public int " << kGetInterfaceVersion << "() {\n" << " return -1;\n" << "}\n"; default_class->elements.emplace_back(new LiteralClassElement(code.str())); } } } default_class->elements.emplace_back( new LiteralClassElement("@Override\n" "public android.os.IBinder asBinder() {\n" " return null;\n" "}\n")); return default_class; } Class* generate_binder_interface_class(const AidlInterface* iface, JavaTypeNamespace* types, const Options& options) { 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->JavaType(); interface->interfaces.push_back(types->IInterfaceType()->JavaType()); interface->annotations = generate_java_annotations(*iface); if (options.Version()) { std::ostringstream code; code << "/**\n" << " * The version of this interface that the caller is built against.\n" << " * This might be different from what {@link #getInterfaceVersion()\n" << " * getInterfaceVersion} returns as that is the version of the interface\n" << " * that the remote object is implementing.\n" << " */\n" << "public static final int VERSION = " << options.Version() << ";\n"; interface->elements.emplace_back(new LiteralClassElement(code.str())); } // the default impl class Class* default_impl = generate_default_impl_class(*iface, options).release(); interface->elements.emplace_back(default_impl); // the stub inner class StubClass* stub = new StubClass(interfaceType->GetStub(), interfaceType, types, options); interface->elements.push_back(stub); compute_outline_methods(iface, stub, options.onTransact_outline_threshold_, options.onTransact_non_outline_count_); // the proxy inner class ProxyClass* proxy = new ProxyClass(types, interfaceType->GetProxy(), interfaceType, options); 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& constant : iface->GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); switch (value.GetType()) { case AidlConstantValue::Type::STRING: { generate_string_constant(interface, constant->GetName(), constant->ValueString(ConstantValueDecorator)); break; } case AidlConstantValue::Type::INTEGRAL: case AidlConstantValue::Type::HEXIDECIMAL: { generate_int_constant(interface, constant->GetName(), constant->ValueString(ConstantValueDecorator)); break; } default: { LOG(FATAL) << "Unrecognized constant type: " << static_cast(value.GetType()); } } } // all the declared methods of the interface for (const auto& item : iface->GetMethods()) { generate_methods(*iface, *item, interface, stub, proxy, item->GetId(), types, options); } // additional static methods for the default impl set/get to the // stub class. Can't add them to the interface as the generated java files // may be compiled with Java < 1.7 where static interface method isn't // supported. // TODO(b/111417145) make this conditional depending on the Java language // version requested const string i_name = interfaceType->JavaType(); stub->elements.emplace_back(new LiteralClassElement( StringPrintf("public static boolean setDefaultImpl(%s impl) {\n" " if (Stub.Proxy.sDefaultImpl == null && impl != null) {\n" " Stub.Proxy.sDefaultImpl = impl;\n" " return true;\n" " }\n" " return false;\n" "}\n", i_name.c_str()))); stub->elements.emplace_back( new LiteralClassElement(StringPrintf("public static %s getDefaultImpl() {\n" " return Stub.Proxy.sDefaultImpl;\n" "}\n", i_name.c_str()))); // the static field is defined in the proxy class, not in the interface class // because all fields in an interface class are by default final. proxy->elements.emplace_back(new LiteralClassElement( StringPrintf("public static %s sDefaultImpl;\n", i_name.c_str()))); stub->finish(); return interface; } } // namespace java } // namespace android } // namespace aidl generate_ndk.cpp0100644 0000000 0000000 00000102437 13755771705 012767 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "generate_ndk.h" #include "aidl.h" #include "aidl_language.h" #include "aidl_to_cpp_common.h" #include "aidl_to_ndk.h" #include namespace android { namespace aidl { namespace ndk { static constexpr const char* kClazz = "_g_aidl_clazz"; static constexpr const char* kDescriptor = "descriptor"; static constexpr const char* kVersion = "version"; static constexpr const char* kCacheVariable = "_aidl_cached_value"; using namespace internals; using cpp::ClassNames; void GenerateNdkInterface(const string& output_file, const Options& options, const AidlTypenames& types, const AidlInterface& defined_type, const IoDelegate& io_delegate) { const string i_header = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::RAW); unique_ptr i_writer(io_delegate.GetCodeWriter(i_header)); GenerateInterfaceHeader(*i_writer, types, defined_type, options); CHECK(i_writer->Close()); const string bp_header = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::CLIENT); unique_ptr bp_writer(io_delegate.GetCodeWriter(bp_header)); GenerateClientHeader(*bp_writer, types, defined_type, options); CHECK(bp_writer->Close()); const string bn_header = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::SERVER); unique_ptr bn_writer(io_delegate.GetCodeWriter(bn_header)); GenerateServerHeader(*bn_writer, types, defined_type, options); CHECK(bn_writer->Close()); unique_ptr source_writer = io_delegate.GetCodeWriter(output_file); GenerateSource(*source_writer, types, defined_type, options); CHECK(source_writer->Close()); } void GenerateNdkParcel(const string& output_file, const Options& options, const AidlTypenames& types, const AidlStructuredParcelable& defined_type, const IoDelegate& io_delegate) { const string header_path = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::RAW); unique_ptr header_writer(io_delegate.GetCodeWriter(header_path)); GenerateParcelHeader(*header_writer, types, defined_type, options); CHECK(header_writer->Close()); const string bp_header = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::CLIENT); unique_ptr bp_writer(io_delegate.GetCodeWriter(bp_header)); *bp_writer << "#error TODO(b/111362593) defined_types do not have bp classes\n"; CHECK(bp_writer->Close()); const string bn_header = options.OutputHeaderDir() + NdkHeaderFile(defined_type, ClassNames::SERVER); unique_ptr bn_writer(io_delegate.GetCodeWriter(bn_header)); *bn_writer << "#error TODO(b/111362593) defined_types do not have bn classes\n"; CHECK(bn_writer->Close()); unique_ptr source_writer = io_delegate.GetCodeWriter(output_file); GenerateParcelSource(*source_writer, types, defined_type, options); CHECK(source_writer->Close()); } void GenerateNdkParcelDeclaration(const std::string& filename, const IoDelegate& io_delegate) { CodeWriterPtr code_writer = io_delegate.GetCodeWriter(filename); *code_writer << "// This file is intentionally left blank as placeholder for parcel declaration.\n"; CHECK(code_writer->Close()); } void GenerateNdk(const string& output_file, const Options& options, const AidlTypenames& types, const AidlDefinedType& defined_type, const IoDelegate& io_delegate) { const AidlStructuredParcelable* parcelable = defined_type.AsStructuredParcelable(); if (parcelable != nullptr) { GenerateNdkParcel(output_file, options, types, *parcelable, io_delegate); return; } const AidlParcelable* parcelable_decl = defined_type.AsParcelable(); if (parcelable_decl != nullptr) { GenerateNdkParcelDeclaration(output_file, io_delegate); return; } const AidlInterface* interface = defined_type.AsInterface(); if (interface != nullptr) { GenerateNdkInterface(output_file, options, types, *interface, io_delegate); return; } CHECK(false) << "Unrecognized type sent for cpp generation."; } namespace internals { void EnterNdkNamespace(CodeWriter& out, const AidlDefinedType& defined_type) { out << "namespace aidl {\n"; cpp::EnterNamespace(out, defined_type); } void LeaveNdkNamespace(CodeWriter& out, const AidlDefinedType& defined_type) { cpp::LeaveNamespace(out, defined_type); out << "} // namespace aidl\n"; } static void StatusCheckGoto(CodeWriter& out) { out << "if (_aidl_ret_status != STATUS_OK) goto _aidl_error;\n\n"; } static void StatusCheckBreak(CodeWriter& out) { out << "if (_aidl_ret_status != STATUS_OK) break;\n\n"; } static void StatusCheckReturn(CodeWriter& out) { out << "if (_aidl_ret_status != STATUS_OK) return _aidl_ret_status;\n\n"; } static void GenerateHeaderIncludes(CodeWriter& out, const AidlTypenames& types, const AidlDefinedType& defined_type) { out << "#include \n"; types.IterateTypes([&](const AidlDefinedType& other_defined_type) { if (&other_defined_type == &defined_type) return; if (other_defined_type.AsInterface() != nullptr) { out << "#include <" << NdkHeaderFile(other_defined_type, ClassNames::RAW, false /*use_os_sep*/) << ">\n"; } else if (other_defined_type.AsStructuredParcelable() != nullptr) { out << "#include <" << NdkHeaderFile(other_defined_type, ClassNames::BASE, false /*use_os_sep*/) << ">\n"; } else if (other_defined_type.AsParcelable() != nullptr) { out << "#include \"" << other_defined_type.AsParcelable()->GetCppHeader() << "\"\n"; } else { AIDL_FATAL(defined_type) << "Unrecognized type."; } }); } static void GenerateSourceIncludes(CodeWriter& out, const AidlTypenames& types, const AidlDefinedType& /*defined_type*/) { types.IterateTypes([&](const AidlDefinedType& a_defined_type) { if (a_defined_type.AsInterface() != nullptr) { out << "#include <" << NdkHeaderFile(a_defined_type, ClassNames::CLIENT, false /*use_os_sep*/) << ">\n"; out << "#include <" << NdkHeaderFile(a_defined_type, ClassNames::SERVER, false /*use_os_sep*/) << ">\n"; out << "#include <" << NdkHeaderFile(a_defined_type, ClassNames::RAW, false /*use_os_sep*/) << ">\n"; } }); } static void GenerateConstantDeclarations(CodeWriter& out, const AidlInterface& interface) { for (const auto& constant : interface.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); if (value.GetType() == AidlConstantValue::Type::STRING) { out << "static const char* " << constant->GetName() << ";\n"; } } out << "\n"; bool hasIntegralConstant = false; for (const auto& constant : interface.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); if (value.GetType() == AidlConstantValue::Type::HEXIDECIMAL || value.GetType() == AidlConstantValue::Type::INTEGRAL) { hasIntegralConstant = true; break; } } if (hasIntegralConstant) { out << "enum : int32_t {\n"; out.Indent(); for (const auto& constant : interface.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); if (value.GetType() == AidlConstantValue::Type::HEXIDECIMAL || value.GetType() == AidlConstantValue::Type::INTEGRAL) { out << constant->GetName() << " = " << constant->ValueString(AidlConstantValueDecorator) << ",\n"; } } out.Dedent(); out << "};\n"; } } static void GenerateConstantDefinitions(CodeWriter& out, const AidlInterface& interface) { const std::string clazz = ClassName(interface, ClassNames::INTERFACE); for (const auto& constant : interface.GetConstantDeclarations()) { const AidlConstantValue& value = constant->GetValue(); if (value.GetType() == AidlConstantValue::Type::STRING) { out << "const char* " << clazz << "::" << constant->GetName() << " = " << constant->ValueString(AidlConstantValueDecorator) << ";\n"; } } } void GenerateSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { GenerateSourceIncludes(out, types, defined_type); out << "\n"; EnterNdkNamespace(out, defined_type); GenerateClassSource(out, types, defined_type, options); GenerateClientSource(out, types, defined_type, options); GenerateServerSource(out, types, defined_type, options); GenerateInterfaceSource(out, types, defined_type, options); LeaveNdkNamespace(out, defined_type); } static std::string MethodId(const AidlMethod& m) { return "(FIRST_CALL_TRANSACTION + " + std::to_string(m.GetId()) + " /*" + m.GetName() + "*/)"; } static void GenerateClientMethodDefinition(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const AidlMethod& method, const std::optional return_value_cached_to, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::CLIENT); out << NdkMethodDecl(types, method, clazz) << " {\n"; out.Indent(); out << "binder_status_t _aidl_ret_status = STATUS_OK;\n"; out << "::ndk::ScopedAStatus _aidl_status;\n"; if (return_value_cached_to) { out << "if (" << *return_value_cached_to << " != -1) {\n"; out.Indent(); out << "*_aidl_return = " << *return_value_cached_to << ";\n" << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n" << "return _aidl_status;\n"; out.Dedent(); out << "}\n"; } out << "::ndk::ScopedAParcel _aidl_in;\n"; out << "::ndk::ScopedAParcel _aidl_out;\n"; out << "\n"; if (options.GenLog()) { out << cpp::GenLogBeforeExecute(ClassName(defined_type, ClassNames::CLIENT), method, false /* isServer */, true /* isNdk */); } out << "_aidl_ret_status = AIBinder_prepareTransaction(asBinder().get(), _aidl_in.getR());\n"; StatusCheckGoto(out); for (const auto& arg : method.GetArguments()) { const std::string var_name = cpp::BuildVarName(*arg); if (arg->IsIn()) { out << "_aidl_ret_status = "; const std::string prefix = (arg->IsOut() ? "*" : ""); WriteToParcelFor({out, types, arg->GetType(), "_aidl_in.get()", prefix + var_name}); out << ";\n"; StatusCheckGoto(out); } else if (arg->IsOut() && arg->GetType().IsArray()) { out << "_aidl_ret_status = ::ndk::AParcel_writeVectorSize(_aidl_in.get(), *" << var_name << ");\n"; } } out << "_aidl_ret_status = AIBinder_transact(\n"; out.Indent(); out << "asBinder().get(),\n"; out << MethodId(method) << ",\n"; out << "_aidl_in.getR(),\n"; out << "_aidl_out.getR(),\n"; out << (method.IsOneway() ? "FLAG_ONEWAY" : "0") << ");\n"; out.Dedent(); // If the method is not implmented in the server side but the client has // provided the default implementation, call it instead of failing hard. const std::string iface = ClassName(defined_type, ClassNames::INTERFACE); out << "if (_aidl_ret_status == STATUS_UNKNOWN_TRANSACTION && "; out << iface << "::getDefaultImpl()) {\n"; out.Indent(); out << "return " << iface << "::getDefaultImpl()->" << method.GetName() << "("; out << NdkArgList(types, method, FormatArgNameOnly) << ");\n"; out.Dedent(); out << "}\n"; StatusCheckGoto(out); if (!method.IsOneway()) { out << "_aidl_ret_status = AParcel_readStatusHeader(_aidl_out.get(), _aidl_status.getR());\n"; StatusCheckGoto(out); out << "if (!AStatus_isOk(_aidl_status.get())) return _aidl_status;\n\n"; } if (method.GetType().GetName() != "void") { out << "_aidl_ret_status = "; ReadFromParcelFor({out, types, method.GetType(), "_aidl_out.get()", "_aidl_return"}); out << ";\n"; StatusCheckGoto(out); if (return_value_cached_to) { out << *return_value_cached_to << " = *_aidl_return;\n"; } } for (const AidlArgument* arg : method.GetOutArguments()) { out << "_aidl_ret_status = "; ReadFromParcelFor({out, types, arg->GetType(), "_aidl_out.get()", cpp::BuildVarName(*arg)}); out << ";\n"; StatusCheckGoto(out); } out << "_aidl_error:\n"; out << "_aidl_status.set(AStatus_fromStatus(_aidl_ret_status));\n"; if (options.GenLog()) { out << cpp::GenLogAfterExecute(ClassName(defined_type, ClassNames::CLIENT), defined_type, method, "_aidl_status", "_aidl_return", false /* isServer */, true /* isNdk */); } out << "return _aidl_status;\n"; out.Dedent(); out << "}\n"; } static void GenerateServerCaseDefinition(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const AidlMethod& method, const Options& options) { out << "case " << MethodId(method) << ": {\n"; out.Indent(); for (const auto& arg : method.GetArguments()) { out << NdkNameOf(types, arg->GetType(), StorageMode::STACK) << " " << cpp::BuildVarName(*arg) << ";\n"; } if (method.GetType().GetName() != "void") { out << NdkNameOf(types, method.GetType(), StorageMode::STACK) << " _aidl_return;\n"; } out << "\n"; for (const auto& arg : method.GetArguments()) { const std::string var_name = cpp::BuildVarName(*arg); if (arg->IsIn()) { out << "_aidl_ret_status = "; ReadFromParcelFor({out, types, arg->GetType(), "_aidl_in", "&" + var_name}); out << ";\n"; StatusCheckBreak(out); } else if (arg->IsOut() && arg->GetType().IsArray()) { out << "_aidl_ret_status = ::ndk::AParcel_resizeVector(_aidl_in, &" << var_name << ");\n"; } } if (options.GenLog()) { out << cpp::GenLogBeforeExecute(ClassName(defined_type, ClassNames::SERVER), method, true /* isServer */, true /* isNdk */); } out << "::ndk::ScopedAStatus _aidl_status = _aidl_impl->" << method.GetName() << "(" << NdkArgList(types, method, FormatArgForCall) << ");\n"; if (options.GenLog()) { out << cpp::GenLogAfterExecute(ClassName(defined_type, ClassNames::SERVER), defined_type, method, "_aidl_status", "_aidl_return", true /* isServer */, true /* isNdk */); } if (method.IsOneway()) { // For a oneway transaction, the kernel will have already returned a result. This is for the // in-process case when a oneway transaction is parceled/unparceled in the same process. out << "_aidl_ret_status = STATUS_OK;\n"; } else { out << "_aidl_ret_status = AParcel_writeStatusHeader(_aidl_out, _aidl_status.get());\n"; StatusCheckBreak(out); out << "if (!AStatus_isOk(_aidl_status.get())) break;\n\n"; if (method.GetType().GetName() != "void") { out << "_aidl_ret_status = "; WriteToParcelFor({out, types, method.GetType(), "_aidl_out", "_aidl_return"}); out << ";\n"; StatusCheckBreak(out); } for (const AidlArgument* arg : method.GetOutArguments()) { out << "_aidl_ret_status = "; WriteToParcelFor({out, types, arg->GetType(), "_aidl_out", cpp::BuildVarName(*arg)}); out << ";\n"; StatusCheckBreak(out); } } out << "break;\n"; out.Dedent(); out << "}\n"; } void GenerateClassSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE); const std::string bn_clazz = ClassName(defined_type, ClassNames::SERVER); out << "static binder_status_t " << "_aidl_onTransact" << "(AIBinder* _aidl_binder, transaction_code_t _aidl_code, const AParcel* _aidl_in, " "AParcel* _aidl_out) {\n"; out.Indent(); out << "(void)_aidl_in;\n"; out << "(void)_aidl_out;\n"; out << "binder_status_t _aidl_ret_status = STATUS_UNKNOWN_TRANSACTION;\n"; if (!defined_type.GetMethods().empty()) { // we know this cast is valid because this method is only called by the ICInterface // AIBinder_Class object which is associated with this class. out << "std::shared_ptr<" << bn_clazz << "> _aidl_impl = std::static_pointer_cast<" << bn_clazz << ">(::ndk::ICInterface::asInterface(_aidl_binder));\n"; out << "switch (_aidl_code) {\n"; out.Indent(); for (const auto& method : defined_type.GetMethods()) { GenerateServerCaseDefinition(out, types, defined_type, *method, options); } out.Dedent(); out << "}\n"; } else { out << "(void)_aidl_binder;\n"; out << "(void)_aidl_code;\n"; } out << "return _aidl_ret_status;\n"; out.Dedent(); out << "};\n\n"; out << "static AIBinder_Class* " << kClazz << " = ::ndk::ICInterface::defineClass(" << clazz << "::" << kDescriptor << ", _aidl_onTransact);\n\n"; } void GenerateClientSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::CLIENT); out << clazz << "::" << clazz << "(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}\n"; out << clazz << "::~" << clazz << "() {}\n"; if (options.GenLog()) { out << "std::function " << clazz << "::logFunc;\n"; } out << "\n"; for (const auto& method : defined_type.GetMethods()) { // Only getInterfaceVersion can use cache. const bool cacheable = !method->IsUserDefined() && method->GetName() == kGetInterfaceVersion && options.Version() > 0; const auto return_value_cached_to = cacheable ? std::make_optional(kCacheVariable) : std::nullopt; GenerateClientMethodDefinition(out, types, defined_type, *method, return_value_cached_to, options); } } void GenerateServerSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::SERVER); const std::string iface = ClassName(defined_type, ClassNames::INTERFACE); out << "// Source for " << clazz << "\n"; out << clazz << "::" << clazz << "() {}\n"; out << clazz << "::~" << clazz << "() {}\n"; if (options.GenLog()) { out << "std::function " << clazz << "::logFunc;\n"; } out << "::ndk::SpAIBinder " << clazz << "::createBinder() {\n"; out.Indent(); out << "AIBinder* binder = AIBinder_new(" << kClazz << ", static_cast(this));\n"; out << "return ::ndk::SpAIBinder(binder);\n"; out.Dedent(); out << "}\n"; // Implement the meta methods for (const auto& method : defined_type.GetMethods()) { if (method->IsUserDefined()) { continue; } if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << NdkMethodDecl(types, *method, clazz) << " {\n"; out.Indent(); out << "*_aidl_return = " << iface << "::" << kVersion << ";\n"; out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n"; out.Dedent(); out << "}\n"; } } } void GenerateInterfaceSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE); const std::string bp_clazz = ClassName(defined_type, ClassNames::CLIENT); out << "// Source for " << clazz << "\n"; out << "const char* " << clazz << "::" << kDescriptor << " = \"" << defined_type.GetCanonicalName() << "\";\n"; out << clazz << "::" << clazz << "() {}\n"; out << clazz << "::~" << clazz << "() {}\n"; out << "\n"; GenerateConstantDefinitions(out, defined_type); out << "\n"; out << "std::shared_ptr<" << clazz << "> " << clazz << "::fromBinder(const ::ndk::SpAIBinder& binder) {\n"; out.Indent(); out << "if (!AIBinder_associateClass(binder.get(), " << kClazz << ")) { return nullptr; }\n"; out << "std::shared_ptr<::ndk::ICInterface> interface = " "::ndk::ICInterface::asInterface(binder.get());\n"; out << "if (interface) {\n"; out.Indent(); out << "return std::static_pointer_cast<" << clazz << ">(interface);\n"; out.Dedent(); out << "}\n"; out << "return (new " << bp_clazz << "(binder))->ref<" << clazz << ">();\n"; out.Dedent(); out << "}\n\n"; out << "binder_status_t " << clazz << "::writeToParcel(AParcel* parcel, const std::shared_ptr<" << clazz << ">& instance) {\n"; out.Indent(); out << "return AParcel_writeStrongBinder(parcel, instance ? instance->asBinder().get() : " "nullptr);\n"; out.Dedent(); out << "}\n"; out << "binder_status_t " << clazz << "::readFromParcel(const AParcel* parcel, std::shared_ptr<" << clazz << ">* instance) {\n"; out.Indent(); out << "::ndk::SpAIBinder binder;\n"; out << "binder_status_t status = AParcel_readStrongBinder(parcel, binder.getR());\n"; out << "if (status != STATUS_OK) return status;\n"; out << "*instance = " << clazz << "::fromBinder(binder);\n"; out << "return STATUS_OK;\n"; out.Dedent(); out << "}\n"; // defintion for static member setDefaultImpl out << "bool " << clazz << "::setDefaultImpl(std::shared_ptr<" << clazz << "> impl) {\n"; out.Indent(); out << "if (!" << clazz << "::default_impl && impl) {\n"; out.Indent(); out << clazz << "::default_impl = impl;\n"; out << "return true;\n"; out.Dedent(); out << "}\n"; out << "return false;\n"; out.Dedent(); out << "}\n"; // definition for static member getDefaultImpl out << "const std::shared_ptr<" << clazz << ">& " << clazz << "::getDefaultImpl() {\n"; out.Indent(); out << "return " << clazz << "::default_impl;\n"; out.Dedent(); out << "}\n"; // definition for the static field default_impl out << "std::shared_ptr<" << clazz << "> " << clazz << "::default_impl = nullptr;\n"; // default implementation for the Default class members const std::string defaultClazz = clazz + "Default"; for (const auto& method : defined_type.GetMethods()) { if (method->IsUserDefined()) { out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "(" << NdkArgList(types, *method, FormatArgNameUnused) << ") {\n"; out.Indent(); out << "::ndk::ScopedAStatus _aidl_status;\n"; out << "_aidl_status.set(AStatus_fromStatus(STATUS_UNKNOWN_TRANSACTION));\n"; out << "return _aidl_status;\n"; out.Dedent(); out << "}\n"; } else { if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << "::ndk::ScopedAStatus " << defaultClazz << "::" << method->GetName() << "(" << "int32_t* _aidl_return) {\n"; out.Indent(); out << "*_aidl_return = 0;\n"; out << "return ::ndk::ScopedAStatus(AStatus_newOk());\n"; out.Dedent(); out << "}\n"; } } } out << "::ndk::SpAIBinder " << defaultClazz << "::asBinder() {\n"; out.Indent(); out << "return ::ndk::SpAIBinder();\n"; out.Dedent(); out << "}\n"; out << "bool " << defaultClazz << "::isRemote() {\n"; out.Indent(); out << "return false;\n"; out.Dedent(); out << "}\n"; } void GenerateClientHeader(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::CLIENT); out << "#pragma once\n\n"; out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::RAW, false /*use_os_sep*/) << "\"\n"; out << "\n"; out << "#include \n"; if (options.GenLog()) { out << "#include \n"; out << "#include \n"; out << "#include \n"; out << "#include \n"; } out << "\n"; EnterNdkNamespace(out, defined_type); out << "class " << clazz << " : public ::ndk::BpCInterface<" << ClassName(defined_type, ClassNames::INTERFACE) << "> {\n"; out << "public:\n"; out.Indent(); out << clazz << "(const ::ndk::SpAIBinder& binder);\n"; out << "virtual ~" << clazz << "();\n"; out << "\n"; for (const auto& method : defined_type.GetMethods()) { out << NdkMethodDecl(types, *method) << " override;\n"; } if (options.Version() > 0) { out << "int32_t " << kCacheVariable << " = -1;\n"; } if (options.GenLog()) { out << "static std::function logFunc;\n"; } out.Dedent(); out << "};\n"; LeaveNdkNamespace(out, defined_type); } void GenerateServerHeader(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::SERVER); const std::string iface = ClassName(defined_type, ClassNames::INTERFACE); out << "#pragma once\n\n"; out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::RAW, false /*use_os_sep*/) << "\"\n"; out << "\n"; out << "#include \n"; out << "\n"; EnterNdkNamespace(out, defined_type); out << "class " << clazz << " : public ::ndk::BnCInterface<" << iface << "> {\n"; out << "public:\n"; out.Indent(); out << clazz << "();\n"; out << "virtual ~" << clazz << "();\n"; // Declare the meta methods for (const auto& method : defined_type.GetMethods()) { if (method->IsUserDefined()) { continue; } if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << NdkMethodDecl(types, *method) << " final override;\n"; } else { AIDL_FATAL(defined_type) << "Meta method '" << method->GetName() << "' is unimplemented."; } } if (options.GenLog()) { out << "static std::function logFunc;\n"; } out.Dedent(); out << "protected:\n"; out.Indent(); out << "::ndk::SpAIBinder createBinder() override;\n"; out.Dedent(); out << "private:\n"; out.Indent(); out.Dedent(); out << "};\n"; LeaveNdkNamespace(out, defined_type); } void GenerateInterfaceHeader(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options) { const std::string clazz = ClassName(defined_type, ClassNames::INTERFACE); out << "#pragma once\n\n"; out << "#include \n"; if (options.GenLog()) { out << "#include \n"; out << "#include \n"; out << "#include \n"; out << "#include \n"; } out << "\n"; GenerateHeaderIncludes(out, types, defined_type); out << "\n"; EnterNdkNamespace(out, defined_type); out << "class " << clazz << " : public ::ndk::ICInterface {\n"; out << "public:\n"; out.Indent(); out << "static const char* " << kDescriptor << ";\n"; out << clazz << "();\n"; out << "virtual ~" << clazz << "();\n"; out << "\n"; GenerateConstantDeclarations(out, defined_type); if (options.Version() > 0) { out << "static const int32_t " << kVersion << " = " << std::to_string(options.Version()) << ";\n"; } out << "\n"; out << "static std::shared_ptr<" << clazz << "> fromBinder(const ::ndk::SpAIBinder& binder);\n"; out << "static binder_status_t writeToParcel(AParcel* parcel, const std::shared_ptr<" << clazz << ">& instance);"; out << "\n"; out << "static binder_status_t readFromParcel(const AParcel* parcel, std::shared_ptr<" << clazz << ">* instance);"; out << "\n"; out << "static bool setDefaultImpl(std::shared_ptr<" << clazz << "> impl);"; out << "\n"; out << "static const std::shared_ptr<" << clazz << ">& getDefaultImpl();"; out << "\n"; for (const auto& method : defined_type.GetMethods()) { out << "virtual " << NdkMethodDecl(types, *method) << " = 0;\n"; } out.Dedent(); out << "private:\n"; out.Indent(); out << "static std::shared_ptr<" << clazz << "> default_impl;\n"; out.Dedent(); out << "};\n"; const std::string defaultClazz = clazz + "Default"; out << "class " << defaultClazz << " : public " << clazz << " {\n"; out << "public:\n"; out.Indent(); for (const auto& method : defined_type.GetMethods()) { if (method->IsUserDefined()) { out << NdkMethodDecl(types, *method) << " override;\n"; } else if (method->GetName() == kGetInterfaceVersion && options.Version() > 0) { out << NdkMethodDecl(types, *method) << " override;\n"; } } out << "::ndk::SpAIBinder asBinder() override;\n"; out << "bool isRemote() override;\n"; out.Dedent(); out << "};\n"; LeaveNdkNamespace(out, defined_type); } void GenerateParcelHeader(CodeWriter& out, const AidlTypenames& types, const AidlStructuredParcelable& defined_type, const Options& /*options*/) { const std::string clazz = ClassName(defined_type, ClassNames::BASE); out << "#pragma once\n"; out << "#include \n"; out << "\n"; GenerateHeaderIncludes(out, types, defined_type); EnterNdkNamespace(out, defined_type); out << "class " << clazz << " {\n"; out << "public:\n"; out.Indent(); out << "static const char* descriptor;\n"; out << "\n"; for (const auto& variable : defined_type.GetFields()) { out << NdkNameOf(types, variable->GetType(), StorageMode::STACK) << " " << variable->GetName(); if (variable->GetDefaultValue()) { out << " = " << variable->ValueString(AidlConstantValueDecorator); } out << ";\n"; } out << "\n"; out << "binder_status_t readFromParcel(const AParcel* parcel);\n"; out << "binder_status_t writeToParcel(AParcel* parcel) const;\n"; out.Dedent(); out << "};\n"; LeaveNdkNamespace(out, defined_type); } void GenerateParcelSource(CodeWriter& out, const AidlTypenames& types, const AidlStructuredParcelable& defined_type, const Options& /*options*/) { const std::string clazz = ClassName(defined_type, ClassNames::BASE); out << "#include \"" << NdkHeaderFile(defined_type, ClassNames::RAW, false /*use_os_sep*/) << "\"\n"; out << "\n"; GenerateSourceIncludes(out, types, defined_type); out << "\n"; EnterNdkNamespace(out, defined_type); out << "const char* " << clazz << "::" << kDescriptor << " = \"" << defined_type.GetCanonicalName() << "\";\n"; out << "\n"; out << "binder_status_t " << clazz << "::readFromParcel(const AParcel* parcel) {\n"; out.Indent(); out << "std::string _aidl_descriptor;\n"; out << "binder_status_t _aidl_ret_status;\n"; out << "int32_t _aidl_null;\n"; out << "int32_t _aidl_parcelable_size;\n"; out << "int32_t _aidl_start_pos;\n"; out << "_aidl_ret_status = AParcel_readInt32(parcel, &_aidl_null);\n"; StatusCheckReturn(out); out << "_aidl_start_pos = AParcel_getDataPosition(parcel);\n"; out << "_aidl_ret_status = AParcel_readInt32(parcel, &_aidl_parcelable_size);\n"; out << "if (_aidl_parcelable_size < 0) return STATUS_BAD_VALUE;\n"; StatusCheckReturn(out); // TODO(b/117281836) out << "if (_aidl_null == 0) return STATUS_UNEXPECTED_NULL;\n\n"; for (const auto& variable : defined_type.GetFields()) { out << "_aidl_ret_status = "; ReadFromParcelFor({out, types, variable->GetType(), "parcel", "&" + variable->GetName()}); out << ";\n"; StatusCheckReturn(out); out << "if (AParcel_getDataPosition(parcel) - _aidl_start_pos >= _aidl_parcelable_size) {\n" << " AParcel_setDataPosition(parcel, _aidl_start_pos + _aidl_parcelable_size);\n" << " return _aidl_ret_status;\n" << "}\n"; } out << "AParcel_setDataPosition(parcel, _aidl_start_pos + _aidl_parcelable_size);\n" << "return _aidl_ret_status;\n"; out.Dedent(); out << "}\n"; out << "binder_status_t " << clazz << "::writeToParcel(AParcel* parcel) const {\n"; out.Indent(); out << "binder_status_t _aidl_ret_status;\n"; // non-null out << "_aidl_ret_status = AParcel_writeInt32(parcel, 1);\n"; StatusCheckReturn(out); out << "size_t _aidl_start_pos = AParcel_getDataPosition(parcel);\n"; out << "_aidl_ret_status = AParcel_writeInt32(parcel, 0);\n"; StatusCheckReturn(out); for (const auto& variable : defined_type.GetFields()) { out << "_aidl_ret_status = "; WriteToParcelFor({out, types, variable->GetType(), "parcel", variable->GetName()}); out << ";\n"; StatusCheckReturn(out); } out << "size_t _aidl_end_pos = AParcel_getDataPosition(parcel);\n"; out << "AParcel_setDataPosition(parcel, _aidl_start_pos);\n"; out << "AParcel_writeInt32(parcel, _aidl_end_pos - _aidl_start_pos);\n"; out << "AParcel_setDataPosition(parcel, _aidl_end_pos);\n"; out << "return _aidl_ret_status;\n"; out.Dedent(); out << "}\n"; out << "\n"; LeaveNdkNamespace(out, defined_type); } } // namespace internals } // namespace ndk } // namespace aidl } // namespace android generate_ndk.h0100644 0000000 0000000 00000005147 13755771705 012434 0ustar000000000 0000000 /* * Copyright (C) 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include "aidl_language.h" #include "options.h" namespace android { namespace aidl { namespace ndk { void GenerateNdk(const string& output_file, const Options& options, const AidlTypenames& types, const AidlDefinedType& defined_type, const IoDelegate& io_delegate); namespace internals { void GenerateSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateClassSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateClientSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateServerSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateInterfaceSource(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateClientHeader(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateServerHeader(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateInterfaceHeader(CodeWriter& out, const AidlTypenames& types, const AidlInterface& defined_type, const Options& options); void GenerateParcelHeader(CodeWriter& out, const AidlTypenames& types, const AidlStructuredParcelable& defined_type, const Options& options); void GenerateParcelSource(CodeWriter& out, const AidlTypenames& types, const AidlStructuredParcelable& defined_type, const Options& options); } // namespace internals } // namespace ndk } // namespace aidl } // namespace android import_resolver.cpp0100644 0000000 0000000 00000005170 13755771705 013570 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 "aidl_language.h" #include #include #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 string& input_file_name, const set& import_paths, const vector& input_files) : io_delegate_(io_delegate), input_file_name_(input_file_name), input_files_(input_files) { 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. vector found_paths; for (string path : import_paths_) { path = path + relative_path; if (io_delegate_.FileIsReadable(path)) { found_paths.emplace_back(path); } } int num_found = found_paths.size(); if (num_found == 0) { // If not found from the import paths, try to find from the input files relative_path.insert(0, 1, OS_PATH_SEPARATOR); for (string input_file : input_files_) { if (android::base::EndsWith(input_file, relative_path)) { return input_file; } } return ""; } else if (num_found == 1) { return found_paths.front(); } else { AIDL_ERROR(input_file_name_) << "Duplicate files found for " << canonical_name << " from:" << std::endl << android::base::Join(found_paths, "\n"); return ""; } } } // namespace android } // namespace aidl import_resolver.h0100644 0000000 0000000 00000002763 13755771705 013242 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. */ #pragma once #include #include #include #include #include "io_delegate.h" namespace android { namespace aidl { class ImportResolver { public: ImportResolver(const IoDelegate& io_delegate, const std::string& input_file_name, const std::set& import_paths, const std::vector& input_files); 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_; const std::string& input_file_name_; std::vector import_paths_; std::vector input_files_; DISALLOW_COPY_AND_ASSIGN(ImportResolver); }; } // namespace android } // namespace aidl io_delegate.cpp0100644 0000000 0000000 00000013612 13755771705 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 #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 } static bool CreateNestedDirs(const string& caller_base_dir, const vector& nested_subdirs) { 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::CreateDirForPath(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{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. bool is_file = path.back() != OS_PATH_SEPARATOR; if (is_file) { directories.pop_back(); } return CreateNestedDirs(base, directories); } unique_ptr IoDelegate::GetCodeWriter( const string& file_path) const { if (CreateDirForPath(file_path)) { return CodeWriter::ForFile(file_path); } else { return nullptr; } } void IoDelegate::RemovePath(const std::string& file_path) const { #ifdef _WIN32 _unlink(file_path.c_str()); #else unlink(file_path.c_str()); #endif } #ifdef _WIN32 vector IoDelegate::ListFiles(const string&) const { vector result; return result; } #else static void add_list_files(const string& dirname, vector* result) { CHECK(result != nullptr); std::unique_ptr dir(opendir(dirname.c_str()), closedir); if (dir != nullptr) { while (struct dirent* ent = readdir(dir.get())) { if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { continue; } if (ent->d_type == DT_REG) { result->emplace_back(dirname + OS_PATH_SEPARATOR + ent->d_name); } else if (ent->d_type == DT_DIR) { add_list_files(dirname + OS_PATH_SEPARATOR + ent->d_name, result); } } } } vector IoDelegate::ListFiles(const string& dir) const { vector result; add_list_files(dir, &result); return result; } #endif } // namespace android } // namespace aidl io_delegate.h0100644 0000000 0000000 00000004232 13755771705 012241 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. */ #pragma once #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 std::unique_ptr GetCodeWriter( const std::string& file_path) const; virtual void RemovePath(const std::string& file_path) const; virtual std::vector ListFiles(const std::string& dir) const; private: // Create the directory when path is a dir or the parent directory when // path is a file. Path is a dir if it ends with the path separator. bool CreateDirForPath(const std::string& path) const; DISALLOW_COPY_AND_ASSIGN(IoDelegate); }; // class IoDelegate } // namespace android } // namespace aidl io_delegate_unittest.cpp0100644 0000000 0000000 00000002725 13755771705 014540 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 00000004470 13755771705 012610 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; ~FileLineReader() override { 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) {} ~MemoryLineReader() override = 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 00000002234 13755771705 012251 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. */ #pragma once #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 logging.h0100644 0000000 0000000 00000001417 13755771705 011430 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. */ #pragma once // We must include windows.h before android-base/logging.h on Windows. #ifdef _WIN32 #include #endif #include main.cpp0100644 0000000 0000000 00000003601 13755771705 011256 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 "aidl_apicheck.h" #include "io_delegate.h" #include "logging.h" #include "options.h" #include #include using android::aidl::Options; // 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"; Options options(argc, argv, Options::Language::JAVA); if (!options.Ok()) { std::cerr << options.GetErrorMessage(); std::cerr << options.GetUsage(); return 1; } android::aidl::IoDelegate io_delegate; switch (options.GetTask()) { case Options::Task::COMPILE: return android::aidl::compile_aidl(options, io_delegate); case Options::Task::PREPROCESS: return android::aidl::preprocess_aidl(options, io_delegate) ? 0 : 1; case Options::Task::DUMP_API: return android::aidl::dump_api(options, io_delegate) ? 0 : 1; case Options::Task::CHECK_API: return android::aidl::check_api(options, io_delegate) ? 0 : 1; case Options::Task::DUMP_MAPPINGS: return android::aidl::dump_mappings(options, io_delegate) ? 0 : 1; default: LOG(FATAL) << "aidl: internal error" << std::endl; return 1; } } main_cpp.cpp0100644 0000000 0000000 00000002413 13755771705 012120 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 "io_delegate.h" #include "logging.h" #include "options.h" #include using android::aidl::Options; // 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"; Options options(argc, argv, Options::Language::CPP); if (!options.Ok()) { std::cerr << options.GetErrorMessage(); std::cerr << options.GetUsage(); return 1; } android::aidl::IoDelegate io_delegate; return android::aidl::compile_aidl(options, io_delegate); } options.cpp0100644 0000000 0000000 00000036705 13755771705 012040 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 "logging.h" #include "os.h" #include #include #include #include #include #include #include #include using android::base::Split; using android::base::Trim; using std::endl; using std::string; namespace android { namespace aidl { string Options::GetUsage() const { std::ostringstream sstr; sstr << "usage:" << endl << myname_ << " --lang={java|cpp} [OPTION]... INPUT..." << endl << " Generate Java or C++ files for AIDL file(s)." << endl << endl << myname_ << " --preprocess OUTPUT INPUT..." << endl << " Create an AIDL file having declarations of AIDL file(s)." << endl << endl #ifndef _WIN32 << myname_ << " --dumpapi --out=DIR INPUT..." << endl << " Dump API signature of AIDL file(s) to DIR." << endl << endl << myname_ << " --checkapi OLD_DIR NEW_DIR" << endl << " Checkes whether API dump NEW_DIR is backwards compatible extension " << endl << " of the API dump OLD_DIR." << endl #endif << endl; // Legacy option formats if (language_ == Options::Language::JAVA) { sstr << myname_ << " [OPTION]... INPUT [OUTPUT]" << endl << " Generate a Java file for an AIDL file." << endl << endl; } else if (language_ == Options::Language::CPP) { sstr << myname_ << " [OPTION]... INPUT HEADER_DIR OUTPUT" << endl << " Generate C++ headers and source for an AIDL file." << endl << endl; } sstr << "OPTION:" << endl << " -I DIR, --include=DIR" << endl << " Use DIR as a search path for import statements." << endl << " -m FILE, --import=FILE" << endl << " Import FILE directly without searching in the search paths." << endl << " -p FILE, --preprocessed=FILE" << endl << " Include FILE which is created by --preprocess." << endl << " -d FILE, --dep=FILE" << endl << " Generate dependency file as FILE. Don't use this when" << endl << " there are multiple input files. Use -a then." << endl << " -o DIR, --out=DIR" << endl << " Use DIR as the base output directory for generated files." << endl << " -h DIR, --header_out=DIR" << endl << " Generate C++ headers under DIR." << endl << " -a" << endl << " Generate dependency file next to the output file with the" << endl << " name based on the input file." << endl << " -b" << endl << " Trigger fail when trying to compile a parcelable." << endl << " --ninja" << endl << " Generate dependency file in a format ninja understands." << endl << " --structured" << endl << " Whether this interface is defined exclusively in AIDL." << endl << " It is therefore a candidate for stabilization." << endl << " -t, --trace" << endl << " Include tracing code for systrace. Note that if either" << endl << " the client or service code is not auto-generated by this" << endl << " tool, that part will not be traced." << endl << " --transaction_names" << endl << " Generate transaction names." << endl << " --apimapping" << endl << " Generates a mapping of declared aidl method signatures to" << endl << " the original line number. e.g.: " << endl << " If line 39 of foo/bar/IFoo.aidl contains:" << " void doFoo(int bar, String baz);" << endl << " Then the result would be:" << endl << " foo.bar.Baz|doFoo|int,String,|void" << endl << " foo/bar/IFoo.aidl:39" << endl << " -v VER, --version=VER" << endl << " Set the version of the interface and parcelable to VER." << endl << " VER must be an interger greater than 0." << endl << " --log" << endl << " Information about the transaction, e.g., method name, argument" << endl << " values, execution time, etc., is provided via callback." << endl << " --help" << endl << " Show this help." << endl << endl << "INPUT:" << endl << " An AIDL file." << endl << endl << "OUTPUT:" << endl << " Path to the generated Java or C++ source file. This is ignored when" << endl << " -o or --out is specified or the number of the input files are" << endl << " more than one." << endl << " For Java, if omitted, Java source file is generated at the same" << endl << " place as the input AIDL file," << endl << endl << "HEADER_DIR:" << endl << " Path to where C++ headers are generated." << endl; return sstr.str(); } Options Options::From(const string& cmdline) { vector args = Split(cmdline, " "); return From(args); } Options Options::From(const vector& args) { Options::Language lang = Options::Language::JAVA; int argc = args.size(); if (argc >= 1 && args.at(0) == "aidl-cpp") { lang = Options::Language::CPP; } const char* argv[argc + 1]; for (int i = 0; i < argc; i++) { argv[i] = args.at(i).c_str(); } argv[argc] = nullptr; return Options(argc, argv, lang); } Options::Options(int argc, const char* const argv[], Options::Language default_lang) : myname_(argv[0]), language_(default_lang) { bool lang_option_found = false; optind = 0; while (true) { static struct option long_options[] = { {"lang", required_argument, 0, 'l'}, {"preprocess", no_argument, 0, 's'}, #ifndef _WIN32 {"dumpapi", no_argument, 0, 'u'}, {"checkapi", no_argument, 0, 'A'}, #endif {"apimapping", required_argument, 0, 'i'}, {"include", required_argument, 0, 'I'}, {"import", required_argument, 0, 'm'}, {"preprocessed", required_argument, 0, 'p'}, {"dep", required_argument, 0, 'd'}, {"out", required_argument, 0, 'o'}, {"header_out", required_argument, 0, 'h'}, {"ninja", no_argument, 0, 'n'}, {"structured", no_argument, 0, 'S'}, {"trace", no_argument, 0, 't'}, {"transaction_names", no_argument, 0, 'c'}, {"version", required_argument, 0, 'v'}, {"log", no_argument, 0, 'L'}, {"help", no_argument, 0, 'e'}, {0, 0, 0, 0}, }; const int c = getopt_long(argc, const_cast(argv), "I:m:p:d:o:h:abtv:", long_options, nullptr); if (c == -1) { // no more options break; } switch (c) { case 'l': if (language_ == Options::Language::CPP) { // aidl-cpp can't set language. aidl-cpp exists only for backwards // compatibility. error_message_ << "aidl-cpp does not support --lang." << endl; return; } else { lang_option_found = true; string lang = Trim(optarg); if (lang == "java") { language_ = Options::Language::JAVA; task_ = Options::Task::COMPILE; } else if (lang == "cpp") { language_ = Options::Language::CPP; task_ = Options::Task::COMPILE; } else if (lang == "ndk") { language_ = Options::Language::NDK; task_ = Options::Task::COMPILE; } else { error_message_ << "Unsupported language: '" << lang << "'" << endl; return; } } break; case 's': if (task_ != Options::Task::UNSPECIFIED) { task_ = Options::Task::PREPROCESS; } break; #ifndef _WIN32 case 'u': if (task_ != Options::Task::UNSPECIFIED) { task_ = Options::Task::DUMP_API; } break; case 'A': if (task_ != Options::Task::UNSPECIFIED) { task_ = Options::Task::CHECK_API; // to ensure that all parcelables in the api dumpes are structured structured_ = true; } break; #endif case 'I': { import_dirs_.emplace(Trim(optarg)); break; } case 'm': { import_files_.emplace(Trim(optarg)); break; } case 'p': preprocessed_files_.emplace_back(Trim(optarg)); break; case 'd': dependency_file_ = Trim(optarg); break; case 'o': output_dir_ = Trim(optarg); if (output_dir_.back() != OS_PATH_SEPARATOR) { output_dir_.push_back(OS_PATH_SEPARATOR); } break; case 'h': output_header_dir_ = Trim(optarg); if (output_header_dir_.back() != OS_PATH_SEPARATOR) { output_header_dir_.push_back(OS_PATH_SEPARATOR); } break; case 'n': dependency_file_ninja_ = true; break; case 'S': structured_ = true; break; case 't': gen_traces_ = true; break; case 'a': auto_dep_file_ = true; break; case 'b': fail_on_parcelable_ = true; break; case 'c': gen_transaction_names_ = true; break; case 'v': { const string ver_str = Trim(optarg); int ver = atoi(ver_str.c_str()); if (ver > 0) { version_ = ver; } else { error_message_ << "Invalid version number: '" << ver_str << "'. " << "Version must be a positive natural number." << endl; return; } break; } case 'L': gen_log_ = true; break; case 'e': std::cerr << GetUsage(); exit(0); case 'i': output_file_ = Trim(optarg); task_ = Task::DUMP_MAPPINGS; break; default: std::cerr << GetUsage(); exit(1); } } // while // Positional arguments if (!lang_option_found && task_ == Options::Task::COMPILE) { // the legacy arguments format if (argc - optind <= 0) { error_message_ << "No input file" << endl; return; } if (language_ == Options::Language::JAVA) { input_files_.emplace_back(argv[optind++]); if (argc - optind >= 1) { output_file_ = argv[optind++]; } else if (output_dir_.empty()) { // when output is omitted and -o option isn't set, the output is by // default set to the input file path with .aidl is replaced to .java. // If -o option is set, the output path is calculated by // generate_outputFileName which returns "// // .java" output_file_ = input_files_.front(); if (android::base::EndsWith(output_file_, ".aidl")) { output_file_ = output_file_.substr(0, output_file_.length() - strlen(".aidl")); } output_file_ += ".java"; } } else if (IsCppOutput()) { input_files_.emplace_back(argv[optind++]); if (argc - optind < 2) { error_message_ << "No HEADER_DIR or OUTPUT." << endl; return; } output_header_dir_ = argv[optind++]; if (output_header_dir_.back() != OS_PATH_SEPARATOR) { output_header_dir_.push_back(OS_PATH_SEPARATOR); } output_file_ = argv[optind++]; } if (argc - optind > 0) { error_message_ << "Too many arguments: "; for (int i = optind; i < argc; i++) { error_message_ << " " << argv[i]; } error_message_ << endl; } } else { // the new arguments format if (task_ == Options::Task::COMPILE || task_ == Options::Task::DUMP_API) { if (argc - optind < 1) { error_message_ << "No input file." << endl; return; } } else { if (argc - optind < 2) { error_message_ << "Insufficient arguments. At least 2 required, but " << "got " << (argc - optind) << "." << endl; return; } if (task_ != Options::Task::CHECK_API && task_ != Options::Task::DUMP_MAPPINGS) { output_file_ = argv[optind++]; } } while (optind < argc) { input_files_.emplace_back(argv[optind++]); } } // filter out invalid combinations if (lang_option_found) { if (IsCppOutput() && task_ == Options::Task::COMPILE) { if (output_dir_.empty()) { error_message_ << "Output directory is not set. Set with --out." << endl; return; } if (output_header_dir_.empty()) { error_message_ << "Header output directory is not set. Set with " << "--header_out." << endl; return; } } if (language_ == Options::Language::JAVA && task_ == Options::Task::COMPILE) { if (output_dir_.empty()) { error_message_ << "Output directory is not set. Set with --out." << endl; return; } if (!output_header_dir_.empty()) { error_message_ << "Header output directory is set, which does not make " << "sense for Java." << endl; return; } } } if (task_ == Options::Task::COMPILE) { for (const string& input : input_files_) { if (!android::base::EndsWith(input, ".aidl")) { error_message_ << "Expected .aidl file for input but got '" << input << "'" << endl; return; } } if (!output_file_.empty() && input_files_.size() > 1) { error_message_ << "Multiple AIDL files can't be compiled to a single " << "output file '" << output_file_ << "'. " << "Use --out=DIR instead for output files." << endl; return; } if (!dependency_file_.empty() && input_files_.size() > 1) { error_message_ << "-d or --dep doesn't work when compiling multiple AIDL " << "files. Use '-a' to generate dependency file next to " << "the output file with the name based on the input " << "file." << endl; return; } if (gen_log_ && (language_ != Options::Language::CPP && language_ != Options::Language::NDK)) { error_message_ << "--log is currently supported for either --lang=cpp or --lang=ndk" << endl; return; } } if (task_ == Options::Task::PREPROCESS) { if (version_ > 0) { error_message_ << "--version should not be used with '--preprocess'." << endl; return; } } if (task_ == Options::Task::CHECK_API) { if (input_files_.size() != 2) { error_message_ << "--checkapi requires two inputs for comparing, " << "but got " << input_files_.size() << "." << endl; return; } } if (task_ == Options::Task::DUMP_API) { if (output_dir_.empty()) { error_message_ << "--dump_api requires output directory. Use --out." << endl; return; } } CHECK(output_dir_.empty() || output_dir_.back() == OS_PATH_SEPARATOR); CHECK(output_header_dir_.empty() || output_header_dir_.back() == OS_PATH_SEPARATOR); } } // namespace android } // namespace aidl options.h0100644 0000000 0000000 00000011706 13755771705 011477 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. */ #pragma once #include #include #include #include namespace android { namespace aidl { using std::set; using std::string; using std::vector; // A simple wrapper around ostringstream. This is just to make Options class // copiable by the implicit copy constructor. If ostingstream is not wrapped, // the implcit copy constructor is not generated because ostringstream isn't // copiable. This class makes the field copiable by having a copy constructor // that does not copy the underlying stream. class ErrorMessage { public: ErrorMessage() = default; ErrorMessage(const ErrorMessage&) {} std::ostringstream stream_; template ErrorMessage& operator<<(T& t) { stream_ << t; return *this; } template ErrorMessage& operator<<(const T& t) { stream_ << t; return *this; } // for "<< endl" ErrorMessage& operator<<(std::ostream& (*f)(std::ostream&)) { f(stream_); return *this; } }; class Options final { public: enum class Language { UNSPECIFIED, JAVA, CPP, NDK }; enum class Task { UNSPECIFIED, COMPILE, PREPROCESS, DUMP_API, CHECK_API, DUMP_MAPPINGS }; Options(int argc, const char* const argv[], Language default_lang = Language::UNSPECIFIED); static Options From(const string& cmdline); static Options From(const vector& args); // Contain no references to unstructured data types (such as a parcelable that is // implemented in Java). These interfaces aren't inherently stable but they have the // capacity to be stabilized. bool IsStructured() const { return structured_; } Language TargetLanguage() const { return language_; } bool IsCppOutput() const { return language_ == Language::CPP || language_ == Language::NDK; } Task GetTask() const { return task_; } const set& ImportDirs() const { return import_dirs_; } const set& ImportFiles() const { return import_files_; } const vector& PreprocessedFiles() const { return preprocessed_files_; } string DependencyFile() const { return dependency_file_; } bool AutoDepFile() const { return auto_dep_file_; } bool GenTraces() const { return gen_traces_; } bool GenTransactionNames() const { return gen_transaction_names_; } bool DependencyFileNinja() const { return dependency_file_ninja_; } const vector& InputFiles() const { return input_files_; } // Path to the output file. This is used only when there is only one // output file for the invocation. When there are multiple outputs // (e.g. compile multiple AIDL files), output files are created under // OutputDir(). const string& OutputFile() const { return output_file_; } // Path to the directory where output file(s) will be generated under. const string& OutputDir() const { return output_dir_; } // Path to the directory where header file(s) will be generated under. // Only used when TargetLanguage() == Language::CPP const string& OutputHeaderDir() const { return output_header_dir_; } bool FailOnParcelable() const { return fail_on_parcelable_; } int Version() const { return version_; } bool GenLog() const { return gen_log_; } bool Ok() const { return error_message_.stream_.str().empty(); } string GetErrorMessage() const { return error_message_.stream_.str(); } string GetUsage() const; bool GenApiMapping() const { return task_ == Task::DUMP_MAPPINGS; } // The following are for testability, but cannot be influenced on the command line. // Threshold of interface methods to enable outlining of onTransact cases. size_t onTransact_outline_threshold_{275u}; // Number of cases to _not_ outline, if outlining is enabled. size_t onTransact_non_outline_count_{275u}; private: Options() = default; const string myname_; bool structured_ = false; Language language_ = Language::UNSPECIFIED; Task task_ = Task::COMPILE; set import_dirs_; set import_files_; vector preprocessed_files_; string dependency_file_; bool gen_traces_ = false; bool gen_transaction_names_ = false; bool dependency_file_ninja_ = false; string output_dir_; string output_header_dir_; bool fail_on_parcelable_ = false; bool auto_dep_file_ = false; vector input_files_; string output_file_; int version_ = 0; bool gen_log_ = false; ErrorMessage error_message_; }; } // namespace android } // namespace aidl options_unittest.cpp0100644 0000000 0000000 00000023073 13755771705 013771 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 #include 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.aidl"; const char kPreprocessCommandInput2[] = "input2.aidl"; const char kPreprocessCommandInput3[] = "input3.aidl"; 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, }; unique_ptr GetOptions(const char* command[], Options::Language default_lang = Options::Language::JAVA) { int argc = 0; const char** command_part = command; for (; *command_part; ++argc, ++command_part) {} unique_ptr ret(new Options(argc, command, default_lang)); if (!ret->Ok()) { cerr << ret->GetErrorMessage(); cerr << "Failed to parse command line:"; for (int i = 0; i < argc; ++i) { cerr << " " << command[i]; cerr << endl; } } EXPECT_NE(ret, nullptr) << "Failed to parse options!"; return ret; } } // namespace TEST(OptionsTests, ParsesPreprocess) { unique_ptr options = GetOptions(kPreprocessCommand); EXPECT_EQ(Options::Task::PREPROCESS, options->GetTask()); EXPECT_EQ(false, options->FailOnParcelable()); EXPECT_EQ(0u, options->ImportDirs().size()); EXPECT_EQ(0u, options->PreprocessedFiles().size()); EXPECT_EQ(string{kPreprocessCommandOutputFile}, options->OutputFile()); EXPECT_EQ(false, options->AutoDepFile()); const vector expected_input{kPreprocessCommandInput1, kPreprocessCommandInput2, kPreprocessCommandInput3}; EXPECT_EQ(expected_input, options->InputFiles()); } TEST(OptionsTests, ParsesCompileJava) { unique_ptr options = GetOptions(kCompileJavaCommand); EXPECT_EQ(Options::Task::COMPILE, options->GetTask()); EXPECT_EQ(Options::Language::JAVA, options->TargetLanguage()); EXPECT_EQ(true, options->FailOnParcelable()); EXPECT_EQ(1u, options->ImportDirs().size()); EXPECT_EQ(0u, options->PreprocessedFiles().size()); EXPECT_EQ(string{kCompileCommandInput}, options->InputFiles().front()); EXPECT_EQ(string{kCompileCommandJavaOutput}, options->OutputFile()); EXPECT_EQ(false, options->AutoDepFile()); EXPECT_EQ(false, options->DependencyFileNinja()); } TEST(OptionsTests, ParsesCompileJavaNinja) { unique_ptr options = GetOptions(kCompileJavaCommandNinja); EXPECT_EQ(Options::Task::COMPILE, options->GetTask()); EXPECT_EQ(Options::Language::JAVA, options->TargetLanguage()); EXPECT_EQ(true, options->FailOnParcelable()); EXPECT_EQ(1u, options->ImportDirs().size()); EXPECT_EQ(0u, options->PreprocessedFiles().size()); EXPECT_EQ(string{kCompileCommandInput}, options->InputFiles().front()); EXPECT_EQ(string{kCompileCommandJavaOutput}, options->OutputFile()); EXPECT_EQ(false, options->AutoDepFile()); EXPECT_EQ(true, options->DependencyFileNinja()); } TEST(OptionsTests, ParsesCompileCpp) { unique_ptr options = GetOptions(kCompileCppCommand, Options::Language::CPP); ASSERT_EQ(1u, options->ImportDirs().size()); EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2), *options->ImportDirs().begin()); EXPECT_EQ(string{kCompileDepFile}.substr(2), options->DependencyFile()); EXPECT_EQ(false, options->DependencyFileNinja()); EXPECT_EQ(kCompileCommandInput, options->InputFiles().front()); EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir()); EXPECT_EQ(kCompileCommandCppOutput, options->OutputFile()); } TEST(OptionsTests, ParsesCompileCppNinja) { unique_ptr options = GetOptions(kCompileCppCommandNinja, Options::Language::CPP); ASSERT_EQ(1u, options->ImportDirs().size()); EXPECT_EQ(string{kCompileCommandIncludePath}.substr(2), *options->ImportDirs().begin()); EXPECT_EQ(string{kCompileDepFile}.substr(2), options->DependencyFile()); EXPECT_EQ(true, options->DependencyFileNinja()); EXPECT_EQ(kCompileCommandInput, options->InputFiles().front()); EXPECT_EQ(kCompileCommandHeaderDir, options->OutputHeaderDir()); EXPECT_EQ(kCompileCommandCppOutput, options->OutputFile()); } TEST(OptionsTests, ParsesCompileJavaMultiInput) { const char* argv[] = { "aidl", "--lang=java", kCompileCommandIncludePath, "-o src_out", "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl", nullptr, }; unique_ptr options = GetOptions(argv); EXPECT_EQ(Options::Task::COMPILE, options->GetTask()); EXPECT_EQ(Options::Language::JAVA, options->TargetLanguage()); EXPECT_EQ(false, options->FailOnParcelable()); EXPECT_EQ(1u, options->ImportDirs().size()); EXPECT_EQ(0u, options->PreprocessedFiles().size()); const vector expected_input{"directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl"}; EXPECT_EQ(expected_input, options->InputFiles()); EXPECT_EQ(string{""}, options->OutputFile()); EXPECT_EQ(false, options->AutoDepFile()); EXPECT_EQ(false, options->DependencyFileNinja()); EXPECT_EQ(string{""}, options->OutputHeaderDir()); EXPECT_EQ(string{"src_out/"}, options->OutputDir()); } TEST(OptionsTests, ParsesCompileJavaInvalid) { // -o option is required const char* arg_with_no_out_dir[] = { "aidl", "--lang=java", kCompileCommandIncludePath, "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl", nullptr, }; EXPECT_EQ(false, GetOptions(arg_with_no_out_dir)->Ok()); // -h options is not for Java const char* arg_with_header_dir[] = { "aidl", "--lang=java", kCompileCommandIncludePath, "-o src_out", "-h header_out", "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl", nullptr, }; EXPECT_EQ(false, GetOptions(arg_with_header_dir)->Ok()); } TEST(OptionsTests, ParsesCompileCppMultiInput) { const char* argv[] = { "aidl", "--lang=cpp", kCompileCommandIncludePath, "-h header_out", "-o src_out", "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl", nullptr, }; unique_ptr options = GetOptions(argv); EXPECT_EQ(Options::Task::COMPILE, options->GetTask()); EXPECT_EQ(Options::Language::CPP, options->TargetLanguage()); EXPECT_EQ(false, options->FailOnParcelable()); EXPECT_EQ(1u, options->ImportDirs().size()); EXPECT_EQ(0u, options->PreprocessedFiles().size()); const vector expected_input{"directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl"}; EXPECT_EQ(expected_input, options->InputFiles()); EXPECT_EQ(string{""}, options->OutputFile()); EXPECT_EQ(false, options->AutoDepFile()); EXPECT_EQ(false, options->DependencyFileNinja()); EXPECT_EQ(string{"header_out/"}, options->OutputHeaderDir()); EXPECT_EQ(string{"src_out/"}, options->OutputDir()); } TEST(OptionsTests, ParsesCompileCppInvalid) { // -o option is required const char* arg_with_no_out_dir[] = { "aidl", "--lang=cpp", kCompileCommandIncludePath, "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl", nullptr, }; EXPECT_EQ(false, GetOptions(arg_with_no_out_dir)->Ok()); // -h options is required as well const char* arg_with_no_header_dir[] = { "aidl", "--lang=cpp", kCompileCommandIncludePath, "-o src_out", "directory/input1.aidl", "directory/input2.aidl", "directory/input3.aidl", nullptr, }; EXPECT_EQ(false, GetOptions(arg_with_no_header_dir)->Ok()); } } // namespace android } // namespace aidl os.h0100644 0000000 0000000 00000001325 13755771705 010421 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. */ #pragma once #if defined(_WIN32) #define OS_PATH_SEPARATOR '\\' #else #define OS_PATH_SEPARATOR '/' #endif runtests.sh0100755 0000000 0000000 00000002525 13755771705 012060 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 $ANDROID_BUILD_TOP/system/tools/aidl" $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ 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 13755771705 010773 5ustar000000000 0000000 tests/aidl_test_client.cpp0100644 0000000 0000000 00000006542 13755771705 015011 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_defaultimpl.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::ConfirmStructuredParcelables(service)) return 1; if (!client_tests::ConfirmFileDescriptors(service)) return 1; if (!client_tests::ConfirmFileDescriptorArrays(service)) return 1; if (!client_tests::ConfirmParcelFileDescriptors(service)) return 1; if (!client_tests::ConfirmParcelFileDescriptorArrays(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; if (!client_tests::ConfirmDefaultImpl(service)) return 1; return 0; } tests/aidl_test_client_defaultimpl.cpp0100644 0000000 0000000 00000004357 13755771705 017401 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "aidl_test_client_defaultimpl.h" #include namespace android { namespace aidl { namespace tests { namespace client { static const int32_t kExpectedArgValue = 100; static const int32_t kExpectedReturnValue = 200; bool ConfirmDefaultImpl(const sp& s) { class Def : public android::aidl::tests::ITestServiceDefault { android::binder::Status UnimplementedMethod(int32_t arg, int32_t* _aidl_return) override { if (arg != kExpectedArgValue) { std::cerr << "Argument to UnimplementedMethod is expected to be " << kExpectedArgValue << ", " << "but got " << arg << std::endl; return android::binder::Status::fromStatusT(android::FAILED_TRANSACTION); } *_aidl_return = kExpectedReturnValue; return android::binder::Status::ok(); } }; bool success = android::aidl::tests::ITestService::setDefaultImpl(std::make_unique()); if (!success) { std::cerr << "Failed to set default impl for ITestService" << std::endl; return false; } int32_t ret; android::binder::Status status = s->UnimplementedMethod(kExpectedArgValue, &ret); if (!status.isOk()) { std::cerr << "Call to UnimplementedMethod() has failed. status=" << status.toString8() << std::endl; return false; } if (ret != kExpectedReturnValue) { std::cerr << "Return value from UnimplementedMethod is expected to be " << kExpectedReturnValue << ", " << "but got " << ret << std::endl; return false; } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_defaultimpl.h0100644 0000000 0000000 00000002106 13755771705 017034 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_AIDL_TESTS_CLIENT_DEFAULTIMPL_H #define ANDROID_AIDL_TESTS_CLIENT_DEFAULTIMPL_H #include "android/aidl/tests/ITestService.h" #include // Tests for default impl namespace android { namespace aidl { namespace tests { namespace client { bool ConfirmDefaultImpl(const sp& s); } // namespace client } // namespace tests } // namespace aidl } // namespace android #endif // ANDROID_AIDL_TESTS_CLIENT_DEFAULTIMPL_H tests/aidl_test_client_file_descriptors.cpp0100644 0000000 0000000 00000013621 13755771705 020425 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 #include // libbase using android::base::unique_fd; // libutils: using android::sp; // libbinder: using android::binder::Status; // generated using android::aidl::tests::ITestService; using android::os::ParcelFileDescriptor; 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; } bool ConfirmParcelFileDescriptors(const sp& s) { Status status; cout << "Confirming passing and returning parcel file descriptors works." << endl; unique_fd read_fd; unique_fd write_fd; if (!DoPipe(&read_fd, &write_fd)) { return false; } ParcelFileDescriptor return_fd; status = s->RepeatParcelFileDescriptor(ParcelFileDescriptor(std::move(write_fd)), &return_fd); if (!status.isOk()) { cerr << "Could not repeat parcel 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.release()), "ReturnString") && DoRead(FdByName(read_fd), "ReturnString"); return ret; } bool ConfirmParcelFileDescriptorArrays(const sp& s) { Status status; cout << "Confirming passing and returning parcel file descriptor arrays works." << endl; vector array; array.resize(2); if (!DoPipe(&array[0], &array[1])) { return false; } vector input; for (auto& fd : array) { input.push_back(ParcelFileDescriptor(std::move(fd))); } vector repeated; vector reversed; status = s->ReverseParcelFileDescriptorArray(input, &repeated, &reversed); if (!status.isOk()) { cerr << "Could not reverse file descriptor array." << endl; return false; } bool ret = DoWrite(FdByName(input[1].release()), "First") && DoWrite(FdByName(repeated[1].release()), "Second") && DoWrite(FdByName(reversed[0].release()), "Third") && DoRead(FdByName(input[0].release()), "FirstSecondThird"); return ret; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_file_descriptors.h0100644 0000000 0000000 00000002462 13755771705 020073 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); bool ConfirmParcelFileDescriptors(const sp& s); bool ConfirmParcelFileDescriptorArrays(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 13755771705 017063 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 13755771705 016505 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 00000017400 13755771705 017341 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; } bool ConfirmStructuredParcelables(const sp& s) { constexpr int kDesiredValue = 23; StructuredParcelable parcelable; parcelable.f = kDesiredValue; if (parcelable.stringDefaultsToFoo != String16("foo")) { cout << "stringDefaultsToFoo should be 'foo' but is " << parcelable.stringDefaultsToFoo << endl; return false; } if (parcelable.byteDefaultsToFour != 4) { cout << "byteDefaultsToFour should be 4 but is " << parcelable.byteDefaultsToFour << endl; return false; } if (parcelable.intDefaultsToFive != 5) { cout << "intDefaultsToFive should be 5 but is " << parcelable.intDefaultsToFive << endl; return false; } if (parcelable.longDefaultsToNegativeSeven != -7) { cout << "longDefaultsToNegativeSeven should be -7 but is " << parcelable.longDefaultsToNegativeSeven << endl; return false; } if (!parcelable.booleanDefaultsToTrue) { cout << "booleanDefaultsToTrue isn't true" << endl; return false; } if (parcelable.charDefaultsToC != 'C') { cout << "charDefaultsToC is " << parcelable.charDefaultsToC << endl; return false; } if (parcelable.floatDefaultsToPi != 3.14f) { cout << "floatDefaultsToPi is " << parcelable.floatDefaultsToPi << endl; return false; } if (parcelable.doubleWithDefault != -3.14e17) { cout << "doubleWithDefault is " << parcelable.doubleWithDefault << " but should be -3.14e17" << endl; return false; } if (parcelable.arrayDefaultsTo123.size() != 3) { cout << "arrayDefaultsTo123 is of length " << parcelable.arrayDefaultsTo123.size() << endl; return false; } for (int i = 0; i < 3; i++) { if (parcelable.arrayDefaultsTo123[i] != i + 1) { cout << "arrayDefaultsTo123[" << i << "] is " << parcelable.arrayDefaultsTo123[i] << " but should be " << i + 1 << endl; return false; } } if (!parcelable.arrayDefaultsToEmpty.empty()) { cout << "arrayDefaultsToEmpty is not empty " << parcelable.arrayDefaultsToEmpty.size() << endl; return false; } s->FillOutStructuredParcelable(&parcelable); if (parcelable.shouldContainThreeFs.size() != 3) { cout << "shouldContainThreeFs is of length " << parcelable.shouldContainThreeFs.size() << endl; return false; } for (int i = 0; i < 3; i++) { if (parcelable.shouldContainThreeFs[i] != kDesiredValue) { cout << "shouldContainThreeFs[" << i << "] is " << parcelable.shouldContainThreeFs[i] << " but should be " << kDesiredValue << endl; return false; } } if (parcelable.shouldBeJerry != "Jerry") { cout << "shouldBeJerry should be 'Jerry' but is " << parcelable.shouldBeJerry << endl; return false; } return true; } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_parcelables.h0100644 0000000 0000000 00000002340 13755771705 017003 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); bool ConfirmStructuredParcelables(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 13755771705 017261 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 13755771705 016730 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 13755771705 020766 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 13755771705 020422 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 00000013417 13755771705 017527 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"), ITestService::STRING_TEST_CONSTANT_UTF8(), }; 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; } namespace { bool ConfirmUtf8InCppStringCollectionReverse(const sp& s, Status (ITestService::*m)(const unique_ptr>>&, unique_ptr>>*, unique_ptr>>*)) { (void)m; LOG(INFO) << "Confirming reversing a list of utf8 strings works"; unique_ptr>> input, reversed, repeated; Status status = (s.get()->*m)(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 bool ConfirmUtf8InCppStringListReverse(const sp& s) { return ConfirmUtf8InCppStringCollectionReverse(s, &ITestService::ReverseUtf8CppStringList); } bool ConfirmUtf8InCppNullableStringArrayReverse(const sp& s) { return ConfirmUtf8InCppStringCollectionReverse(s, &ITestService::ReverseNullableUtf8CppString); } } // namespace client } // namespace tests } // namespace aidl } // namespace android tests/aidl_test_client_utf8_strings.h0100644 0000000 0000000 00000002536 13755771705 017174 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 13755771705 017223 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 00000040756 13755771705 015200 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::binder::Map; using android::os::ParcelFileDescriptor; using android::os::PersistableBundle; // 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 RepeatParcelFileDescriptor(const ParcelFileDescriptor& read, ParcelFileDescriptor* _aidl_return) override { ALOGE("Repeating parcel file descriptor"); _aidl_return->reset(unique_fd(dup(read.get()))); return Status::ok(); } Status ReverseParcelFileDescriptorArray(const vector& input, vector* repeated, vector* _aidl_return) override { ALOGI("Reversing parcel descriptor array of length %zu", input.size()); for (const auto& item : input) { repeated->push_back(ParcelFileDescriptor(unique_fd(dup(item.get())))); } for (auto i = input.rbegin(); i != input.rend(); i++) { _aidl_return->push_back(ParcelFileDescriptor(unique_fd(dup(i->get())))); } 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 ReverseNullableUtf8CppString( const unique_ptr>>& input, unique_ptr>>* repeated, unique_ptr>>* _aidl_return) { return ReverseUtf8CppStringList(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(); } virtual ::android::binder::Status FillOutStructuredParcelable( ::android::aidl::tests::StructuredParcelable* parcelable) { parcelable->shouldBeJerry = "Jerry"; parcelable->shouldContainThreeFs = {parcelable->f, parcelable->f, parcelable->f}; return Status::ok(); } Status UnimplementedMethod(int32_t /* arg */, int32_t* /* _aidl_return */) override { LOG_ALWAYS_FATAL("UnimplementedMethod shouldn't be called"); } android::status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override { if (code == ::android::IBinder::FIRST_CALL_TRANSACTION + 45 /* UnimplementedMethod */) { // pretend that UnimplementedMethod isn't implemented by this service. return android::UNKNOWN_TRANSACTION; } else { return BnTestService::onTransact(code, data, reply, flags); } } 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 13755771705 012413 5ustar000000000 0000000 tests/android/aidl/0040755 0000000 0000000 00000000000 13755771705 013324 5ustar000000000 0000000 tests/android/aidl/loggable/0040755 0000000 0000000 00000000000 13755771705 015100 5ustar000000000 0000000 tests/android/aidl/loggable/ILoggableInterface.aidl0100644 0000000 0000000 00000001421 13755771705 021374 0ustar000000000 0000000 package android.aidl.loggable; interface ILoggableInterface { String[] LogThis(boolean boolValue, inout boolean[] boolArray, byte byteValue, inout byte[] byteArray, char charValue, inout char[] charArray, int intValue, inout int[] intArray, long longValue, inout long[] longArray, float floatValue, inout float[] floatArray, double doubleValue, inout double[] doubleArray, String stringValue, inout String[] stringArray, inout List listValue, inout Map mapValue, IBinder binderValue, inout ParcelFileDescriptor pfdValue, inout ParcelFileDescriptor[] pfdArray); } tests/android/aidl/loggable/ILoggableInterfaceNdk.aidl0100644 0000000 0000000 00000001225 13755771705 022033 0ustar000000000 0000000 package android.aidl.loggable; interface ILoggableInterfaceNdk { String[] LogThis(boolean boolValue, inout boolean[] boolArray, byte byteValue, inout byte[] byteArray, char charValue, inout char[] charArray, int intValue, inout int[] intArray, long longValue, inout long[] longArray, float floatValue, inout float[] floatArray, double doubleValue, inout double[] doubleArray, String stringValue, inout String[] stringArray, IBinder binderValue, inout ParcelFileDescriptor pfdValue); } tests/android/aidl/tests/0040755 0000000 0000000 00000000000 13755771705 014466 5ustar000000000 0000000 tests/android/aidl/tests/INamedCallback.aidl0100644 0000000 0000000 00000001273 13755771705 020073 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 00000013507 13755771705 017675 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.aidl.tests.StructuredParcelable; 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"; const @utf8InCpp String STRING_TEST_CONSTANT_UTF8 = "baz"; // 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); ParcelFileDescriptor RepeatParcelFileDescriptor(in ParcelFileDescriptor read); ParcelFileDescriptor[] ReverseParcelFileDescriptorArray(in ParcelFileDescriptor[] input, out ParcelFileDescriptor[] 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 String[] ReverseNullableUtf8CppString ( in @nullable @utf8InCpp String[] input, out @nullable @utf8InCpp String[] repeated); @nullable @utf8InCpp List ReverseUtf8CppStringList( in @nullable @utf8InCpp List input, out @nullable @utf8InCpp List repeated); @nullable INamedCallback GetCallback(boolean return_null); // Since this paracelable has clearly defined default values, it would be // inefficient to use an IPC to fill it out in practice. void FillOutStructuredParcelable(inout StructuredParcelable parcel); // This is to emulate a method that is added after the service is implemented. // So the client cannot assume that call to this method will be successful // or not. However, inside the test environment, we can't build client and // the server with different version of this AIDL file. So, we let the server // to actually implement this, but intercept the dispatch to the method // inside onTransact(). int UnimplementedMethod(int arg); } tests/android/aidl/tests/SimpleParcelable.aidl0100644 0000000 0000000 00000001316 13755771705 020523 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/android/aidl/tests/StructuredParcelable.aidl0100644 0000000 0000000 00000002450 13755771705 021436 0ustar000000000 0000000 /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.aidl.tests; parcelable StructuredParcelable { int[] shouldContainThreeFs; int f; @utf8InCpp String shouldBeJerry; String stringDefaultsToFoo = "foo"; byte byteDefaultsToFour = 4; int intDefaultsToFive = 5; long longDefaultsToNegativeSeven = -7; boolean booleanDefaultsToTrue = true; char charDefaultsToC = 'C'; float floatDefaultsToPi = 3.14f; double doubleWithDefault = -3.14e17; int[] arrayDefaultsTo123 = { 1, 2, 3 }; int[] arrayDefaultsToEmpty = { }; // parse checks only double checkDoubleFromFloat = 3.14f; String[] checkStringArray1 = { "a", "b" }; @utf8InCpp String[] checkStringArray2 = { "a", "b" }; } tests/end_to_end_tests.cpp0100644 0000000 0000000 00000026415 13755771705 015024 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: void SetUp() override { } 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; vector args = { "aidl", "-b", "-I .", "-d an/arbitrary/path/to/dep.P", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); // Load up our fake file system with data. io_delegate_.SetFileContents(options.InputFiles().front(), kInterfaceDefinition); io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable", {"Subclass1", "Subclass2"}); AddStubAidls(kImportedParcelables, kImportedInterfaces); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutput); CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput); } TEST_F(EndToEndTest, IExampleInterface_WithTrace) { using namespace ::android::aidl::test_data::example_interface; vector args = { "aidl", "-b", "-I .", "-t", //trace "-d an/arbitrary/path/to/dep.P", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); // Load up our fake file system with data. io_delegate_.SetFileContents(options.InputFiles().front(), kInterfaceDefinition); io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable", {"Subclass1", "Subclass2"}); AddStubAidls(kImportedParcelables, kImportedInterfaces); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutputWithTrace); CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput); } TEST_F(EndToEndTest, IExampleInterface_WithTransactionNames) { using namespace ::android::aidl::test_data::example_interface; vector args = { "aidl", "-b", "-I .", "--transaction_name", //trace "-d an/arbitrary/path/to/dep.P", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); // Load up our fake file system with data. io_delegate_.SetFileContents(options.InputFiles().front(), kInterfaceDefinition); io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable", {"Subclass1", "Subclass2"}); AddStubAidls(kImportedParcelables, kImportedInterfaces); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutputWithTransactionNames); CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput); } TEST_F(EndToEndTest, IExampleInterface_Outlining) { using namespace ::android::aidl::test_data::example_interface; vector args = { "aidl", "-b", "-I .", "-d an/arbitrary/path/to/dep.P", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); options.onTransact_outline_threshold_ = 4; options.onTransact_non_outline_count_ = 3; // Load up our fake file system with data. io_delegate_.SetFileContents(options.InputFiles().front(), kInterfaceDefinitionOutlining); io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable", {"Subclass1", "Subclass2"}); AddStubAidls(kImportedParcelables, kImportedInterfaces); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutputOutlining); CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput); } TEST_F(EndToEndTest, IExampleInterface_WithVersion) { using namespace ::android::aidl::test_data::example_interface; vector args = { "aidl", "-b", "-I .", "-d an/arbitrary/path/to/dep.P", "--version=10", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); options.onTransact_outline_threshold_ = 4; options.onTransact_non_outline_count_ = 3; // Load up our fake file system with data. io_delegate_.SetFileContents(options.InputFiles().front(), kInterfaceDefinitionOutlining); io_delegate_.AddCompoundParcelable("android.test.CompoundParcelable", {"Subclass1", "Subclass2"}); AddStubAidls(kImportedParcelables, kImportedInterfaces); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutputWithVersion); CheckFileContents(options.DependencyFile(), kExpectedJavaDepsOutput); } TEST_F(EndToEndTest, IPingResponderCpp) { using namespace ::android::aidl::test_data::ping_responder; vector args = { "aidl-cpp", "-d deps.P", "-I .", CanonicalNameToPath(kCanonicalName, ".aidl"), kGenHeaderDir, kCppOutputPath}; Options options = Options::From(args); // Set up input paths. io_delegate_.SetFileContents(CanonicalNameToPath(kCanonicalName, ".aidl"), kInterfaceDefinition); AddStubAidls(kImportedParcelables, kImportedInterfaces, kCppParcelableHeader); // Check that we parse and generate code correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kCppOutputPath, kExpectedCppOutput); CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput); CheckFileContents(kGenClientHeaderPath, kExpectedBpHeaderOutput); CheckFileContents(kGenServerHeaderPath, kExpectedBnHeaderOutput); CheckFileContents(options.DependencyFile(), kExpectedCppDepsOutput); } TEST_F(EndToEndTest, IPingResponderCpp_WithVersion) { using namespace ::android::aidl::test_data::ping_responder; vector args = { "aidl-cpp", "-d deps.P", "-I .", "--version=10", CanonicalNameToPath(kCanonicalName, ".aidl"), kGenHeaderDir, kCppOutputPath}; Options options = Options::From(args); // Set up input paths. io_delegate_.SetFileContents(CanonicalNameToPath(kCanonicalName, ".aidl"), kInterfaceDefinition); AddStubAidls(kImportedParcelables, kImportedInterfaces, kCppParcelableHeader); // Check that we parse and generate code correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kCppOutputPath, kExpectedCppOutputWithVersion); CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutputWithVersion); CheckFileContents(kGenClientHeaderPath, kExpectedBpHeaderOutputWithVersion); CheckFileContents(kGenServerHeaderPath, kExpectedBnHeaderOutputWithVersion); CheckFileContents(options.DependencyFile(), kExpectedCppDepsOutput); } TEST_F(EndToEndTest, StringConstantsInCpp) { using namespace ::android::aidl::test_data::string_constants; vector args = { "aidl-cpp", CanonicalNameToPath(kCanonicalName, ".aidl"), kGenHeaderDir, kCppOutputPath}; Options options = Options::From(args); // Set up input paths. io_delegate_.SetFileContents(CanonicalNameToPath(kCanonicalName, ".aidl"), kInterfaceDefinition); // Check that we parse and generate code correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kCppOutputPath, kExpectedCppOutput); CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutput); } TEST_F(EndToEndTest, StringConstantsInJava) { using namespace ::android::aidl::test_data::string_constants; vector args = { "aidl", "-b", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); // Load up our fake file system with data. io_delegate_.SetFileContents(CanonicalNameToPath(kCanonicalName, ".aidl"), kInterfaceDefinition); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutput); } TEST_F(EndToEndTest, StringConstantsInCpp_WithVersion) { using namespace ::android::aidl::test_data::string_constants; vector args = { "aidl-cpp", "--version=10", CanonicalNameToPath(kCanonicalName, ".aidl"), kGenHeaderDir, kCppOutputPath}; Options options = Options::From(args); // Set up input paths. io_delegate_.SetFileContents(CanonicalNameToPath(kCanonicalName, ".aidl"), kInterfaceDefinition); // Check that we parse and generate code correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kCppOutputPath, kExpectedCppOutputWithVersion); CheckFileContents(kGenInterfaceHeaderPath, kExpectedIHeaderOutputWithVersion); } TEST_F(EndToEndTest, StringConstantsInJava_WithVersion) { using namespace ::android::aidl::test_data::string_constants; vector args = { "aidl", "-b", "--version=10", CanonicalNameToPath(kCanonicalName, ".aidl"), kJavaOutputPath}; Options options = Options::From(args); // Load up our fake file system with data. io_delegate_.SetFileContents(CanonicalNameToPath(kCanonicalName, ".aidl"), kInterfaceDefinition); // Check that we parse correctly. EXPECT_EQ(android::aidl::compile_aidl(options, io_delegate_), 0); CheckFileContents(kJavaOutputPath, kExpectedJavaOutputWithVersion); } } // namespace android } // namespace aidl tests/fake_io_delegate.cpp0100644 0000000 0000000 00000012712 13755771705 014726 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 #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; } ~BrokenCodeWriter() override = 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(); } 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 CodeWriter::ForString(&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; } vector FakeIoDelegate::ListFiles(const string& dir) const { const string dir_name = dir.back() == OS_PATH_SEPARATOR ? dir : dir + OS_PATH_SEPARATOR; vector files; for (auto it = file_contents_.begin(); it != file_contents_.end(); it++) { if (android::base::StartsWith(it->first, dir_name) && !it->second.empty()) { files.emplace_back(it->first); } } return files; } 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 00000006166 13755771705 014401 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; std::unique_ptr GetCodeWriter( const std::string& file_path) const override; void RemovePath(const std::string& file_path) const override; std::vector ListFiles(const std::string& dir) 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 13755771705 014653 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 13755771705 012554 5ustar000000000 0000000 tests/java_app/AndroidManifest.xml0100644 0000000 0000000 00000000755 13755771705 016351 0ustar000000000 0000000 tests/java_app/README0100644 0000000 0000000 00000001104 13755771705 013425 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 13755771705 014566 5ustar000000000 0000000 tests/java_app/resources/values/0040755 0000000 0000000 00000000000 13755771705 016065 5ustar000000000 0000000 tests/java_app/resources/values/strings.xml0100644 0000000 0000000 00000000613 13755771705 020275 0ustar000000000 0000000 AIDL Test Services tests/java_app/src/0040755 0000000 0000000 00000000000 13755771705 013343 5ustar000000000 0000000 tests/java_app/src/android/0040755 0000000 0000000 00000000000 13755771705 014763 5ustar000000000 0000000 tests/java_app/src/android/aidl/0040755 0000000 0000000 00000000000 13755771705 015674 5ustar000000000 0000000 tests/java_app/src/android/aidl/tests/0040755 0000000 0000000 00000000000 13755771705 017036 5ustar000000000 0000000 tests/java_app/src/android/aidl/tests/NullableTests.java0100644 0000000 0000000 00000010444 13755771705 022462 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 13755771705 023102 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 13755771705 023271 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 13755771705 021756 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 00000115203 13755771705 023277 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.StructuredParcelable; 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.ParcelFileDescriptor; 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 = 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 checkParcelFileDescriptorPassing(ITestService service) throws TestFailException { mLog.log("Checking that service can receive and return parcel file descriptors..."); try { ParcelFileDescriptor descriptor = ParcelFileDescriptor.open( getFileStreamPath("test-dummy"), ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_WRITE_ONLY); ParcelFileDescriptor journeyed = service.RepeatParcelFileDescriptor(descriptor); FileOutputStream journeyedStream = new ParcelFileDescriptor.AutoCloseOutputStream(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"); final List utf8_queries_and_nulls = Arrays.asList( "typical string", null, "", "\0\0\0", null, // 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]); } } } { String[] input = (String[])utf8_queries_and_nulls.toArray(); String echoed[] = new String[input.length]; String[] reversed = service.ReverseNullableUtf8CppString(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] == null && reversed[j] == null) { continue; } 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."); } private void checkStructuredParcelable(ITestService service) throws TestFailException { final int kDesiredFValue = 17; StructuredParcelable parcelable = new StructuredParcelable(); parcelable.shouldContainThreeFs = new int[0]; parcelable.f = kDesiredFValue; parcelable.shouldBeJerry = ""; if (!parcelable.stringDefaultsToFoo.equals("foo")) { mLog.logAndThrow( "stringDefaultsToFoo should be 'foo' but is " + parcelable.stringDefaultsToFoo); } if (parcelable.byteDefaultsToFour != 4) { mLog.logAndThrow("byteDefaultsToFour should be 4 but is " + parcelable.byteDefaultsToFour); } if (parcelable.intDefaultsToFive != 5) { mLog.logAndThrow("intDefaultsToFive should be 5 but is " + parcelable.intDefaultsToFive); } if (parcelable.longDefaultsToNegativeSeven != -7) { mLog.logAndThrow("longDefaultsToNegativeSeven should be -7 but is " + parcelable.longDefaultsToNegativeSeven); } if (!parcelable.booleanDefaultsToTrue) { mLog.logAndThrow("booleanDefaultsToTrue should be true"); } if (parcelable.charDefaultsToC != 'C') { mLog.logAndThrow("charDefaultsToC is " + parcelable.charDefaultsToC); } if (parcelable.floatDefaultsToPi != 3.14f) { mLog.logAndThrow("floatDefaultsToPi is " + parcelable.floatDefaultsToPi); } if (parcelable.doubleWithDefault != -3.14e17) { mLog.logAndThrow( "doubleWithDefault is " + parcelable.doubleWithDefault + " but should be -3.14e17"); } if (!Arrays.equals(parcelable.arrayDefaultsTo123, new int[] {1, 2, 3})) { mLog.logAndThrow("arrayDefaultsTo123 should be [1,2,3] but is " + Arrays.toString(parcelable.arrayDefaultsTo123)); } if (parcelable.arrayDefaultsToEmpty.length != 0) { mLog.logAndThrow("arrayDefaultsToEmpty should be empty but is " + Arrays.toString(parcelable.arrayDefaultsToEmpty)); } try { service.FillOutStructuredParcelable(parcelable); } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Service failed to handle structured parcelable."); } if (!Arrays.equals(parcelable.shouldContainThreeFs, new int[] {kDesiredFValue, kDesiredFValue, kDesiredFValue})) { mLog.logAndThrow( "shouldContainThreeFs is " + Arrays.toString(parcelable.shouldContainThreeFs)); } if (!parcelable.shouldBeJerry.equals("Jerry")) { mLog.logAndThrow("shouldBeJerry should be 'Jerry' but is " + parcelable.shouldBeJerry); } } private void checkDefaultImpl(ITestService service) throws TestFailException { final int expectedArg = 100; final int expectedReturnValue = 200; boolean success = ITestService.Stub.setDefaultImpl(new ITestService.Default() { @Override public int UnimplementedMethod(int arg) throws RemoteException { if (arg != expectedArg) { throw new RemoteException("Argument for UnimplementedMethod is expected " + " to be " + expectedArg + ", but got " + arg); } return expectedReturnValue; } }); if (!success) { mLog.logAndThrow("Failed to set default impl for ITestService"); } try { int ret = service.UnimplementedMethod(expectedArg); if (ret != expectedReturnValue) { mLog.logAndThrow("Return value from UnimplementedMethod is expected " + " to be " + expectedReturnValue + ", but got " + ret); } } catch (RemoteException ex) { mLog.log(ex.toString()); mLog.logAndThrow("Failed to call UnimplementedMethod"); } } @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); checkParcelFileDescriptorPassing(service); checkServiceSpecificExceptions(service); checkUtf8Strings(service); checkStructuredParcelable(service); new NullableTests(service, mLog).runTests(); checkDefaultImpl(service); 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 13755771705 012412 0ustar000000000 0000000 #include int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } tests/simple_parcelable.cpp0100644 0000000 0000000 00000003077 13755771705 015146 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 13755771705 014613 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 00000005620 13755771705 013114 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 kInterfaceDefinitionOutlining[]; extern const char* kImportedParcelables[]; extern const char* kImportedInterfaces[]; extern const char kExpectedJavaDepsOutput[]; extern const char kExpectedJavaOutput[]; extern const char kExpectedJavaOutputOutlining[]; extern const char kExpectedJavaOutputWithTransactionNames[]; extern const char kExpectedJavaOutputWithTrace[]; extern const char kExpectedJavaOutputWithVersion[]; } // 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[]; extern const char kExpectedCppOutputWithVersion[]; extern const char kExpectedIHeaderOutputWithVersion[]; extern const char kExpectedBpHeaderOutputWithVersion[]; extern const char kExpectedBnHeaderOutputWithVersion[]; } // 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 kExpectedJavaOutputWithVersion[]; extern const char kCppOutputPath[]; extern const char kGenHeaderDir[]; extern const char kGenInterfaceHeaderPath[]; extern const char kExpectedIHeaderOutput[]; extern const char kExpectedCppOutput[]; extern const char kExpectedIHeaderOutputWithVersion[]; extern const char kExpectedCppOutputWithVersion[]; } // namespace string_constants } // namespace test_data } // namespace aidl } // namespace android #endif // AIDL_TESTS_TEST_DATA_H_ tests/test_data_example_interface.cpp0100644 0000000 0000000 00000276262 13755771705 017216 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; @SystemApi @UnsupportedAppUsage interface IExampleInterface { const int EXAMPLE_CONSTANT = 3; boolean isEnabled(); int getState(); String getAddress(); /* Test long comment */ @UnsupportedAppUsage @SystemApi 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 kInterfaceDefinitionOutlining[] = 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(int a, int b); 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/bar/IAuxInterface.aidl \ ./android/foo/ExampleParcelable.aidl \ ./android/test/CompoundParcelable.aidl \ ./android/test/IAuxInterface2.aidl android/test/IExampleInterface.aidl : ./android/bar/IAuxInterface.aidl : ./android/foo/ExampleParcelable.aidl : ./android/test/CompoundParcelable.aidl : ./android/test/IAuxInterface2.aidl : )"; const char kExpectedJavaOutput[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ package android.test; @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi public interface IExampleInterface extends android.os.IInterface { /** Default implementation for IExampleInterface. */ public static class Default implements android.test.IExampleInterface { @Override public boolean isEnabled() throws android.os.RemoteException { return false; } @Override public int getState() throws android.os.RemoteException { return 0; } @Override public java.lang.String getAddress() throws android.os.RemoteException { return null; } /* Test long comment */ @Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException { return null; } // Test short comment @Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException { return false; } /* Test long comment */// And short comment @Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException { } @Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException { return null; } @Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException { return 0; } @Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException { return 0; } @Override public android.os.IBinder asBinder() { return null; } } /** 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 { java.lang.String descriptor = DESCRIPTOR; 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; } default: { 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); boolean _status = mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().isEnabled(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getState(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getAddress(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getParcelables(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().setScanMode(mode, duration); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().registerBinder(foo); return; } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getRecursiveBinder(); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAnInterface(arg); } _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); } boolean _status = mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAParcelable(arg, arg2); } _reply.readException(); _result = _reply.readInt(); if ((0!=_reply.readInt())) { arg2.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } return _result; } public static android.test.IExampleInterface sDefaultImpl; } 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 boolean setDefaultImpl(android.test.IExampleInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.test.IExampleInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } 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 */ @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi 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; } )"; const char kExpectedJavaOutputWithTransactionNames[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ package android.test; @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi public interface IExampleInterface extends android.os.IInterface { /** Default implementation for IExampleInterface. */ public static class Default implements android.test.IExampleInterface { @Override public boolean isEnabled() throws android.os.RemoteException { return false; } @Override public int getState() throws android.os.RemoteException { return 0; } @Override public java.lang.String getAddress() throws android.os.RemoteException { return null; } /* Test long comment */ @Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException { return null; } // Test short comment @Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException { return false; } /* Test long comment */// And short comment @Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException { } @Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException { return null; } @Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException { return 0; } @Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException { return 0; } @Override public android.os.IBinder asBinder() { return null; } } /** 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; } /** @hide */ public static java.lang.String getDefaultTransactionName(int transactionCode) { switch (transactionCode) { case TRANSACTION_isEnabled: { return "isEnabled"; } case TRANSACTION_getState: { return "getState"; } case TRANSACTION_getAddress: { return "getAddress"; } case TRANSACTION_getParcelables: { return "getParcelables"; } case TRANSACTION_setScanMode: { return "setScanMode"; } case TRANSACTION_registerBinder: { return "registerBinder"; } case TRANSACTION_getRecursiveBinder: { return "getRecursiveBinder"; } case TRANSACTION_takesAnInterface: { return "takesAnInterface"; } case TRANSACTION_takesAParcelable: { return "takesAParcelable"; } default: { return null; } } } /** @hide */ public java.lang.String getTransactionName(int transactionCode) { return this.getDefaultTransactionName(transactionCode); } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; 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; } default: { 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); boolean _status = mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().isEnabled(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getState(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getAddress(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getParcelables(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().setScanMode(mode, duration); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().registerBinder(foo); return; } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getRecursiveBinder(); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAnInterface(arg); } _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); } boolean _status = mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAParcelable(arg, arg2); } _reply.readException(); _result = _reply.readInt(); if ((0!=_reply.readInt())) { arg2.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } return _result; } public static android.test.IExampleInterface sDefaultImpl; } 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 boolean setDefaultImpl(android.test.IExampleInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.test.IExampleInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } 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 */ @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi 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; } )"; const char kExpectedJavaOutputWithTrace[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ package android.test; @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi public interface IExampleInterface extends android.os.IInterface { /** Default implementation for IExampleInterface. */ public static class Default implements android.test.IExampleInterface { @Override public boolean isEnabled() throws android.os.RemoteException { return false; } @Override public int getState() throws android.os.RemoteException { return 0; } @Override public java.lang.String getAddress() throws android.os.RemoteException { return null; } /* Test long comment */ @Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException { return null; } // Test short comment @Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException { return false; } /* Test long comment */// And short comment @Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException { } @Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException { return null; } @Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException { return 0; } @Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException { return 0; } @Override public android.os.IBinder asBinder() { return null; } } /** 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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_isEnabled: { data.enforceInterface(descriptor); boolean _result; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::isEnabled::server"); _result = this.isEnabled(); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } reply.writeNoException(); reply.writeInt(((_result)?(1):(0))); return true; } case TRANSACTION_getState: { data.enforceInterface(descriptor); int _result; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getState::server"); _result = this.getState(); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_getAddress: { data.enforceInterface(descriptor); java.lang.String _result; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getAddress::server"); _result = this.getAddress(); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_getParcelables: { data.enforceInterface(descriptor); android.foo.ExampleParcelable[] _result; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getParcelables::server"); _result = this.getParcelables(); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::setScanMode::server"); _result = this.setScanMode(_arg0, _arg1); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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()); try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::registerBinder::server"); this.registerBinder(_arg0); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } reply.writeNoException(); return true; } case TRANSACTION_getRecursiveBinder: { data.enforceInterface(descriptor); android.test.IExampleInterface _result; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getRecursiveBinder::server"); _result = this.getRecursiveBinder(); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAnInterface::server"); _result = this.takesAnInterface(_arg0); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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; try { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAParcelable::server"); _result = this.takesAParcelable(_arg0, _arg1); } finally { android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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; } default: { 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::isEnabled::client"); _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().isEnabled(); } _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getState::client"); _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getState(); } _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getAddress::client"); _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getAddress(); } _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getParcelables::client"); _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getParcelables(); } _reply.readException(); _result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::setScanMode::client"); _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(mode); _data.writeInt(duration); boolean _status = mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().setScanMode(mode, duration); } _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::registerBinder::client"); _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null))); boolean _status = mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().registerBinder(foo); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } } @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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::getRecursiveBinder::client"); _data.writeInterfaceToken(DESCRIPTOR); boolean _status = mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getRecursiveBinder(); } _reply.readException(); _result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder()); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAnInterface::client"); _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null))); boolean _status = mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAnInterface(arg); } _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } 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 { android.os.Trace.traceBegin(android.os.Trace.TRACE_TAG_AIDL, "IExampleInterface::takesAParcelable::client"); _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); } boolean _status = mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAParcelable(arg, arg2); } _reply.readException(); _result = _reply.readInt(); if ((0!=_reply.readInt())) { arg2.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); android.os.Trace.traceEnd(android.os.Trace.TRACE_TAG_AIDL); } return _result; } public static android.test.IExampleInterface sDefaultImpl; } 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 boolean setDefaultImpl(android.test.IExampleInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.test.IExampleInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } 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 */ @android.annotation.UnsupportedAppUsage @android.annotation.SystemApi 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; } )"; const char kExpectedJavaOutputOutlining[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ package android.test; public interface IExampleInterface extends android.os.IInterface { /** Default implementation for IExampleInterface. */ public static class Default implements android.test.IExampleInterface { @Override public boolean isEnabled() throws android.os.RemoteException { return false; } @Override public int getState(int a, int b) throws android.os.RemoteException { return 0; } @Override public java.lang.String getAddress() throws android.os.RemoteException { return null; } /* Test long comment */ @Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException { return null; } // Test short comment @Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException { return false; } /* Test long comment */// And short comment @Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException { } @Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException { return null; } @Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException { return 0; } @Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException { return 0; } @Override public android.os.IBinder asBinder() { return null; } } /** 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 { java.lang.String descriptor = DESCRIPTOR; 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: { return this.onTransact$getState$(data, reply); } 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: { return this.onTransact$setScanMode$(data, reply); } case TRANSACTION_registerBinder: { return this.onTransact$registerBinder$(data, reply); } case TRANSACTION_getRecursiveBinder: { return this.onTransact$getRecursiveBinder$(data, reply); } case TRANSACTION_takesAnInterface: { return this.onTransact$takesAnInterface$(data, reply); } case TRANSACTION_takesAParcelable: { return this.onTransact$takesAParcelable$(data, reply); } default: { 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); boolean _status = mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().isEnabled(); } _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int getState(int a, int b) 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.writeInt(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getState(a, b); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getAddress(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getParcelables(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().setScanMode(mode, duration); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().registerBinder(foo); return; } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getRecursiveBinder(); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAnInterface(arg); } _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); } boolean _status = mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAParcelable(arg, arg2); } _reply.readException(); _result = _reply.readInt(); if ((0!=_reply.readInt())) { arg2.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } return _result; } public static android.test.IExampleInterface sDefaultImpl; } static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); private boolean onTransact$getState$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.getState(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } 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); private boolean onTransact$setScanMode$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { 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; } static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); private boolean onTransact$registerBinder$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { data.enforceInterface(DESCRIPTOR); android.bar.IAuxInterface _arg0; _arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder()); this.registerBinder(_arg0); reply.writeNoException(); return true; } static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); private boolean onTransact$getRecursiveBinder$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { data.enforceInterface(DESCRIPTOR); android.test.IExampleInterface _result = this.getRecursiveBinder(); reply.writeNoException(); reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null))); return true; } static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); private boolean onTransact$takesAnInterface$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { 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; } static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); private boolean onTransact$takesAParcelable$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { 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; } public static boolean setDefaultImpl(android.test.IExampleInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.test.IExampleInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } public static final int EXAMPLE_CONSTANT = 3; public boolean isEnabled() throws android.os.RemoteException; public int getState(int a, int b) 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; } )"; const char kExpectedJavaOutputWithVersion[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ package android.test; public interface IExampleInterface extends android.os.IInterface { /** * The version of this interface that the caller is built against. * This might be different from what {@link #getInterfaceVersion() * getInterfaceVersion} returns as that is the version of the interface * that the remote object is implementing. */ public static final int VERSION = 10; /** Default implementation for IExampleInterface. */ public static class Default implements android.test.IExampleInterface { @Override public boolean isEnabled() throws android.os.RemoteException { return false; } @Override public int getState(int a, int b) throws android.os.RemoteException { return 0; } @Override public java.lang.String getAddress() throws android.os.RemoteException { return null; } /* Test long comment */ @Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException { return null; } // Test short comment @Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException { return false; } /* Test long comment */// And short comment @Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException { } @Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException { return null; } @Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException { return 0; } @Override public int takesAParcelable(android.test.CompoundParcelable.Subclass1 arg, android.test.CompoundParcelable.Subclass2 arg2) throws android.os.RemoteException { return 0; } @Override public int getInterfaceVersion() { return -1; } @Override public android.os.IBinder asBinder() { return null; } } /** 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 { java.lang.String descriptor = DESCRIPTOR; 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: { return this.onTransact$getState$(data, reply); } 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: { return this.onTransact$setScanMode$(data, reply); } case TRANSACTION_registerBinder: { return this.onTransact$registerBinder$(data, reply); } case TRANSACTION_getRecursiveBinder: { return this.onTransact$getRecursiveBinder$(data, reply); } case TRANSACTION_takesAnInterface: { return this.onTransact$takesAnInterface$(data, reply); } case TRANSACTION_takesAParcelable: { return this.onTransact$takesAParcelable$(data, reply); } case TRANSACTION_getInterfaceVersion: { data.enforceInterface(descriptor); reply.writeNoException(); reply.writeInt(getInterfaceVersion()); return true; } default: { 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; } private int mCachedVersion = -1; @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); boolean _status = mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().isEnabled(); } _reply.readException(); _result = (0!=_reply.readInt()); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int getState(int a, int b) 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.writeInt(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getState(a, b); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getAddress(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getParcelables(); } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().setScanMode(mode, duration); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().registerBinder(foo); return; } _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); boolean _status = mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().getRecursiveBinder(); } _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))); boolean _status = mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAnInterface(arg); } _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); } boolean _status = mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().takesAParcelable(arg, arg2); } _reply.readException(); _result = _reply.readInt(); if ((0!=_reply.readInt())) { arg2.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int getInterfaceVersion() throws android.os.RemoteException { if (mCachedVersion == -1) { android.os.Parcel data = android.os.Parcel.obtain(); android.os.Parcel reply = android.os.Parcel.obtain(); try { data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getInterfaceVersion, data, reply, 0); reply.readException(); mCachedVersion = reply.readInt(); } finally { reply.recycle(); data.recycle(); } } return mCachedVersion; } public static android.test.IExampleInterface sDefaultImpl; } static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); private boolean onTransact$getState$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.getState(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } 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); private boolean onTransact$setScanMode$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { 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; } static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); private boolean onTransact$registerBinder$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { data.enforceInterface(DESCRIPTOR); android.bar.IAuxInterface _arg0; _arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder()); this.registerBinder(_arg0); reply.writeNoException(); return true; } static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); private boolean onTransact$getRecursiveBinder$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { data.enforceInterface(DESCRIPTOR); android.test.IExampleInterface _result = this.getRecursiveBinder(); reply.writeNoException(); reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null))); return true; } static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); private boolean onTransact$takesAnInterface$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { 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; } static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); private boolean onTransact$takesAParcelable$(android.os.Parcel data, android.os.Parcel reply) throws android.os.RemoteException { 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; } static final int TRANSACTION_getInterfaceVersion = (android.os.IBinder.FIRST_CALL_TRANSACTION + 16777214); public static boolean setDefaultImpl(android.test.IExampleInterface impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.test.IExampleInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } public static final int EXAMPLE_CONSTANT = 3; public boolean isEnabled() throws android.os.RemoteException; public int getState(int a, int b) 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; public int getInterfaceVersion() throws android.os.RemoteException; } )"; } // namespace example_interface } // namespace test_data } // namespace aidl } // namespace android tests/test_data_ping_responder.cpp0100644 0000000 0000000 00000100315 13755771705 016542 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") ::android::IBinder* IPingResponderDefault::onAsBinder() { return nullptr; } ::android::binder::Status IPingResponderDefault::Ping(const ::android::String16&, ::android::String16* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IPingResponderDefault::NullablePing(const ::std::unique_ptr<::android::String16>&, ::std::unique_ptr<::android::String16>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IPingResponderDefault::Utf8Ping(const ::std::string&, ::std::string* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IPingResponderDefault::NullableUtf8Ping(const ::std::unique_ptr<::std::string>&, ::std::unique_ptr<::std::string>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } } // namespace os } // namespace android #include #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(::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* Ping */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->Ping(input, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* NullablePing */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->NullablePing(input, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* Utf8Ping */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->Utf8Ping(input, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* NullableUtf8Ping */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->NullableUtf8Ping(input, _aidl_return); } 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* 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; }; // class IPingResponder class IPingResponderDefault : public IPingResponder { public: ::android::IBinder* onAsBinder() override; ::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; }; } // 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) override; }; // class BnPingResponder } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_BN_PING_RESPONDER_H_ )"; const char kExpectedCppOutputWithVersion[] = R"(#include #include namespace android { namespace os { IMPLEMENT_META_INTERFACE(PingResponder, "android.os.IPingResponder") ::android::IBinder* IPingResponderDefault::onAsBinder() { return nullptr; } ::android::binder::Status IPingResponderDefault::Ping(const ::android::String16&, ::android::String16* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IPingResponderDefault::NullablePing(const ::std::unique_ptr<::android::String16>&, ::std::unique_ptr<::android::String16>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IPingResponderDefault::Utf8Ping(const ::std::string&, ::std::string* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } ::android::binder::Status IPingResponderDefault::NullableUtf8Ping(const ::std::unique_ptr<::std::string>&, ::std::unique_ptr<::std::string>* ) { return ::android::binder::Status::fromStatusT(::android::UNKNOWN_TRANSACTION); } int32_t IPingResponderDefault::getInterfaceVersion() { return 0; } } // namespace os } // namespace android #include #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(::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* Ping */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->Ping(input, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* NullablePing */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->NullablePing(input, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* Utf8Ping */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->Utf8Ping(input, _aidl_return); } 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(::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* NullableUtf8Ping */, _aidl_data, &_aidl_reply); if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IPingResponder::getDefaultImpl())) { return IPingResponder::getDefaultImpl()->NullableUtf8Ping(input, _aidl_return); } 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; } int32_t BpPingResponder::getInterfaceVersion() { if (cached_version_ == -1) { ::android::Parcel data; ::android::Parcel reply; data.writeInterfaceToken(getInterfaceDescriptor()); ::android::status_t err = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 16777214 /* getInterfaceVersion */, data, &reply); if (err == ::android::OK) { ::android::binder::Status _aidl_status; err = _aidl_status.readFromParcel(reply); if (err == ::android::OK && _aidl_status.isOk()) { cached_version_ = reply.readInt32(); } } } return cached_version_; } } // 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 0 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 1 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 2 /* 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 ::android::IBinder::FIRST_CALL_TRANSACTION + 3 /* 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; case ::android::IBinder::FIRST_CALL_TRANSACTION + 16777214 /* getInterfaceVersion */: { _aidl_data.checkInterface(this); _aidl_reply->writeNoException(); _aidl_reply->writeInt32(IPingResponder::VERSION); } 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; } int32_t BnPingResponder::getInterfaceVersion() { return IPingResponder::VERSION; } } // namespace os } // namespace android )"; const char kExpectedIHeaderOutputWithVersion[] = 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) const int32_t VERSION = 10; 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; virtual int32_t getInterfaceVersion() = 0; }; // class IPingResponder class IPingResponderDefault : public IPingResponder { public: ::android::IBinder* onAsBinder() override; ::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; int32_t getInterfaceVersion() override; }; } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_I_PING_RESPONDER_H_ )"; const char kExpectedBpHeaderOutputWithVersion[] = 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; int32_t getInterfaceVersion() override; private: int32_t cached_version_ = -1; }; // class BpPingResponder } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_BP_PING_RESPONDER_H_ )"; const char kExpectedBnHeaderOutputWithVersion[] = 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) override; int32_t getInterfaceVersion() final 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 00000033372 13755771705 017136 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. */ package android.os; public interface IStringConstants extends android.os.IInterface { /** Default implementation for IStringConstants. */ public static class Default implements android.os.IStringConstants { @Override public android.os.IBinder asBinder() { return null; } } /** 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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } default: { 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 android.os.IStringConstants sDefaultImpl; } public static boolean setDefaultImpl(android.os.IStringConstants impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.os.IStringConstants getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } 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 class IStringConstantsDefault : public IStringConstants { public: ::android::IBinder* onAsBinder() override; }; } // 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(::android::String16("foo")); return value; } ::android::IBinder* IStringConstantsDefault::onAsBinder() { return nullptr; } } // namespace os } // namespace android #include #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 )"; const char kExpectedJavaOutputWithVersion[] = R"(/* * This file is auto-generated. DO NOT MODIFY. */ package android.os; public interface IStringConstants extends android.os.IInterface { /** * The version of this interface that the caller is built against. * This might be different from what {@link #getInterfaceVersion() * getInterfaceVersion} returns as that is the version of the interface * that the remote object is implementing. */ public static final int VERSION = 10; /** Default implementation for IStringConstants. */ public static class Default implements android.os.IStringConstants { @Override public int getInterfaceVersion() { return -1; } @Override public android.os.IBinder asBinder() { return null; } } /** 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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_getInterfaceVersion: { data.enforceInterface(descriptor); reply.writeNoException(); reply.writeInt(getInterfaceVersion()); return true; } default: { 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; } private int mCachedVersion = -1; @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public int getInterfaceVersion() throws android.os.RemoteException { if (mCachedVersion == -1) { android.os.Parcel data = android.os.Parcel.obtain(); android.os.Parcel reply = android.os.Parcel.obtain(); try { data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getInterfaceVersion, data, reply, 0); reply.readException(); mCachedVersion = reply.readInt(); } finally { reply.recycle(); data.recycle(); } } return mCachedVersion; } public static android.os.IStringConstants sDefaultImpl; } static final int TRANSACTION_getInterfaceVersion = (android.os.IBinder.FIRST_CALL_TRANSACTION + 16777214); public static boolean setDefaultImpl(android.os.IStringConstants impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static android.os.IStringConstants getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } public static final String EXAMPLE_CONSTANT = "foo"; public int getInterfaceVersion() throws android.os.RemoteException; } )"; const char kExpectedIHeaderOutputWithVersion[] = 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) const int32_t VERSION = 10; static const ::android::String16& EXAMPLE_CONSTANT(); virtual int32_t getInterfaceVersion() = 0; }; // class IStringConstants class IStringConstantsDefault : public IStringConstants { public: ::android::IBinder* onAsBinder() override; int32_t getInterfaceVersion() override; }; } // namespace os } // namespace android #endif // AIDL_GENERATED_ANDROID_OS_I_STRING_CONSTANTS_H_ )"; const char kExpectedCppOutputWithVersion[] = 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(::android::String16("foo")); return value; } ::android::IBinder* IStringConstantsDefault::onAsBinder() { return nullptr; } int32_t IStringConstantsDefault::getInterfaceVersion() { return 0; } } // namespace os } // namespace android #include #include #include namespace android { namespace os { BpStringConstants::BpStringConstants(const ::android::sp<::android::IBinder>& _aidl_impl) : BpInterface(_aidl_impl){ } int32_t BpStringConstants::getInterfaceVersion() { if (cached_version_ == -1) { ::android::Parcel data; ::android::Parcel reply; data.writeInterfaceToken(getInterfaceDescriptor()); ::android::status_t err = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 16777214 /* getInterfaceVersion */, data, &reply); if (err == ::android::OK) { ::android::binder::Status _aidl_status; err = _aidl_status.readFromParcel(reply); if (err == ::android::OK && _aidl_status.isOk()) { cached_version_ = reply.readInt32(); } } } return cached_version_; } } // 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) { case ::android::IBinder::FIRST_CALL_TRANSACTION + 16777214 /* getInterfaceVersion */: { _aidl_data.checkInterface(this); _aidl_reply->writeNoException(); _aidl_reply->writeInt32(IStringConstants::VERSION); } 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; } int32_t BnStringConstants::getInterfaceVersion() { return IStringConstants::VERSION; } } // namespace os } // namespace android )"; } // namespace string_constants } // namespace test_data } // namespace aidl } // namespace android tests/test_helpers.h0100644 0000000 0000000 00000004637 13755771705 013654 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 13755771705 013511 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 13755771705 013156 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 00000051224 13755771705 012161 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 #include "logging.h" using std::string; using std::vector; 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; class VoidType : public Type { public: VoidType() : Type(ValidatableType::KIND_BUILT_IN, kNoPackage, "void", {}, "void", kNoValidMethod, kNoValidMethod) {} ~VoidType() override = default; 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& underlying_cpp_type_nulllable, 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_nulllable, underlying_cpp_type_nulllable, read_method, write_method, true), src_file_name) {} 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, cpp_type, read_array_method, write_array_method, false)) {} ~PrimitiveType() override = 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", "uint8_t", "readByteVector", "writeByteVector", false)) {} ~ByteType() override = default; bool IsCppPrimitive() const override { return true; } private: DISALLOW_COPY_AND_ASSIGN(ByteType); }; // class PrimitiveType static string GetCppHeader(const AidlDefinedType& defined_type) { vector name = defined_type.GetSplitPackage(); name.push_back(defined_type.GetName()); return Join(name, '/') + ".h"; } class BinderType : public Type { public: BinderType(const AidlInterface& interface, const std::string& src_file_name) : BinderType(interface, src_file_name, new BinderType(interface, src_file_name, kNoNullableType, "readNullableStrongBinder"), "readStrongBinder") {} ~BinderType() override = 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), 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; } std::string write_cast_; }; class NullableParcelableType : public Type { public: NullableParcelableType(const AidlParcelable& parcelable, const std::string& cpp_header, const std::string& src_file_name) : Type(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(), {cpp_header}, GetCppName(parcelable), "readParcelable", "writeNullableParcelable", kNoArrayType, kNoNullableType, src_file_name) {} ~NullableParcelableType() override = default; 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& cpp_header, const std::string& src_file_name) : Type(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(), {cpp_header}, GetCppName(parcelable), "readParcelable", "writeParcelable", new CppArrayType(ValidatableType::KIND_PARCELABLE, parcelable.GetPackage(), parcelable.GetName(), cpp_header, GetCppName(parcelable), GetCppName(parcelable), "readParcelableVector", "writeParcelableVector", false, src_file_name), new NullableParcelableType(parcelable, cpp_header, src_file_name), src_file_name) {} ~ParcelableType() override = default; 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") {} ~NullableMap() override = default; }; 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() ) {} ~MapType() override = default; 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") {} ~NullableStringListType() override = default; 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()) {} ~StringListType() override = default; 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") {} ~NullableUtf8InCppStringListType() override = default; 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()) {} ~Utf8InCppStringListType() override = default; 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") {} ~NullableBinderListType() override = default; 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()) {} ~BinderListType() override = default; 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(std::make_unique()); Add(std::make_unique("int", "cstdint", "int32_t", "readInt32", "writeInt32", "readInt32Vector", "writeInt32Vector")); Add(std::make_unique("long", "cstdint", "int64_t", "readInt64", "writeInt64", "readInt64Vector", "writeInt64Vector")); Add(std::make_unique("float", kNoHeader, "float", "readFloat", "writeFloat", "readFloatVector", "writeFloatVector")); Add(std::make_unique("double", kNoHeader, "double", "readDouble", "writeDouble", "readDoubleVector", "writeDoubleVector")); Add(std::make_unique("boolean", kNoHeader, "bool", "readBool", "writeBool", "readBoolVector", "writeBoolVector")); // C++11 defines the char16_t type as a built in for Unicode characters. Add(std::make_unique("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", "::std::unique_ptr<::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"); AddAndSetMember(&string_type_, std::make_unique(ValidatableType::KIND_BUILT_IN, "java.lang", "String", std::vector{"utils/String16.h"}, "::android::String16", "readString16", "writeString16", string_array_type, nullable_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", "::std::unique_ptr<::std::string>", "readUtf8VectorFromUtf16Vector", "writeUtf8VectorAsUtf16Vector", false); Type* nullable_cpp_utf8_string_type = new Type(ValidatableType::KIND_BUILT_IN, kAidlReservedTypePackage, kUtf8InCppStringClass, std::vector{"string", "memory"}, "::std::unique_ptr<::std::string>", "readUtf8FromUtf16", "writeUtf8AsUtf16"); Add(std::make_unique(ValidatableType::KIND_BUILT_IN, kAidlReservedTypePackage, kUtf8InCppStringClass, std::vector{"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"); AddAndSetMember(&ibinder_type_, std::make_unique(ValidatableType::KIND_BUILT_IN, "android.os", "IBinder", std::vector{"binder/IBinder.h"}, "::android::sp<::android::IBinder>", "readStrongBinder", "writeStrongBinder", kNoArrayType, nullable_ibinder)); Add(std::make_unique()); Add(std::make_unique()); Add(std::make_unique()); Add(std::make_unique()); Type* fd_vector_type = new CppArrayType( ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor", "android-base/unique_fd.h", "::android::base::unique_fd", "::android::base::unique_fd", "readUniqueFileDescriptorVector", "writeUniqueFileDescriptorVector", false); Add(std::make_unique(ValidatableType::KIND_BUILT_IN, kNoPackage, "FileDescriptor", std::vector{"android-base/unique_fd.h"}, "::android::base::unique_fd", "readUniqueFileDescriptor", "writeUniqueFileDescriptor", fd_vector_type)); Type* pfd_vector_type = new CppArrayType(ValidatableType::KIND_BUILT_IN, "android.os", "ParcelFileDescriptor", "binder/ParcelFileDescriptor.h", "::android::os::ParcelFileDescriptor", "::android::os::ParcelFileDescriptor", "readParcelableVector", "writeParcelableVector", false); Type* nullable_pfd_type = new Type(ValidatableType::KIND_BUILT_IN, "android.os", "ParcelFileDescriptor", std::vector{"memory", "binder/ParcelFileDescriptor.h"}, "::std::unique_ptr<::android::os::ParcelFileDescriptor>", "readParcelable", "writeNullableParcelable"); Add(std::make_unique(ValidatableType::KIND_BUILT_IN, "android.os", "ParcelFileDescriptor", std::vector{"binder/ParcelFileDescriptor.h"}, "::android::os::ParcelFileDescriptor", "readParcelable", "writeParcelable", pfd_vector_type, nullable_pfd_type)); // Qualify VoidType so we don't get collisions with the VoidType method AddAndSetMember(&void_type_, std::make_unique()); } bool TypeNamespace::AddParcelableType(const AidlParcelable& p, const std::string& filename) { const std::string cpp_header = p.AsStructuredParcelable() ? GetCppHeader(p) : p.GetCppHeader(); if (cpp_header.empty()) { AIDL_ERROR(p) << "Parcelable " << p.GetCanonicalName() << " has no C++ header defined."; return false; } Add(std::make_unique(p, cpp_header, filename)); return true; } bool TypeNamespace::AddBinderType(const AidlInterface& b, const std::string& filename) { Add(std::make_unique(b, filename)); 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; } const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index, const AidlDefinedType& context) const { return ::android::aidl::TypeNamespace::GetArgType(a, arg_index, context); } } // namespace cpp } // namespace aidl } // namespace android type_cpp.h0100644 0000000 0000000 00000007264 13755771705 011633 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. */ #pragma once #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 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; const ValidatableType* GetArgType(const AidlArgument& a, int arg_index, const AidlDefinedType& context) const override; const Type* VoidType() const { return void_type_; } const Type* IBinderType() const { return ibinder_type_; } private: const Type* void_type_ = nullptr; const Type* string_type_ = nullptr; const Type* ibinder_type_ = nullptr; DISALLOW_COPY_AND_ASSIGN(TypeNamespace); }; // class TypeNamespace } // namespace cpp } // namespace aidl } // namespace android type_cpp_unittest.cpp0100644 0000000 0000000 00000004031 13755771705 014112 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( AIDL_LOCATION_HERE, new AidlQualifiedName(AIDL_LOCATION_HERE, kParcelableDotName, ""), {"a", "goog"}, "")); EXPECT_EQ(parcelable->GetCppName(), kParcelableColonName); } } // namespace cpp } // namespace android } // namespace aidl type_java.cpp0100644 0000000 0000000 00000036302 13755771705 012320 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 #include "aidl_language.h" #include "logging.h" using std::string; 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) : Type(types, "", name, kind, canWriteToParcel, "", -1) {} Type::Type(const JavaTypeNamespace* types, const string& package, const string& name, int kind, bool canWriteToParcel, const string& declFile, int declLine) : ValidatableType(kind, package, name, declFile, declLine), m_types(types), m_javaType((package.empty()) ? name : package + "." + name), m_canWriteToParcel(canWriteToParcel) {} string Type::InstantiableName() const { return 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()->JavaType(), "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), m_marshallParcel(marshallParcel), m_unmarshallParcel(unmarshallParcel) { m_array_type.reset(new BasicArrayType(types, name, writeArrayParcel, createArrayParcel, readArrayParcel)); } 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), m_writeArrayParcel(writeArrayParcel), m_createArrayParcel(createArrayParcel), m_readArrayParcel(readArrayParcel) {} // ================================================================ FileDescriptorType::FileDescriptorType(const JavaTypeNamespace* types) : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN, true) { m_array_type.reset(new FileDescriptorArrayType(types)); } FileDescriptorArrayType::FileDescriptorArrayType(const JavaTypeNamespace* types) : Type(types, "java.io", "FileDescriptor", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ ParcelFileDescriptorType::ParcelFileDescriptorType(const JavaTypeNamespace* types) : Type(types, "android.os", "ParcelFileDescriptor", ValidatableType::KIND_BUILT_IN, true) { m_array_type.reset(new ParcelFileDescriptorArrayType(types)); } ParcelFileDescriptorArrayType::ParcelFileDescriptorArrayType(const JavaTypeNamespace* types) : Type(types, "android.os", "ParcelFileDescriptor", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ BooleanType::BooleanType(const JavaTypeNamespace* types) : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true) { m_array_type.reset(new BooleanArrayType(types)); } BooleanArrayType::BooleanArrayType(const JavaTypeNamespace* types) : Type(types, "boolean", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ CharType::CharType(const JavaTypeNamespace* types) : Type(types, "char", ValidatableType::KIND_BUILT_IN, true) { m_array_type.reset(new CharArrayType(types)); } CharArrayType::CharArrayType(const JavaTypeNamespace* types) : Type(types, "char", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ StringType::StringType(const JavaTypeNamespace* types, const std::string& package, const std::string& class_name) : Type(types, package, class_name, ValidatableType::KIND_BUILT_IN, true) { m_array_type.reset(new StringArrayType(types)); } StringArrayType::StringArrayType(const JavaTypeNamespace* types) : Type(types, "java.lang", "String", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ CharSequenceType::CharSequenceType(const JavaTypeNamespace* types) : Type(types, "java.lang", "CharSequence", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ RemoteExceptionType::RemoteExceptionType(const JavaTypeNamespace* types) : Type(types, "android.os", "RemoteException", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ RuntimeExceptionType::RuntimeExceptionType(const JavaTypeNamespace* types) : Type(types, "java.lang", "RuntimeException", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ IBinderType::IBinderType(const JavaTypeNamespace* types) : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN, true) { m_array_type.reset(new IBinderArrayType(types)); } IBinderArrayType::IBinderArrayType(const JavaTypeNamespace* types) : Type(types, "android.os", "IBinder", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ IInterfaceType::IInterfaceType(const JavaTypeNamespace* types) : Type(types, "android.os", "IInterface", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ BinderType::BinderType(const JavaTypeNamespace* types) : Type(types, "android.os", "Binder", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ BinderProxyType::BinderProxyType(const JavaTypeNamespace* types) : Type(types, "android.os", "BinderProxy", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ ParcelType::ParcelType(const JavaTypeNamespace* types) : Type(types, "android.os", "Parcel", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ ParcelableInterfaceType::ParcelableInterfaceType(const JavaTypeNamespace* types) : Type(types, "android.os", "Parcelable", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ MapType::MapType(const JavaTypeNamespace* types) : Type(types, "java.util", "Map", ValidatableType::KIND_BUILT_IN, true) {} // ================================================================ ListType::ListType(const JavaTypeNamespace* types) : Type(types, "java.util", "List", ValidatableType::KIND_BUILT_IN, true) {} string ListType::InstantiableName() const { return "java.util.ArrayList"; } // ================================================================ 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, declFile, declLine) { m_array_type.reset(new UserDataArrayType(types, package, name, builtIn, canWriteToParcel, declFile, declLine)); } 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, declFile, declLine) {} // ================================================================ InterfaceType::InterfaceType(const JavaTypeNamespace* types, const string& package, const string& name, bool builtIn, const string& declFile, int declLine, const Type* stub, const Type* proxy, const Type* defaultImpl) : Type(types, package, name, builtIn ? ValidatableType::KIND_BUILT_IN : ValidatableType::KIND_INTERFACE, true, declFile, declLine), stub_(stub), proxy_(proxy), defaultImpl_(defaultImpl) {} // ================================================================ GenericListType::GenericListType(const JavaTypeNamespace* types, const Type* contained_type) : Type(types, "java.util", "List<" + contained_type->CanonicalName() + ">", ValidatableType::KIND_BUILT_IN, true), m_contained_type(contained_type) {} string GenericListType::InstantiableName() const { return "java.util.ArrayList<" + m_contained_type->JavaType() + ">"; } // ================================================================ ClassLoaderType::ClassLoaderType(const JavaTypeNamespace* types) : Type(types, "java.lang", "ClassLoader", ValidatableType::KIND_BUILT_IN, false) {} // ================================================================ void JavaTypeNamespace::Init() { Add(std::make_unique(this, "void", "XXX", "XXX", "XXX", "XXX", "XXX")); AddAndSetMember(&m_bool_type, std::make_unique(this)); Add(std::make_unique(this, "byte", "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray")); Add(std::make_unique(this)); AddAndSetMember(&m_int_type, std::make_unique(this, "int", "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray")); Add(std::make_unique(this, "long", "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray")); Add(std::make_unique(this, "float", "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray")); Add(std::make_unique(this, "double", "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray")); AddAndSetMember(&m_string_type, std::make_unique(this, "java.lang", "String")); Add(std::make_unique(this, ::android::aidl::kAidlReservedTypePackage, ::android::aidl::kUtf8InCppStringClass)); Add(std::make_unique(this, "java.lang", "Object", ValidatableType::KIND_BUILT_IN, false)); Add(std::make_unique(this)); Add(std::make_unique(this)); Add(std::make_unique(this)); Add(std::make_unique(this)); Add(std::make_unique(this)); AddAndSetMember(&m_text_utils_type, std::make_unique(this, "android.text", "TextUtils", ValidatableType::KIND_BUILT_IN, false)); AddAndSetMember(&m_remote_exception_type, std::make_unique(this)); AddAndSetMember(&m_runtime_exception_type, std::make_unique(this)); AddAndSetMember(&m_ibinder_type, std::make_unique(this)); AddAndSetMember(&m_iinterface_type, std::make_unique(this)); AddAndSetMember(&m_binder_native_type, std::make_unique(this)); AddAndSetMember(&m_binder_proxy_type, std::make_unique(this)); AddAndSetMember(&m_parcel_type, std::make_unique(this)); AddAndSetMember(&m_parcelable_interface_type, std::make_unique(this)); AddAndSetMember(&m_context_type, std::make_unique(this, "android.content", "Context", ValidatableType::KIND_BUILT_IN, false)); AddAndSetMember(&m_classloader_type, std::make_unique(this)); 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) { return Add( std::make_unique(this, p.GetPackage(), p.GetName(), false, true, filename)); } bool JavaTypeNamespace::AddBinderType(const AidlInterface& b, const std::string& filename) { // for interfaces, add the stub, proxy, and interface types. auto stub = std::make_unique(this, b.GetPackage(), b.GetName() + ".Stub", ValidatableType::KIND_GENERATED, false, filename); auto proxy = std::make_unique(this, b.GetPackage(), b.GetName() + ".Stub.Proxy", ValidatableType::KIND_GENERATED, false, filename); auto defaultImpl = std::make_unique(this, b.GetPackage(), b.GetName() + ".Default", ValidatableType::KIND_GENERATED, false, filename); auto type = std::make_unique(this, b.GetPackage(), b.GetName(), false, filename, -1, stub.get(), proxy.get(), defaultImpl.get()); bool success = true; success &= Add(std::move(type)); success &= Add(std::move(stub)); success &= Add(std::move(proxy)); success &= Add(std::move(defaultImpl)); 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(std::make_unique(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 00000025137 13755771705 011771 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. */ #pragma once #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 }; // defaultValue is by default set to "null" because that is the default value // for most of the types like class and array. default values for built-in // types like int, double, boolean, etc. are explicitly set via BasicType Type(const JavaTypeNamespace* types, const std::string& name, int kind, bool canWriteToParcel); Type(const JavaTypeNamespace* types, const std::string& package, const std::string& name, int kind, bool canWriteToParcel, const std::string& declFile = "", int declLine = -1); virtual ~Type() = default; 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 InstantiableName() const; // The namespace where this type is defined in const JavaTypeNamespace* GetTypeNamespace() const { return m_types; } 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; }; 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); 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); private: std::string m_marshallParcel; std::string m_unmarshallParcel; }; class FileDescriptorArrayType : public Type { public: explicit FileDescriptorArrayType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class FileDescriptorType : public Type { public: explicit FileDescriptorType(const JavaTypeNamespace* types); }; class ParcelFileDescriptorArrayType : public Type { public: explicit ParcelFileDescriptorArrayType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class ParcelFileDescriptorType : public Type { public: explicit ParcelFileDescriptorType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class BooleanArrayType : public Type { public: explicit BooleanArrayType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class BooleanType : public Type { public: explicit BooleanType(const JavaTypeNamespace* types); }; class CharArrayType : public Type { public: explicit CharArrayType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class CharType : public Type { public: explicit CharType(const JavaTypeNamespace* types); }; class StringArrayType : public Type { public: explicit StringArrayType(const JavaTypeNamespace* types); 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"; } const ValidatableType* NullableType() const override { return this; } }; class CharSequenceType : public Type { public: explicit CharSequenceType(const JavaTypeNamespace* types); }; class RemoteExceptionType : public Type { public: explicit RemoteExceptionType(const JavaTypeNamespace* types); }; class RuntimeExceptionType : public Type { public: explicit RuntimeExceptionType(const JavaTypeNamespace* types); }; class IBinderArrayType : public Type { public: explicit IBinderArrayType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class IBinderType : public Type { public: explicit IBinderType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class IInterfaceType : public Type { public: explicit IInterfaceType(const JavaTypeNamespace* types); }; class BinderType : public Type { public: explicit BinderType(const JavaTypeNamespace* types); }; class BinderProxyType : public Type { public: explicit BinderProxyType(const JavaTypeNamespace* types); }; class ParcelType : public Type { public: explicit ParcelType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class ParcelableInterfaceType : public Type { public: explicit ParcelableInterfaceType(const JavaTypeNamespace* types); }; class MapType : public Type { public: explicit MapType(const JavaTypeNamespace* types); const ValidatableType* NullableType() const override { return this; } }; class ListType : public Type { public: explicit ListType(const JavaTypeNamespace* types); std::string InstantiableName() 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); 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); 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, const std::string& declFile, int declLine, const Type* stub, const Type* proxy, const Type* defaultImpl); const ValidatableType* NullableType() const override { return this; } const Type* GetStub() const { return stub_; } const Type* GetProxy() const { return proxy_; } const Type* GetDefaultImpl() const { return defaultImpl_; } private: const Type* stub_; const Type* proxy_; const Type* defaultImpl_; }; class ClassLoaderType : public Type { public: explicit ClassLoaderType(const JavaTypeNamespace* types); }; class GenericListType : public Type { public: GenericListType(const JavaTypeNamespace* types, const Type* arg); std::string InstantiableName() const override; std::string JavaType() const override { return "java.util.List<" + m_contained_type->JavaType() + ">"; } const ValidatableType* NullableType() const override { return this; } private: const Type* m_contained_type; }; 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 type_java_unittest.cpp0100644 0000000 0000000 00000004663 13755771705 014264 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( AIDL_LOCATION_HERE, new AidlQualifiedName(AIDL_LOCATION_HERE, "Foo", ""), {"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... std::vector>* type_args = new std::vector>(); type_args->emplace_back(new AidlTypeSpecifier(AIDL_LOCATION_HERE, "Foo", false, nullptr, "")); AidlTypeSpecifier container_type(AIDL_LOCATION_HERE, "List", false, type_args, ""); 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 00000012721 13755771705 013332 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 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 kUtf8InCppStringClass[] = "Utf8InCppString"; // These *must* match the package and class names above. const char kUtf8InCppStringCanonicalName[] = "aidl-internal.Utf8InCppString"; const char kStringCanonicalName[] = "java.lang.String"; 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"; } const ValidatableType* TypeNamespace::GetReturnType(const AidlTypeSpecifier& raw_type, const AidlDefinedType& context) const { string error_msg; const ValidatableType* return_type = GetValidatableType(raw_type, &error_msg, context); if (return_type == nullptr) { AIDL_ERROR(raw_type) << "Return type " << raw_type.ToString() << ": " << error_msg; return nullptr; } return return_type; } bool TypeNamespace::AddDefinedTypes(vector& types, const string& filename) { bool success = true; for (const auto type : types) { const AidlInterface* interface = type->AsInterface(); if (interface != nullptr) { success &= AddBinderType(*interface, filename); continue; } const AidlParcelable* parcelable = type->AsParcelable(); if (parcelable != nullptr) { success &= AddParcelableType(*parcelable, filename); continue; } CHECK(false) << "aidl internal error: unrecognized type"; } return success; } const ValidatableType* TypeNamespace::GetArgType(const AidlArgument& a, int arg_index, const AidlDefinedType& context) const { string error_prefix = StringPrintf("parameter %s (argument %d): ", a.GetName().c_str(), arg_index); // check the arg type string error_msg; const ValidatableType* t = GetValidatableType(a.GetType(), &error_msg, context); if (t == nullptr) { AIDL_ERROR(a) << error_prefix << error_msg; return nullptr; } const bool can_be_out = typenames_.CanBeOutParameter(a.GetType()); if (!a.DirectionWasSpecified() && can_be_out) { AIDL_ERROR(a) << error_prefix << "'" << a.GetType().ToString() << "' can be an out type, so you must declare it as in, out, or inout."; return nullptr; } if (a.GetDirection() != AidlArgument::IN_DIR && !can_be_out) { AIDL_ERROR(a) << error_prefix << "'" << a.ToString() << "' can only be an in parameter."; return nullptr; } // check that the name doesn't match a keyword if (is_java_keyword(a.GetName().c_str())) { AIDL_ERROR(a) << 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") { AIDL_ERROR(a) << error_prefix << "Argument name cannot begin with '_aidl'"; return nullptr; } return t; } } // namespace aidl } // namespace android type_namespace.h0100644 0000000 0000000 00000036004 13755771705 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. */ #pragma once #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 kUtf8InCppStringClass[]; // UTF16 wire format, UTF8 in C++ // Helpful aliases defined to be . 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 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 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; bool AddDefinedTypes(vector& types, const string& filename); // 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 AidlTypeSpecifier& aidl_type) = 0; // Returns true iff this has a type for |import|. virtual bool HasImportType(const std::string& import) const = 0; // Returns a pointer to a type corresponding to |raw_type| or nullptr // if this is an invalid return type. virtual const ValidatableType* GetReturnType(const AidlTypeSpecifier& raw_type, const AidlDefinedType& context) const; // Returns a pointer to a type corresponding to |a| or nullptr if |a| // has an invalid argument type. virtual const ValidatableType* GetArgType(const AidlArgument& a, int arg_index, const AidlDefinedType& context) const; // Returns a pointer to a type corresponding to |defined_type|. virtual const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const = 0; AidlTypenames typenames_; protected: TypeNamespace() = default; virtual ~TypeNamespace() = default; virtual const ValidatableType* GetValidatableType(const AidlTypeSpecifier& type, std::string* error_msg, const AidlDefinedType& context) 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 AidlTypeSpecifier& 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 std::string& import) const override { return HasTypeByCanonicalName(import); } const ValidatableType* GetDefinedType(const AidlDefinedType& defined_type) const override { return FindTypeByCanonicalName(defined_type.GetCanonicalName()); } bool MaybeAddContainerType(const AidlTypeSpecifier& 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(std::unique_ptr type); void AddAndSetMember(const T** member, std::unique_ptr type) { const T* ptr_value = type.get(); CHECK(Add(std::move(type))); *member = ptr_value; } private: // Returns true iff the name can be canonicalized to a container type. virtual bool CanonicalizeContainerType(const AidlTypeSpecifier& 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 AidlTypeSpecifier& type, std::string* error_msg, const AidlDefinedType& context) const override; std::vector> types_; DISALLOW_COPY_AND_ASSIGN(LanguageTypeNamespace); }; // class LanguageTypeNamespace template bool LanguageTypeNamespace::Add(std::unique_ptr type) { const T* existing = FindTypeByCanonicalName(type->CanonicalName()); if (!existing) { types_.push_back(std::move(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 AidlTypeSpecifier& aidl_type) const { using std::string; using std::vector; using android::base::Join; using android::base::Trim; string name = Trim(aidl_type.IsArray() ? aidl_type.GetName() : aidl_type.ToString()); 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 AidlTypeSpecifier& aidl_type) { using android::base::Join; const std::string& type_name = aidl_type.ToString(); 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 AidlTypeSpecifier& aidl_type, std::vector* container_class, std::vector* contained_type_names) const { std::string container = aidl_type.GetName(); std::vector args; for (auto& type_arg : aidl_type.GetTypeParameters()) { if (type_arg->IsGeneric()) { // nesting is not allowed yet. LOG(ERROR) << "Nested template type '" << aidl_type.ToString() << "'"; } std::string type_name = type_arg->ToString(); // 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.IsUtf8InCpp() && type_name == "java.lang.String") { type_name = kUtf8InCppStringCanonicalName; } args.emplace_back(type_name); } // 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 AidlTypeSpecifier& aidl_type, std::string* error_msg, const AidlDefinedType& context) 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.IsUtf8InCpp()) { *error_msg = "void type cannot be annotated"; return nullptr; } // We have no more special handling for void. return type; } 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())) { utf8InCpp = false; } else if (aidl_type.GetName() == "String" || aidl_type.GetName() == "java.lang.String") { utf8InCpp = utf8InCpp || context.IsUtf8InCpp(); } else if (utf8InCpp) { *error_msg = StringPrintf("type '%s' may not be annotated as %s.", aidl_type.GetName().c_str(), kUtf8InCppAnnotation); return nullptr; } if (utf8InCpp) { type = FindTypeByCanonicalName(kUtf8InCppStringCanonicalName); } // One of our UTF8 transforms made type null if (type == nullptr) { *error_msg = StringPrintf("%s is unsupported when generating code for this language.", kUtf8InCppAnnotation); 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 (context.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