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
52using android::base::Join;
53using android::base::Split;
54using std::cerr;
55using std::endl;
56using std::map;
57using std::set;
58using std::string;
59using std::unique_ptr;
60using std::vector;
61
62namespace android {
63namespace aidl {
64namespace {
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
69const int kMinUserSetMethodId = 0;
70const int kMaxUserSetMethodId = 16777214;
71
72bool 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
136bool 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
157bool 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
174int check_types(const string& filename,
175                const AidlInterface* c,
176                TypeNamespace* types) {
177  int err = 0;
178
179  // Has to be a pointer due to deleting copy constructor. No idea why.
180  map<string, const AidlMethod*> method_names;
181  for (const auto& m : c->GetMethods()) {
182    bool oneway = m->IsOneway() || c->IsOneway();
183
184    if (!types->MaybeAddContainerType(m->GetType())) {
185      err = 1;  // return type is invalid
186    }
187
188    const ValidatableType* return_type =
189        types->GetReturnType(m->GetType(), filename);
190
191    if (!return_type) {
192      err = 1;
193    }
194
195    m->GetMutableType()->SetLanguageType(return_type);
196
197    if (oneway && m->GetType().GetName() != "void") {
198        cerr << filename << ":" << m->GetLine()
199            << " oneway method '" << m->GetName() << "' cannot return a value"
200            << endl;
201        err = 1;
202    }
203
204    int index = 1;
205    for (const auto& arg : m->GetArguments()) {
206      if (!types->MaybeAddContainerType(arg->GetType())) {
207        err = 1;
208      }
209
210      const ValidatableType* arg_type =
211          types->GetArgType(*arg, index, filename);
212
213      if (!arg_type) {
214        err = 1;
215      }
216
217      arg->GetMutableType()->SetLanguageType(arg_type);
218
219      if (oneway && arg->IsOut()) {
220        cerr << filename << ":" << m->GetLine()
221            << " oneway method '" << m->GetName()
222            << "' cannot have out parameters" << endl;
223        err = 1;
224      }
225    }
226
227    auto it = method_names.find(m->GetName());
228    // prevent duplicate methods
229    if (it == method_names.end()) {
230      method_names[m->GetName()] = m.get();
231    } else {
232      cerr << filename << ":" << m->GetLine()
233           << " attempt to redefine method " << m->GetName() << "," << endl
234           << filename << ":" << it->second->GetLine()
235           << "    previously defined here." << endl;
236      err = 1;
237    }
238  }
239  return err;
240}
241
242void write_common_dep_file(const string& output_file,
243                           const vector<string>& aidl_sources,
244                           CodeWriter* writer) {
245  // Encode that the output file depends on aidl input files.
246  writer->Write("%s : \\\n", output_file.c_str());
247  writer->Write("  %s", Join(aidl_sources, " \\\n  ").c_str());
248  writer->Write("\n\n");
249
250  // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
251  // has been deleted, moved or renamed in incremental build.
252  for (const auto& src : aidl_sources) {
253    writer->Write("%s :\n", src.c_str());
254  }
255}
256
257bool write_java_dep_file(const JavaOptions& options,
258                         const vector<unique_ptr<AidlImport>>& imports,
259                         const IoDelegate& io_delegate,
260                         const string& output_file_name) {
261  string dep_file_name = options.DependencyFilePath();
262  if (dep_file_name.empty()) {
263    return true;  // nothing to do
264  }
265  CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
266  if (!writer) {
267    LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
268    return false;
269  }
270
271  vector<string> source_aidl = {options.input_file_name_};
272  for (const auto& import : imports) {
273    if (!import->GetFilename().empty()) {
274      source_aidl.push_back(import->GetFilename());
275    }
276  }
277
278  write_common_dep_file(output_file_name, source_aidl, writer.get());
279
280  return true;
281}
282
283bool write_cpp_dep_file(const CppOptions& options,
284                        const AidlInterface& interface,
285                        const vector<unique_ptr<AidlImport>>& imports,
286                        const IoDelegate& io_delegate) {
287  using ::android::aidl::cpp::HeaderFile;
288  using ::android::aidl::cpp::ClassNames;
289
290  string dep_file_name = options.DependencyFilePath();
291  if (dep_file_name.empty()) {
292    return true;  // nothing to do
293  }
294  CodeWriterPtr writer = io_delegate.GetCodeWriter(dep_file_name);
295  if (!writer) {
296    LOG(ERROR) << "Could not open dependency file: " << dep_file_name;
297    return false;
298  }
299
300  vector<string> source_aidl = {options.InputFileName()};
301  for (const auto& import : imports) {
302    if (!import->GetFilename().empty()) {
303      source_aidl.push_back(import->GetFilename());
304    }
305  }
306
307  vector<string> headers;
308  for (ClassNames c : {ClassNames::CLIENT,
309                       ClassNames::SERVER,
310                       ClassNames::INTERFACE}) {
311    headers.push_back(options.OutputHeaderDir() + '/' +
312                      HeaderFile(interface, c, false /* use_os_sep */));
313  }
314
315  write_common_dep_file(options.OutputCppFilePath(), source_aidl, writer.get());
316  writer->Write("\n");
317
318  // Generated headers also depend on the source aidl files.
319  writer->Write("%s : \\\n    %s\n", Join(headers, " \\\n    ").c_str(),
320                Join(source_aidl, " \\\n    ").c_str());
321
322  return true;
323}
324
325string generate_outputFileName(const JavaOptions& options,
326                               const AidlInterface& interface) {
327    string name = interface.GetName();
328    string package = interface.GetPackage();
329    string result;
330
331    // create the path to the destination folder based on the
332    // interface package name
333    result = options.output_base_folder_;
334    result += OS_PATH_SEPARATOR;
335
336    string packageStr = package;
337    size_t len = packageStr.length();
338    for (size_t i=0; i<len; i++) {
339        if (packageStr[i] == '.') {
340            packageStr[i] = OS_PATH_SEPARATOR;
341        }
342    }
343
344    result += packageStr;
345
346    // add the filename by replacing the .aidl extension to .java
347    result += OS_PATH_SEPARATOR;
348    result.append(name, 0, name.find('.'));
349    result += ".java";
350
351    return result;
352}
353
354int check_and_assign_method_ids(const char * filename,
355                                const std::vector<std::unique_ptr<AidlMethod>>& items) {
356    // Check whether there are any methods with manually assigned id's and any that are not.
357    // Either all method id's must be manually assigned or all of them must not.
358    // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
359    set<int> usedIds;
360    bool hasUnassignedIds = false;
361    bool hasAssignedIds = false;
362    for (const auto& item : items) {
363        if (item->HasId()) {
364            hasAssignedIds = true;
365            // Ensure that the user set id is not duplicated.
366            if (usedIds.find(item->GetId()) != usedIds.end()) {
367                // We found a duplicate id, so throw an error.
368                fprintf(stderr,
369                        "%s:%d Found duplicate method id (%d) for method: %s\n",
370                        filename, item->GetLine(),
371                        item->GetId(), item->GetName().c_str());
372                return 1;
373            }
374            // Ensure that the user set id is within the appropriate limits
375            if (item->GetId() < kMinUserSetMethodId ||
376                    item->GetId() > kMaxUserSetMethodId) {
377                fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
378                        filename, item->GetLine(),
379                        item->GetId(), item->GetName().c_str());
380                fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
381                        kMinUserSetMethodId, kMaxUserSetMethodId);
382                return 1;
383            }
384            usedIds.insert(item->GetId());
385        } else {
386            hasUnassignedIds = true;
387        }
388        if (hasAssignedIds && hasUnassignedIds) {
389            fprintf(stderr,
390                    "%s: You must either assign id's to all methods or to none of them.\n",
391                    filename);
392            return 1;
393        }
394    }
395
396    // In the case that all methods have unassigned id's, set a unique id for them.
397    if (hasUnassignedIds) {
398        int newId = 0;
399        for (const auto& item : items) {
400            item->SetId(newId++);
401        }
402    }
403
404    // success
405    return 0;
406}
407
408// TODO: Remove this in favor of using the YACC parser b/25479378
409bool ParsePreprocessedLine(const string& line, string* decl,
410                           vector<string>* package, string* class_name) {
411  // erase all trailing whitespace and semicolons
412  const size_t end = line.find_last_not_of(" ;\t");
413  if (end == string::npos) {
414    return false;
415  }
416  if (line.rfind(';', end) != string::npos) {
417    return false;
418  }
419
420  decl->clear();
421  string type;
422  vector<string> pieces = Split(line.substr(0, end + 1), " \t");
423  for (const string& piece : pieces) {
424    if (piece.empty()) {
425      continue;
426    }
427    if (decl->empty()) {
428      *decl = std::move(piece);
429    } else if (type.empty()) {
430      type = std::move(piece);
431    } else {
432      return false;
433    }
434  }
435
436  // Note that this logic is absolutely wrong.  Given a parcelable
437  // org.some.Foo.Bar, the class name is Foo.Bar, but this code will claim that
438  // the class is just Bar.  However, this was the way it was done in the past.
439  //
440  // See b/17415692
441  size_t dot_pos = type.rfind('.');
442  if (dot_pos != string::npos) {
443    *class_name = type.substr(dot_pos + 1);
444    *package = Split(type.substr(0, dot_pos), ".");
445  } else {
446    *class_name = type;
447    package->clear();
448  }
449
450  return true;
451}
452
453}  // namespace
454
455namespace internals {
456
457bool parse_preprocessed_file(const IoDelegate& io_delegate,
458                             const string& filename, TypeNamespace* types) {
459  bool success = true;
460  unique_ptr<LineReader> line_reader = io_delegate.GetLineReader(filename);
461  if (!line_reader) {
462    LOG(ERROR) << "cannot open preprocessed file: " << filename;
463    success = false;
464    return success;
465  }
466
467  string line;
468  unsigned lineno = 1;
469  for ( ; line_reader->ReadLine(&line); ++lineno) {
470    if (line.empty() || line.compare(0, 2, "//") == 0) {
471      // skip comments and empty lines
472      continue;
473    }
474
475    string decl;
476    vector<string> package;
477    string class_name;
478    if (!ParsePreprocessedLine(line, &decl, &package, &class_name)) {
479      success = false;
480      break;
481    }
482
483    if (decl == "parcelable") {
484      AidlParcelable doc(new AidlQualifiedName(class_name, ""),
485                         lineno, package);
486      types->AddParcelableType(doc, filename);
487    } else if (decl == "interface") {
488      auto temp = new std::vector<std::unique_ptr<AidlMember>>();
489      AidlInterface doc(class_name, lineno, "", false, temp, package);
490      types->AddBinderType(doc, filename);
491    } else {
492      success = false;
493      break;
494    }
495  }
496  if (!success) {
497    LOG(ERROR) << filename << ':' << lineno
498               << " malformed preprocessed file line: '" << line << "'";
499  }
500
501  return success;
502}
503
504AidlError load_and_validate_aidl(
505    const std::vector<std::string> preprocessed_files,
506    const std::vector<std::string> import_paths,
507    const std::string& input_file_name,
508    const IoDelegate& io_delegate,
509    TypeNamespace* types,
510    std::unique_ptr<AidlInterface>* returned_interface,
511    std::vector<std::unique_ptr<AidlImport>>* returned_imports) {
512  AidlError err = AidlError::OK;
513
514  std::map<AidlImport*,std::unique_ptr<AidlDocument>> docs;
515
516  // import the preprocessed file
517  for (const string& s : preprocessed_files) {
518    if (!parse_preprocessed_file(io_delegate, s, types)) {
519      err = AidlError::BAD_PRE_PROCESSED_FILE;
520    }
521  }
522  if (err != AidlError::OK) {
523    return err;
524  }
525
526  // parse the input file
527  Parser p{io_delegate};
528  if (!p.ParseFile(input_file_name)) {
529    return AidlError::PARSE_ERROR;
530  }
531
532  AidlDocument* parsed_doc = p.GetDocument();
533
534  unique_ptr<AidlInterface> interface(parsed_doc->ReleaseInterface());
535
536  if (!interface) {
537    LOG(ERROR) << "refusing to generate code from aidl file defining "
538                  "parcelable";
539    return AidlError::FOUND_PARCELABLE;
540  }
541
542  if (!check_filename(input_file_name.c_str(), interface->GetPackage(),
543                      interface->GetName(), interface->GetLine()) ||
544      !types->IsValidPackage(interface->GetPackage())) {
545    LOG(ERROR) << "Invalid package declaration '" << interface->GetPackage()
546               << "'";
547    return AidlError::BAD_PACKAGE;
548  }
549
550  // parse the imports of the input file
551  ImportResolver import_resolver{io_delegate, import_paths};
552  for (auto& import : p.GetImports()) {
553    if (types->HasImportType(*import)) {
554      // There are places in the Android tree where an import doesn't resolve,
555      // but we'll pick the type up through the preprocessed types.
556      // This seems like an error, but legacy support demands we support it...
557      continue;
558    }
559    string import_path = import_resolver.FindImportFile(import->GetNeededClass());
560    if (import_path.empty()) {
561      cerr << import->GetFileFrom() << ":" << import->GetLine()
562           << ": couldn't find import for class "
563           << import->GetNeededClass() << endl;
564      err = AidlError::BAD_IMPORT;
565      continue;
566    }
567    import->SetFilename(import_path);
568
569    Parser p{io_delegate};
570    if (!p.ParseFile(import->GetFilename())) {
571      cerr << "error while parsing import for class "
572           << import->GetNeededClass() << endl;
573      err = AidlError::BAD_IMPORT;
574      continue;
575    }
576
577    std::unique_ptr<AidlDocument> document(p.ReleaseDocument());
578    if (!check_filenames(import->GetFilename(), document.get()))
579      err = AidlError::BAD_IMPORT;
580    docs[import.get()] = std::move(document);
581  }
582  if (err != AidlError::OK) {
583    return err;
584  }
585
586  // gather the types that have been declared
587  if (!types->AddBinderType(*interface.get(), input_file_name)) {
588    err = AidlError::BAD_TYPE;
589  }
590
591  interface->SetLanguageType(types->GetInterfaceType(*interface));
592
593  for (const auto& import : p.GetImports()) {
594    // If we skipped an unresolved import above (see comment there) we'll have
595    // an empty bucket here.
596    const auto import_itr = docs.find(import.get());
597    if (import_itr == docs.cend()) {
598      continue;
599    }
600
601    if (!gather_types(import->GetFilename(), import_itr->second.get(), types)) {
602      err = AidlError::BAD_TYPE;
603    }
604  }
605
606  // check the referenced types in parsed_doc to make sure we've imported them
607  if (check_types(input_file_name, interface.get(), types) != 0) {
608    err = AidlError::BAD_TYPE;
609  }
610  if (err != AidlError::OK) {
611    return err;
612  }
613
614
615  // assign method ids and validate.
616  if (check_and_assign_method_ids(input_file_name.c_str(),
617                                  interface->GetMethods()) != 0) {
618    return AidlError::BAD_METHOD_ID;
619  }
620
621  if (returned_interface)
622    *returned_interface = std::move(interface);
623
624  if (returned_imports)
625    p.ReleaseImports(returned_imports);
626
627  return AidlError::OK;
628}
629
630} // namespace internals
631
632int compile_aidl_to_cpp(const CppOptions& options,
633                        const IoDelegate& io_delegate) {
634  unique_ptr<AidlInterface> interface;
635  std::vector<std::unique_ptr<AidlImport>> imports;
636  unique_ptr<cpp::TypeNamespace> types(new cpp::TypeNamespace());
637  types->Init();
638  AidlError err = internals::load_and_validate_aidl(
639      std::vector<std::string>{},  // no preprocessed files
640      options.ImportPaths(),
641      options.InputFileName(),
642      io_delegate,
643      types.get(),
644      &interface,
645      &imports);
646  if (err != AidlError::OK) {
647    return 1;
648  }
649
650  if (!write_cpp_dep_file(options, *interface, imports, io_delegate)) {
651    return 1;
652  }
653
654  return (cpp::GenerateCpp(options, *types, *interface, io_delegate)) ? 0 : 1;
655}
656
657int compile_aidl_to_java(const JavaOptions& options,
658                         const IoDelegate& io_delegate) {
659  unique_ptr<AidlInterface> interface;
660  std::vector<std::unique_ptr<AidlImport>> imports;
661  unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
662  types->Init();
663  AidlError aidl_err = internals::load_and_validate_aidl(
664      options.preprocessed_files_,
665      options.import_paths_,
666      options.input_file_name_,
667      io_delegate,
668      types.get(),
669      &interface,
670      &imports);
671  if (aidl_err == AidlError::FOUND_PARCELABLE && !options.fail_on_parcelable_) {
672    // We aborted code generation because this file contains parcelables.
673    // However, we were not told to complain if we find parcelables.
674    // Just generate a dep file and exit quietly.  The dep file is for a legacy
675    // use case by the SDK.
676    write_java_dep_file(options, imports, io_delegate, "");
677    return 0;
678  }
679  if (aidl_err != AidlError::OK) {
680    return 1;
681  }
682
683  string output_file_name = options.output_file_name_;
684  // if needed, generate the output file name from the base folder
685  if (output_file_name.empty() && !options.output_base_folder_.empty()) {
686    output_file_name = generate_outputFileName(options, *interface);
687  }
688
689  // make sure the folders of the output file all exists
690  if (!io_delegate.CreatePathForFile(output_file_name)) {
691    return 1;
692  }
693
694  if (!write_java_dep_file(options, imports, io_delegate, output_file_name)) {
695    return 1;
696  }
697
698  return generate_java(output_file_name, options.input_file_name_.c_str(),
699                       interface.get(), types.get(), io_delegate);
700}
701
702bool preprocess_aidl(const JavaOptions& options,
703                     const IoDelegate& io_delegate) {
704  unique_ptr<CodeWriter> writer =
705      io_delegate.GetCodeWriter(options.output_file_name_);
706
707  for (const auto& file : options.files_to_preprocess_) {
708    Parser p{io_delegate};
709    if (!p.ParseFile(file))
710      return false;
711    AidlDocument* doc = p.GetDocument();
712    string line;
713
714    const AidlInterface* interface = doc->GetInterface();
715
716    if (interface != nullptr &&
717        !writer->Write("interface %s;\n",
718                       interface->GetCanonicalName().c_str())) {
719      return false;
720    }
721
722    for (const auto& parcelable : doc->GetParcelables()) {
723      if (!writer->Write("parcelable %s;\n",
724                         parcelable->GetCanonicalName().c_str())) {
725        return false;
726      }
727    }
728  }
729
730  return writer->Close();
731}
732
733}  // namespace android
734}  // namespace aidl
735