Home | History | Annotate | Download | only in aidl
      1 /*
      2  * Copyright (C) 2015, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "aidl.h"
     18 
     19 #include <fcntl.h>
     20 #include <iostream>
     21 #include <map>
     22 #include <stdio.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <sys/param.h>
     26 #include <sys/stat.h>
     27 #include <unistd.h>
     28 
     29 #ifdef _WIN32
     30 #include <io.h>
     31 #include <direct.h>
     32 #include <sys/stat.h>
     33 #endif
     34 
     35 #include <android-base/strings.h>
     36 
     37 #include "aidl_language.h"
     38 #include "generate_cpp.h"
     39 #include "generate_java.h"
     40 #include "import_resolver.h"
     41 #include "logging.h"
     42 #include "options.h"
     43 #include "os.h"
     44 #include "type_cpp.h"
     45 #include "type_java.h"
     46 #include "type_namespace.h"
     47 
     48 #ifndef O_BINARY
     49 #  define O_BINARY  0
     50 #endif
     51 
     52 using android::base::Join;
     53 using android::base::Split;
     54 using std::cerr;
     55 using std::endl;
     56 using std::map;
     57 using std::set;
     58 using std::string;
     59 using std::unique_ptr;
     60 using std::vector;
     61 
     62 namespace android {
     63 namespace aidl {
     64 namespace {
     65 
     66 // The following are gotten as the offset from the allowable id's between
     67 // android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
     68 // android.os.IBinder.LAST_CALL_TRANSACTION=16777215
     69 const int kMinUserSetMethodId = 0;
     70 const int kMaxUserSetMethodId = 16777214;
     71 
     72 bool check_filename(const std::string& filename,
     73                     const std::string& package,
     74                     const std::string& name,
     75                     unsigned line) {
     76     const char* p;
     77     string expected;
     78     string fn;
     79     size_t len;
     80     bool valid = false;
     81 
     82     if (!IoDelegate::GetAbsolutePath(filename, &fn)) {
     83       return false;
     84     }
     85 
     86     if (!package.empty()) {
     87         expected = package;
     88         expected += '.';
     89     }
     90 
     91     len = expected.length();
     92     for (size_t i=0; i<len; i++) {
     93         if (expected[i] == '.') {
     94             expected[i] = OS_PATH_SEPARATOR;
     95         }
     96     }
     97 
     98     expected.append(name, 0, name.find('.'));
     99 
    100     expected += ".aidl";
    101 
    102     len = fn.length();
    103     valid = (len >= expected.length());
    104 
    105     if (valid) {
    106         p = fn.c_str() + (len - expected.length());
    107 
    108 #ifdef _WIN32
    109         if (OS_PATH_SEPARATOR != '/') {
    110             // Input filename under cygwin most likely has / separators
    111             // whereas the expected string uses \\ separators. Adjust
    112             // them accordingly.
    113           for (char *c = const_cast<char *>(p); *c; ++c) {
    114                 if (*c == '/') *c = OS_PATH_SEPARATOR;
    115             }
    116         }
    117 #endif
    118 
    119         // aidl assumes case-insensitivity on Mac Os and Windows.
    120 #if defined(__linux__)
    121         valid = (expected == p);
    122 #else
    123         valid = !strcasecmp(expected.c_str(), p);
    124 #endif
    125     }
    126 
    127     if (!valid) {
    128         fprintf(stderr, "%s:%d interface %s should be declared in a file"
    129                 " called %s.\n",
    130                 filename.c_str(), line, name.c_str(), expected.c_str());
    131     }
    132 
    133     return valid;
    134 }
    135 
    136 bool check_filenames(const std::string& filename, const AidlDocument* doc) {
    137   if (!doc)
    138     return true;
    139 
    140   const AidlInterface* interface = doc->GetInterface();
    141 
    142   if (interface) {
    143     return check_filename(filename, interface->GetPackage(),
    144                           interface->GetName(), interface->GetLine());
    145   }
    146 
    147   bool success = true;
    148 
    149   for (const auto& item : doc->GetParcelables()) {
    150     success &= check_filename(filename, item->GetPackage(), item->GetName(),
    151                               item->GetLine());
    152   }
    153 
    154   return success;
    155 }
    156 
    157 bool gather_types(const std::string& filename,
    158                   const AidlDocument* doc,
    159                   TypeNamespace* types) {
    160   bool success = true;
    161 
    162   const AidlInterface* interface = doc->GetInterface();
    163 
    164   if (interface)
    165     return types->AddBinderType(*interface, filename);
    166 
    167   for (const auto& item : doc->GetParcelables()) {
    168     success &= types->AddParcelableType(*item, filename);
    169   }
    170 
    171   return success;
    172 }
    173 
    174 int check_types(const string& filename,
    175                 const AidlInterface* c,
    176                 TypeNamespace* types) {
    177   int err = 0;
    178 
    179   if (c->IsUtf8() && c->IsUtf8InCpp()) {
    180     cerr << filename << ":" << c->GetLine()
    181          << "Interface cannot be marked as both @utf8 and @utf8InCpp";
    182     err = 1;
    183   }
    184 
    185   // Has to be a pointer due to deleting copy constructor. No idea why.
    186   map<string, const AidlMethod*> method_names;
    187   for (const auto& m : c->GetMethods()) {
    188     bool oneway = m->IsOneway() || c->IsOneway();
    189 
    190     if (!types->MaybeAddContainerType(m->GetType())) {
    191       err = 1;  // return type is invalid
    192     }
    193 
    194     const ValidatableType* return_type =
    195         types->GetReturnType(m->GetType(), filename, *c);
    196 
    197     if (!return_type) {
    198       err = 1;
    199     }
    200 
    201     m->GetMutableType()->SetLanguageType(return_type);
    202 
    203     if (oneway && m->GetType().GetName() != "void") {
    204         cerr << filename << ":" << m->GetLine()
    205             << " oneway method '" << m->GetName() << "' cannot return a value"
    206             << endl;
    207         err = 1;
    208     }
    209 
    210     int index = 1;
    211     for (const auto& arg : m->GetArguments()) {
    212       if (!types->MaybeAddContainerType(arg->GetType())) {
    213         err = 1;
    214       }
    215 
    216       const ValidatableType* arg_type =
    217           types->GetArgType(*arg, index, filename, *c);
    218 
    219       if (!arg_type) {
    220         err = 1;
    221       }
    222 
    223       arg->GetMutableType()->SetLanguageType(arg_type);
    224 
    225       if (oneway && arg->IsOut()) {
    226         cerr << filename << ":" << m->GetLine()
    227             << " oneway method '" << m->GetName()
    228             << "' cannot have out parameters" << endl;
    229         err = 1;
    230       }
    231     }
    232 
    233     auto it = method_names.find(m->GetName());
    234     // prevent duplicate methods
    235     if (it == method_names.end()) {
    236       method_names[m->GetName()] = m.get();
    237     } else {
    238       cerr << filename << ":" << m->GetLine()
    239            << " attempt to redefine method " << m->GetName() << "," << endl
    240            << filename << ":" << it->second->GetLine()
    241            << "    previously defined here." << endl;
    242       err = 1;
    243     }
    244   }
    245   return err;
    246 }
    247 
    248 void write_common_dep_file(const string& output_file,
    249                            const vector<string>& aidl_sources,
    250                            CodeWriter* writer,
    251                            const bool ninja) {
    252   // Encode that the output file depends on aidl input files.
    253   writer->Write("%s : \\\n", output_file.c_str());
    254   writer->Write("  %s", Join(aidl_sources, " \\\n  ").c_str());
    255   writer->Write("\n");
    256 
    257   if (!ninja) {
    258     writer->Write("\n");
    259     // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
    260     // has been deleted, moved or renamed in incremental build.
    261     for (const auto& src : aidl_sources) {
    262       writer->Write("%s :\n", src.c_str());
    263     }
    264   }
    265 }
    266 
    267 bool write_java_dep_file(const JavaOptions& options,
    268                          const vector<unique_ptr<AidlImport>>& imports,
    269                          const IoDelegate& io_delegate,
    270                          const string& output_file_name) {
    271   string dep_file_name = options.DependencyFilePath();
    272   if (dep_file_name.empty()) {
    273     return true;  // nothing to do
    274   }
    275   CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
    276   if (!writer) {
    277     LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
    278     return false;
    279   }
    280 
    281   vector<string> source_aidl = {options.input_file_name_};
    282   for (const auto& import : imports) {
    283     if (!import->GetFilename().empty()) {
    284       source_aidl.push_back(import->GetFilename());
    285     }
    286   }
    287 
    288   write_common_dep_file(output_file_name, source_aidl, writer.get(),
    289                         options.DependencyFileNinja());
    290 
    291   return true;
    292 }
    293 
    294 bool write_cpp_dep_file(const CppOptions& options,
    295                         const AidlInterface& interface,
    296                         const vector<unique_ptr<AidlImport>>& imports,
    297                         const IoDelegate& io_delegate) {
    298   using ::android::aidl::cpp::HeaderFile;
    299   using ::android::aidl::cpp::ClassNames;
    300 
    301   string dep_file_name = options.DependencyFilePath();
    302   if (dep_file_name.empty()) {
    303     return true;  // nothing to do
    304   }
    305   CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
    306   if (!writer) {
    307     LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
    308     return false;
    309   }
    310 
    311   vector<string> source_aidl = {options.InputFileName()};
    312   for (const auto& import : imports) {
    313     if (!import->GetFilename().empty()) {
    314       source_aidl.push_back(import->GetFilename());
    315     }
    316   }
    317 
    318   write_common_dep_file(options.OutputCppFilePath(), source_aidl, writer.get(),
    319                         options.DependencyFileNinja());
    320 
    321   if (!options.DependencyFileNinja()) {
    322     vector<string> headers;
    323     for (ClassNames c : {ClassNames::CLIENT,
    324                          ClassNames::SERVER,
    325                          ClassNames::INTERFACE}) {
    326       headers.push_back(options.OutputHeaderDir() + '/' +
    327                         HeaderFile(interface, c, false /* use_os_sep */));
    328     }
    329 
    330     writer->Write("\n");
    331 
    332     // Generated headers also depend on the source aidl files.
    333     writer->Write("%s : \\\n    %s\n", Join(headers, " \\\n    ").c_str(),
    334                   Join(source_aidl, " \\\n    ").c_str());
    335   }
    336 
    337   return true;
    338 }
    339 
    340 string generate_outputFileName(const JavaOptions& options,
    341                                const AidlInterface& interface) {
    342     const string& name = interface.GetName();
    343     string package = interface.GetPackage();
    344     string result;
    345 
    346     // create the path to the destination folder based on the
    347     // interface package name
    348     result = options.output_base_folder_;
    349     result += OS_PATH_SEPARATOR;
    350 
    351     string packageStr = package;
    352     size_t len = packageStr.length();
    353     for (size_t i=0; i<len; i++) {
    354         if (packageStr[i] == '.') {
    355             packageStr[i] = OS_PATH_SEPARATOR;
    356         }
    357     }
    358 
    359     result += packageStr;
    360 
    361     // add the filename by replacing the .aidl extension to .java
    362     result += OS_PATH_SEPARATOR;
    363     result.append(name, 0, name.find('.'));
    364     result += ".java";
    365 
    366     return result;
    367 }
    368 
    369 int check_and_assign_method_ids(const char * filename,
    370                                 const std::vector<std::unique_ptr<AidlMethod>>& items) {
    371     // Check whether there are any methods with manually assigned id's and any that are not.
    372     // Either all method id's must be manually assigned or all of them must not.
    373     // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
    374     set<int> usedIds;
    375     bool hasUnassignedIds = false;
    376     bool hasAssignedIds = false;
    377     for (const auto& item : items) {
    378         if (item->HasId()) {
    379             hasAssignedIds = true;
    380             // Ensure that the user set id is not duplicated.
    381             if (usedIds.find(item->GetId()) != usedIds.end()) {
    382                 // We found a duplicate id, so throw an error.
    383                 fprintf(stderr,
    384                         "%s:%d Found duplicate method id (%d) for method: %s\n",
    385                         filename, item->GetLine(),
    386                         item->GetId(), item->GetName().c_str());
    387                 return 1;
    388             }
    389             // Ensure that the user set id is within the appropriate limits
    390             if (item->GetId() < kMinUserSetMethodId ||
    391                     item->GetId() > kMaxUserSetMethodId) {
    392                 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
    393                         filename, item->GetLine(),
    394                         item->GetId(), item->GetName().c_str());
    395                 fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
    396                         kMinUserSetMethodId, kMaxUserSetMethodId);
    397                 return 1;
    398             }
    399             usedIds.insert(item->GetId());
    400         } else {
    401             hasUnassignedIds = true;
    402         }
    403         if (hasAssignedIds && hasUnassignedIds) {
    404             fprintf(stderr,
    405                     "%s: You must either assign id's to all methods or to none of them.\n",
    406                     filename);
    407             return 1;
    408         }
    409     }
    410 
    411     // In the case that all methods have unassigned id's, set a unique id for them.
    412     if (hasUnassignedIds) {
    413         int newId = 0;
    414         for (const auto& item : items) {
    415             item->SetId(newId++);
    416         }
    417     }
    418 
    419     // success
    420     return 0;
    421 }
    422 
    423 bool validate_constants(const AidlInterface& interface) {
    424   bool success = true;
    425   set<string> names;
    426   for (const std::unique_ptr<AidlIntConstant>& int_constant :
    427        interface.GetIntConstants()) {
    428     if (names.count(int_constant->GetName()) > 0) {
    429       LOG(ERROR) << "Found duplicate constant name '" << int_constant->GetName()
    430                  << "'";
    431       success = false;
    432     }
    433     names.insert(int_constant->GetName());
    434     // We've logged an error message for this on object construction.
    435     success = success && int_constant->IsValid();
    436   }
    437   for (const std::unique_ptr<AidlStringConstant>& string_constant :
    438        interface.GetStringConstants()) {
    439     if (names.count(string_constant->GetName()) > 0) {
    440       LOG(ERROR) << "Found duplicate constant name '" << string_constant->GetName()
    441                  << "'";
    442       success = false;
    443     }
    444     names.insert(string_constant->GetName());
    445     // We've logged an error message for this on object construction.
    446     success = success && string_constant->IsValid();
    447   }
    448   return success;
    449 }
    450 
    451 // TODO: Remove this in favor of using the YACC parser b/25479378
    452 bool ParsePreprocessedLine(const string& line, string* decl,
    453                            vector<string>* package, string* class_name) {
    454   // erase all trailing whitespace and semicolons
    455   const size_t end = line.find_last_not_of(" ;\t");
    456   if (end == string::npos) {
    457     return false;
    458   }
    459   if (line.rfind(';', end) != string::npos) {
    460     return false;
    461   }
    462 
    463   decl->clear();
    464   string type;
    465   vector<string> pieces = Split(line.substr(0, end + 1), " \t");
    466   for (const string& piece : pieces) {
    467     if (piece.empty()) {
    468       continue;
    469     }
    470     if (decl->empty()) {
    471       *decl = std::move(piece);
    472     } else if (type.empty()) {
    473       type = std::move(piece);
    474     } else {
    475       return false;
    476     }
    477   }
    478 
    479   // Note that this logic is absolutely wrong.  Given a parcelable
    480   // org.some.Foo.Bar, the class name is Foo.Bar, but this code will claim that
    481   // the class is just Bar.  However, this was the way it was done in the past.
    482   //
    483   // See b/17415692
    484   size_t dot_pos = type.rfind('.');
    485   if (dot_pos != string::npos) {
    486     *class_name = type.substr(dot_pos + 1);
    487     *package = Split(type.substr(0, dot_pos), ".");
    488   } else {
    489     *class_name = type;
    490     package->clear();
    491   }
    492 
    493   return true;
    494 }
    495 
    496 }  // namespace
    497 
    498 namespace internals {
    499 
    500 bool parse_preprocessed_file(const IoDelegate& io_delegate,
    501                              const string& filename, TypeNamespace* types) {
    502   bool success = true;
    503   unique_ptr<LineReader> line_reader = io_delegate.GetLineReader(filename);
    504   if (!line_reader) {
    505     LOG(ERROR) << "cannot open preprocessed file: " << filename;
    506     success = false;
    507     return success;
    508   }
    509 
    510   string line;
    511   unsigned lineno = 1;
    512   for ( ; line_reader->ReadLine(&line); ++lineno) {
    513     if (line.empty() || line.compare(0, 2, "//") == 0) {
    514       // skip comments and empty lines
    515       continue;
    516     }
    517 
    518     string decl;
    519     vector<string> package;
    520     string class_name;
    521     if (!ParsePreprocessedLine(line, &decl, &package, &class_name)) {
    522       success = false;
    523       break;
    524     }
    525 
    526     if (decl == "parcelable") {
    527       AidlParcelable doc(new AidlQualifiedName(class_name, ""),
    528                          lineno, package);
    529       types->AddParcelableType(doc, filename);
    530     } else if (decl == "interface") {
    531       auto temp = new std::vector<std::unique_ptr<AidlMember>>();
    532       AidlInterface doc(class_name, lineno, "", false, temp, package);
    533       types->AddBinderType(doc, filename);
    534     } else {
    535       success = false;
    536       break;
    537     }
    538   }
    539   if (!success) {
    540     LOG(ERROR) << filename << ':' << lineno
    541                << " malformed preprocessed file line: '" << line << "'";
    542   }
    543 
    544   return success;
    545 }
    546 
    547 AidlError load_and_validate_aidl(
    548     const std::vector<std::string>& preprocessed_files,
    549     const std::vector<std::string>& import_paths,
    550     const std::string& input_file_name,
    551     const IoDelegate& io_delegate,
    552     TypeNamespace* types,
    553     std::unique_ptr<AidlInterface>* returned_interface,
    554     std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
    555   AidlError err = AidlError::OK;
    556 
    557   std::map<AidlImport*,std::unique_ptr<AidlDocument>> docs;
    558 
    559   // import the preprocessed file
    560   for (const string& s : preprocessed_files) {
    561     if (!parse_preprocessed_file(io_delegate, s, types)) {
    562       err = AidlError::BAD_PRE_PROCESSED_FILE;
    563     }
    564   }
    565   if (err != AidlError::OK) {
    566     return err;
    567   }
    568 
    569   // parse the input file
    570   Parser p{io_delegate};
    571   if (!p.ParseFile(input_file_name)) {
    572     return AidlError::PARSE_ERROR;
    573   }
    574 
    575   AidlDocument* parsed_doc = p.GetDocument();
    576 
    577   unique_ptr<AidlInterface> interface(parsed_doc->ReleaseInterface());
    578 
    579   if (!interface) {
    580     LOG(ERROR) << "refusing to generate code from aidl file defining "
    581                   "parcelable";
    582     return AidlError::FOUND_PARCELABLE;
    583   }
    584 
    585   if (!check_filename(input_file_name.c_str(), interface->GetPackage(),
    586                       interface->GetName(), interface->GetLine()) ||
    587       !types->IsValidPackage(interface->GetPackage())) {
    588     LOG(ERROR) << "Invalid package declaration '" << interface->GetPackage()
    589                << "'";
    590     return AidlError::BAD_PACKAGE;
    591   }
    592 
    593   // parse the imports of the input file
    594   ImportResolver import_resolver{io_delegate, import_paths};
    595   for (auto& import : p.GetImports()) {
    596     if (types->HasImportType(*import)) {
    597       // There are places in the Android tree where an import doesn't resolve,
    598       // but we'll pick the type up through the preprocessed types.
    599       // This seems like an error, but legacy support demands we support it...
    600       continue;
    601     }
    602     string import_path = import_resolver.FindImportFile(import->GetNeededClass());
    603     if (import_path.empty()) {
    604       cerr << import->GetFileFrom() << ":" << import->GetLine()
    605            << ": couldn't find import for class "
    606            << import->GetNeededClass() << endl;
    607       err = AidlError::BAD_IMPORT;
    608       continue;
    609     }
    610     import->SetFilename(import_path);
    611 
    612     Parser p{io_delegate};
    613     if (!p.ParseFile(import->GetFilename())) {
    614       cerr << "error while parsing import for class "
    615            << import->GetNeededClass() << endl;
    616       err = AidlError::BAD_IMPORT;
    617       continue;
    618     }
    619 
    620     std::unique_ptr<AidlDocument> document(p.ReleaseDocument());
    621     if (!check_filenames(import->GetFilename(), document.get()))
    622       err = AidlError::BAD_IMPORT;
    623     docs[import.get()] = std::move(document);
    624   }
    625   if (err != AidlError::OK) {
    626     return err;
    627   }
    628 
    629   // gather the types that have been declared
    630   if (!types->AddBinderType(*interface.get(), input_file_name)) {
    631     err = AidlError::BAD_TYPE;
    632   }
    633 
    634   interface->SetLanguageType(types->GetInterfaceType(*interface));
    635 
    636   for (const auto& import : p.GetImports()) {
    637     // If we skipped an unresolved import above (see comment there) we'll have
    638     // an empty bucket here.
    639     const auto import_itr = docs.find(import.get());
    640     if (import_itr == docs.cend()) {
    641       continue;
    642     }
    643 
    644     if (!gather_types(import->GetFilename(), import_itr->second.get(), types)) {
    645       err = AidlError::BAD_TYPE;
    646     }
    647   }
    648 
    649   // check the referenced types in parsed_doc to make sure we've imported them
    650   if (check_types(input_file_name, interface.get(), types) != 0) {
    651     err = AidlError::BAD_TYPE;
    652   }
    653   if (err != AidlError::OK) {
    654     return err;
    655   }
    656 
    657 
    658   // assign method ids and validate.
    659   if (check_and_assign_method_ids(input_file_name.c_str(),
    660                                   interface->GetMethods()) != 0) {
    661     return AidlError::BAD_METHOD_ID;
    662   }
    663   if (!validate_constants(*interface)) {
    664     return AidlError::BAD_CONSTANTS;
    665   }
    666 
    667   if (returned_interface)
    668     *returned_interface = std::move(interface);
    669 
    670   if (returned_imports)
    671     p.ReleaseImports(returned_imports);
    672 
    673   return AidlError::OK;
    674 }
    675 
    676 } // namespace internals
    677 
    678 int compile_aidl_to_cpp(const CppOptions& options,
    679                         const IoDelegate& io_delegate) {
    680   unique_ptr<AidlInterface> interface;
    681   std::vector<std::unique_ptr<AidlImport>> imports;
    682   unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
    683   types->Init();
    684   AidlError err = internals::load_and_validate_aidl(
    685       std::vector<std::string>{},  // no preprocessed files
    686       options.ImportPaths(),
    687       options.InputFileName(),
    688       io_delegate,
    689       types.get(),
    690       &interface,
    691       &imports);
    692   if (err != AidlError::OK) {
    693     return 1;
    694   }
    695 
    696   if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) {
    697     return 1;
    698   }
    699 
    700   return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1;
    701 }
    702 
    703 int compile_aidl_to_java(const JavaOptions& options,
    704                          const IoDelegate& io_delegate) {
    705   unique_ptr<AidlInterface> interface;
    706   std::vector<std::unique_ptr<AidlImport>> imports;
    707   unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
    708   types->Init();
    709   AidlError aidl_err = internals::load_and_validate_aidl(
    710       options.preprocessed_files_,
    711       options.import_paths_,
    712       options.input_file_name_,
    713       io_delegate,
    714       types.get(),
    715       &interface,
    716       &imports);
    717   if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) {
    718     // We aborted code generation because this file contains parcelables.
    719     // However, we were not told to complain if we find parcelables.
    720     // Just generate a dep file and exit quietly.  The dep file is for a legacy
    721     // use case by the SDK.
    722     write_java_dep_file(options, imports, io_delegate, "");
    723     return 0;
    724   }
    725   if (aidl_err != AidlError::OK) {
    726     return 1;
    727   }
    728 
    729   string output_file_name = options.output_file_name_;
    730   // if needed, generate the output file name from the base folder
    731   if (output_file_name.empty() && !options.output_base_folder_.empty()) {
    732     output_file_name = generate_outputFileName(options, *interface);
    733   }
    734 
    735   // make sure the folders of the output file all exists
    736   if (!io_delegate.CreatePathForFile(output_file_name)) {
    737     return 1;
    738   }
    739 
    740   if (!write_java_dep_file(options, imports, io_delegate, output_file_name)) {
    741     return 1;
    742   }
    743 
    744   return generate_java(output_file_name, options.input_file_name_.c_str(),
    745                        interface.get(), types.get(), io_delegate);
    746 }
    747 
    748 bool preprocess_aidl(const JavaOptions& options,
    749                      const IoDelegate& io_delegate) {
    750   unique_ptr<CodeWriter> writer =
    751       io_delegate.GetCodeWriter(options.output_file_name_);
    752 
    753   for (const auto& file : options.files_to_preprocess_) {
    754     Parser p{io_delegate};
    755     if (!p.ParseFile(file))
    756       return false;
    757     AidlDocument* doc = p.GetDocument();
    758     string line;
    759 
    760     const AidlInterface* interface = doc->GetInterface();
    761 
    762     if (interface != nullptr &&
    763         !writer->Write("interface %s;\n",
    764                        interface->GetCanonicalName().c_str())) {
    765       return false;
    766     }
    767 
    768     for (const auto& parcelable : doc->GetParcelables()) {
    769       if (!writer->Write("parcelable %s;\n",
    770                          parcelable->GetCanonicalName().c_str())) {
    771         return false;
    772       }
    773     }
    774   }
    775 
    776   return writer->Close();
    777 }
    778 
    779 }  // namespace android
    780 }  // namespace aidl
    781