blob: a55724a33745d3fd64faef4a0f7ef57f9bcd99c2 [file] [log] [blame]
Christopher Wiley89eaab52015-09-15 14:46:46 -07001/*
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 */
Adam Lesinskiffa16862014-01-23 18:17:42 -080016
Christopher Wileyf690be52015-09-14 15:19:10 -070017#include "aidl.h"
Adam Lesinskiffa16862014-01-23 18:17:42 -080018
Christopher Wileyf690be52015-09-14 15:19:10 -070019#include <fcntl.h>
Christopher Wileyc16e5e72015-09-16 10:49:40 -070020#include <iostream>
Christopher Wileyf690be52015-09-14 15:19:10 -070021#include <map>
Adam Lesinskiffa16862014-01-23 18:17:42 -080022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Christopher Wileyf690be52015-09-14 15:19:10 -070025#include <sys/param.h>
26#include <sys/stat.h>
27#include <unistd.h>
Adam Lesinskiffa16862014-01-23 18:17:42 -080028
Elliott Hughes549b6e22015-08-17 12:41:46 -070029#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -080030#include <io.h>
Andrew Hsieh15ce9942014-05-07 20:14:30 +080031#include <direct.h>
Adam Lesinskiffa16862014-01-23 18:17:42 -080032#include <sys/stat.h>
33#endif
34
Christopher Wileyf690be52015-09-14 15:19:10 -070035
Christopher Wileyf690be52015-09-14 15:19:10 -070036#include "aidl_language.h"
Christopher Wileyeb1acc12015-09-16 11:25:13 -070037#include "generate_cpp.h"
Christopher Wileyf690be52015-09-14 15:19:10 -070038#include "generate_java.h"
39#include "logging.h"
40#include "options.h"
41#include "os.h"
42#include "parse_helpers.h"
43#include "search_path.h"
Christopher Wiley775fa1f2015-09-22 15:00:12 -070044#include "type_java.h"
Christopher Wiley84c1eac2015-09-23 13:29:28 -070045#include "type_namespace.h"
Christopher Wileyf690be52015-09-14 15:19:10 -070046
Adam Lesinskiffa16862014-01-23 18:17:42 -080047#ifndef O_BINARY
48# define O_BINARY 0
49#endif
50
Christopher Wileyc16e5e72015-09-16 10:49:40 -070051using std::cerr;
52using std::endl;
Christopher Wiley9f4c7ae2015-08-24 14:07:32 -070053using std::map;
54using std::set;
55using std::string;
Christopher Wiley84c1eac2015-09-23 13:29:28 -070056using std::unique_ptr;
Christopher Wiley9f4c7ae2015-08-24 14:07:32 -070057using std::vector;
Adam Lesinskiffa16862014-01-23 18:17:42 -080058
Christopher Wileyf690be52015-09-14 15:19:10 -070059namespace android {
60namespace aidl {
61namespace {
Adam Lesinskiffa16862014-01-23 18:17:42 -080062
Christopher Wileyf690be52015-09-14 15:19:10 -070063// The following are gotten as the offset from the allowable id's between
64// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
65// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
66const int kMinUserSetMethodId = 0;
67const int kMaxUserSetMethodId = 16777214;
Adam Lesinskiffa16862014-01-23 18:17:42 -080068
Christopher Wileyf690be52015-09-14 15:19:10 -070069int check_filename(const char* filename,
70 const char* package,
71 buffer_type* name) {
Adam Lesinskiffa16862014-01-23 18:17:42 -080072 const char* p;
73 string expected;
74 string fn;
75 size_t len;
76 char cwd[MAXPATHLEN];
77 bool valid = false;
78
Elliott Hughesce310da2015-07-29 08:44:17 -070079#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -080080 if (isalpha(filename[0]) && filename[1] == ':'
81 && filename[2] == OS_PATH_SEPARATOR) {
82#else
83 if (filename[0] == OS_PATH_SEPARATOR) {
84#endif
85 fn = filename;
86 } else {
87 fn = getcwd(cwd, sizeof(cwd));
88 len = fn.length();
89 if (fn[len-1] != OS_PATH_SEPARATOR) {
90 fn += OS_PATH_SEPARATOR;
91 }
92 fn += filename;
93 }
94
95 if (package) {
96 expected = package;
97 expected += '.';
98 }
99
100 len = expected.length();
101 for (size_t i=0; i<len; i++) {
102 if (expected[i] == '.') {
103 expected[i] = OS_PATH_SEPARATOR;
104 }
105 }
106
107 p = strchr(name->data, '.');
108 len = p ? p-name->data : strlen(name->data);
109 expected.append(name->data, len);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700110
Adam Lesinskiffa16862014-01-23 18:17:42 -0800111 expected += ".aidl";
112
113 len = fn.length();
114 valid = (len >= expected.length());
115
116 if (valid) {
117 p = fn.c_str() + (len - expected.length());
118
Elliott Hughesce310da2015-07-29 08:44:17 -0700119#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800120 if (OS_PATH_SEPARATOR != '/') {
121 // Input filename under cygwin most likely has / separators
122 // whereas the expected string uses \\ separators. Adjust
123 // them accordingly.
124 for (char *c = const_cast<char *>(p); *c; ++c) {
125 if (*c == '/') *c = OS_PATH_SEPARATOR;
126 }
127 }
128#endif
129
Yabin Cui482eefb2014-11-10 15:01:43 -0800130 // aidl assumes case-insensitivity on Mac Os and Windows.
131#if defined(__linux__)
Adam Lesinskiffa16862014-01-23 18:17:42 -0800132 valid = (expected == p);
133#else
134 valid = !strcasecmp(expected.c_str(), p);
135#endif
136 }
137
138 if (!valid) {
139 fprintf(stderr, "%s:%d interface %s should be declared in a file"
140 " called %s.\n",
141 filename, name->lineno, name->data, expected.c_str());
142 return 1;
143 }
144
145 return 0;
146}
147
Christopher Wileyf690be52015-09-14 15:19:10 -0700148int check_filenames(const char* filename, document_item_type* items) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800149 int err = 0;
150 while (items) {
151 if (items->item_type == USER_DATA_TYPE) {
152 user_data_type* p = (user_data_type*)items;
153 err |= check_filename(filename, p->package, &p->name);
154 }
Casey Dahlin88868fc2015-09-01 13:21:26 -0700155 else if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800156 interface_type* c = (interface_type*)items;
157 err |= check_filename(filename, c->package, &c->name);
158 }
159 else {
160 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
161 items->item_type);
162 return 1;
163 }
164 items = items->next;
165 }
166 return err;
167}
168
Christopher Wileyf690be52015-09-14 15:19:10 -0700169char* rfind(char* str, char c) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800170 char* p = str + strlen(str) - 1;
171 while (p >= str) {
172 if (*p == c) {
173 return p;
174 }
175 p--;
176 }
177 return NULL;
178}
179
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700180bool gather_types(const char* raw_filename,
181 document_item_type* all_items,
182 TypeNamespace* types) {
183 bool success = true;
184 if (raw_filename == nullptr)
185 raw_filename = "";
186 const std::string filename{raw_filename};
Adam Lesinskiffa16862014-01-23 18:17:42 -0800187
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700188 for (document_item_type* item = all_items; item; item = item->next) {
189 if (item->item_type == USER_DATA_TYPE) {
190 user_data_type* p = (user_data_type*)item;
191 success &= types->AddParcelableType(p, filename);
192 } else if (item->item_type == INTERFACE_TYPE_BINDER) {
193 interface_type* c = (interface_type*)item;
194 success &= types->AddBinderType(c, filename);
195 } else {
196 LOG(FATAL) << "internal error";
Adam Lesinskiffa16862014-01-23 18:17:42 -0800197 }
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700198 }
199 return success;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800200}
201
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700202int check_types(const string& filename,
203 interface_type* c,
204 TypeNamespace* types) {
205 int err = 0;
206 map<string,method_type*> method_names;
207 for (interface_item_type* member = c->interface_items;
208 member;
209 member = member->next) {
210 if (member->item_type != METHOD_TYPE) {
211 continue;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800212 }
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700213 method_type* m = (method_type*)member;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800214
Adam Lesinskiffa16862014-01-23 18:17:42 -0800215
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700216 if (!types->AddContainerType(m->type.type.data) ||
217 !types->IsValidReturnType(&m->type, filename)) {
218 err = 1; // return type is invalid
Adam Lesinskiffa16862014-01-23 18:17:42 -0800219 }
220
221 int index = 1;
Casey Dahlinbc7a50a2015-09-28 19:20:50 -0700222 for (const std::unique_ptr<AidlArgument>& arg : *m->args) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700223 if (!types->AddContainerType(arg->type.type.data) ||
Casey Dahlinbc7a50a2015-09-28 19:20:50 -0700224 !types->IsValidArg(*arg, index, filename)) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700225 err = 1;
226 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800227 }
228
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700229 // prevent duplicate methods
230 if (method_names.find(m->name.data) == method_names.end()) {
231 method_names[m->name.data] = m;
232 } else {
233 cerr << filename << ":" << m->name.lineno
234 << " attempt to redefine method " << m->name.data << "," << endl
235 << filename << ":" << m->name.lineno
236 << " previously defined here." << endl;
237 err = 1;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800238 }
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700239 }
240 return err;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800241}
242
Christopher Wileyf690be52015-09-14 15:19:10 -0700243void generate_dep_file(const JavaOptions& options,
244 const document_item_type* items,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700245 import_info* import_head) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800246 /* we open the file in binary mode to ensure that the same output is
247 * generated on all platforms !!
248 */
249 FILE* to = NULL;
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700250 if (options.auto_dep_file_) {
251 string fileName = options.output_file_name_ + ".d";
Adam Lesinskiffa16862014-01-23 18:17:42 -0800252 to = fopen(fileName.c_str(), "wb");
253 } else {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700254 to = fopen(options.dep_file_name_.c_str(), "wb");
Adam Lesinskiffa16862014-01-23 18:17:42 -0800255 }
256
257 if (to == NULL) {
258 return;
259 }
260
261 const char* slash = "\\";
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700262 import_info* import = import_head;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800263 if (import == NULL) {
264 slash = "";
265 }
266
Casey Dahlin88868fc2015-09-01 13:21:26 -0700267 if (items->item_type == INTERFACE_TYPE_BINDER) {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700268 fprintf(to, "%s: \\\n", options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800269 } else {
270 // parcelable: there's no output file.
271 fprintf(to, " : \\\n");
272 }
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700273 fprintf(to, " %s %s\n", options.input_file_name_.c_str(), slash);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800274
275 while (import) {
276 if (import->next == NULL) {
277 slash = "";
278 }
279 if (import->filename) {
280 fprintf(to, " %s %s\n", import->filename, slash);
281 }
282 import = import->next;
283 }
284
285 fprintf(to, "\n");
286
Ying Wang0e4861a2015-07-22 17:42:35 -0700287 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
288 // has been deleted, moved or renamed in incremental build.
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700289 fprintf(to, "%s :\n", options.input_file_name_.c_str());
Ying Wang0e4861a2015-07-22 17:42:35 -0700290
Adam Lesinskiffa16862014-01-23 18:17:42 -0800291 // Output "<imported_file>: " so make won't fail if the imported file has
292 // been deleted, moved or renamed in incremental build.
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700293 import = import_head;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800294 while (import) {
295 if (import->filename) {
296 fprintf(to, "%s :\n", import->filename);
297 }
298 import = import->next;
299 }
300
301 fclose(to);
302}
303
Christopher Wileyf690be52015-09-14 15:19:10 -0700304string generate_outputFileName2(const JavaOptions& options,
305 const buffer_type& name,
306 const char* package) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800307 string result;
308
309 // create the path to the destination folder based on the
310 // interface package name
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700311 result = options.output_base_folder_;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800312 result += OS_PATH_SEPARATOR;
313
314 string packageStr = package;
315 size_t len = packageStr.length();
316 for (size_t i=0; i<len; i++) {
317 if (packageStr[i] == '.') {
318 packageStr[i] = OS_PATH_SEPARATOR;
319 }
320 }
321
322 result += packageStr;
323
324 // add the filename by replacing the .aidl extension to .java
325 const char* p = strchr(name.data, '.');
326 len = p ? p-name.data : strlen(name.data);
327
328 result += OS_PATH_SEPARATOR;
329 result.append(name.data, len);
330 result += ".java";
331
332 return result;
333}
334
Christopher Wileyf690be52015-09-14 15:19:10 -0700335string generate_outputFileName(const JavaOptions& options,
336 const document_item_type* items) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800337 // items has already been checked to have only one interface.
Casey Dahlin88868fc2015-09-01 13:21:26 -0700338 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800339 interface_type* type = (interface_type*)items;
340
341 return generate_outputFileName2(options, type->name, type->package);
342 } else if (items->item_type == USER_DATA_TYPE) {
343 user_data_type* type = (user_data_type*)items;
344 return generate_outputFileName2(options, type->name, type->package);
345 }
346
347 // I don't think we can come here, but safer than returning NULL.
348 string result;
349 return result;
350}
351
352
Christopher Wileyf690be52015-09-14 15:19:10 -0700353void check_outputFilePath(const string& path) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800354 size_t len = path.length();
355 for (size_t i=0; i<len ; i++) {
356 if (path[i] == OS_PATH_SEPARATOR) {
357 string p = path.substr(0, i);
358 if (access(path.data(), F_OK) != 0) {
Elliott Hughes549b6e22015-08-17 12:41:46 -0700359#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800360 _mkdir(p.data());
361#else
362 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
363#endif
364 }
365 }
366 }
367}
368
369
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700370int parse_preprocessed_file(const string& filename, TypeNamespace* types) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800371 FILE* f = fopen(filename.c_str(), "rb");
372 if (f == NULL) {
373 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
374 filename.c_str());
375 return 1;
376 }
377
378 int lineno = 1;
379 char line[1024];
380 char type[1024];
381 char fullname[1024];
382 while (fgets(line, sizeof(line), f)) {
383 // skip comments and empty lines
384 if (!line[0] || strncmp(line, "//", 2) == 0) {
385 continue;
386 }
387
388 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
389
390 char* packagename;
391 char* classname = rfind(fullname, '.');
392 if (classname != NULL) {
393 *classname = '\0';
394 classname++;
395 packagename = fullname;
396 } else {
397 classname = fullname;
398 packagename = NULL;
399 }
400
401 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
402 // type, packagename, classname);
403 document_item_type* doc;
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700404
Adam Lesinskiffa16862014-01-23 18:17:42 -0800405 if (0 == strcmp("parcelable", type)) {
Christopher Wileyb2116862015-09-29 16:08:57 +0000406 user_data_type* parcl = (user_data_type*)malloc(
407 sizeof(user_data_type));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800408 memset(parcl, 0, sizeof(user_data_type));
409 parcl->document_item.item_type = USER_DATA_TYPE;
410 parcl->keyword_token.lineno = lineno;
411 parcl->keyword_token.data = strdup(type);
412 parcl->package = packagename ? strdup(packagename) : NULL;
413 parcl->name.lineno = lineno;
414 parcl->name.data = strdup(classname);
415 parcl->semicolon_token.lineno = lineno;
416 parcl->semicolon_token.data = strdup(";");
Casey Dahlin88868fc2015-09-01 13:21:26 -0700417 parcl->parcelable = true;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800418 doc = (document_item_type*)parcl;
419 }
420 else if (0 == strcmp("interface", type)) {
Christopher Wileyb2116862015-09-29 16:08:57 +0000421 interface_type* iface = (interface_type*)malloc(
422 sizeof(interface_type));
Adam Lesinskiffa16862014-01-23 18:17:42 -0800423 memset(iface, 0, sizeof(interface_type));
424 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
425 iface->interface_token.lineno = lineno;
426 iface->interface_token.data = strdup(type);
427 iface->package = packagename ? strdup(packagename) : NULL;
428 iface->name.lineno = lineno;
429 iface->name.data = strdup(classname);
430 iface->open_brace_token.lineno = lineno;
431 iface->open_brace_token.data = strdup("{");
432 iface->close_brace_token.lineno = lineno;
433 iface->close_brace_token.data = strdup("}");
434 doc = (document_item_type*)iface;
435 }
436 else {
437 fprintf(stderr, "%s:%d: bad type in line: %s\n",
438 filename.c_str(), lineno, line);
Elliott Hughes5cd06072013-10-29 15:25:52 -0700439 fclose(f);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800440 return 1;
441 }
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700442 if (!gather_types(filename.c_str(), doc, types)) {
443 fprintf(stderr, "Failed to gather types for preprocessed aidl.\n");
444 fclose(f);
445 return 1;
446 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800447 lineno++;
448 }
449
450 if (!feof(f)) {
451 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
452 filename.c_str(), lineno);
453 return 1;
454 }
455
456 fclose(f);
457 return 0;
458}
459
Christopher Wileyf690be52015-09-14 15:19:10 -0700460int check_and_assign_method_ids(const char * filename,
461 interface_item_type* first_item) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800462 // Check whether there are any methods with manually assigned id's and any that are not.
463 // Either all method id's must be manually assigned or all of them must not.
464 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
465 set<int> usedIds;
466 interface_item_type* item = first_item;
467 bool hasUnassignedIds = false;
468 bool hasAssignedIds = false;
469 while (item != NULL) {
470 if (item->item_type == METHOD_TYPE) {
471 method_type* method_item = (method_type*)item;
472 if (method_item->hasId) {
473 hasAssignedIds = true;
474 method_item->assigned_id = atoi(method_item->id.data);
475 // Ensure that the user set id is not duplicated.
476 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
477 // We found a duplicate id, so throw an error.
478 fprintf(stderr,
479 "%s:%d Found duplicate method id (%d) for method: %s\n",
480 filename, method_item->id.lineno,
481 method_item->assigned_id, method_item->name.data);
482 return 1;
483 }
484 // Ensure that the user set id is within the appropriate limits
Christopher Wileyf690be52015-09-14 15:19:10 -0700485 if (method_item->assigned_id < kMinUserSetMethodId ||
486 method_item->assigned_id > kMaxUserSetMethodId) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800487 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
488 filename, method_item->id.lineno,
489 method_item->assigned_id, method_item->name.data);
490 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
Christopher Wileyf690be52015-09-14 15:19:10 -0700491 kMinUserSetMethodId, kMaxUserSetMethodId);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800492 return 1;
493 }
494 usedIds.insert(method_item->assigned_id);
495 } else {
496 hasUnassignedIds = true;
497 }
498 if (hasAssignedIds && hasUnassignedIds) {
499 fprintf(stderr,
500 "%s: You must either assign id's to all methods or to none of them.\n",
501 filename);
502 return 1;
503 }
504 }
505 item = item->next;
506 }
507
508 // In the case that all methods have unassigned id's, set a unique id for them.
509 if (hasUnassignedIds) {
510 int newId = 0;
511 item = first_item;
512 while (item != NULL) {
513 if (item->item_type == METHOD_TYPE) {
514 method_type* method_item = (method_type*)item;
515 method_item->assigned_id = newId++;
516 }
517 item = item->next;
518 }
519 }
520
521 // success
522 return 0;
523}
524
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700525int load_and_validate_aidl(const std::vector<std::string> preprocessed_files,
526 const std::vector<std::string> import_paths,
527 const std::string& input_file_name,
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700528 TypeNamespace* types,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700529 interface_type** returned_interface,
530 import_info** returned_imports) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700531 int err = 0;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800532
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700533 set_import_paths(import_paths);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800534
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700535 // import the preprocessed file
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700536 for (const string& s : preprocessed_files) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700537 err |= parse_preprocessed_file(s, types);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700538 }
539 if (err != 0) {
540 return err;
541 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800542
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700543 // parse the input file
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700544 Parser p{input_file_name};
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700545 if (!p.OpenFileFromDisk() || !p.RunParser()) {
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700546 return 1;
547 }
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700548 document_item_type* parsed_doc = p.GetDocument();
549 // We could in theory declare parcelables in the same file as the interface.
550 // In practice, those parcelables would have to have the same name as
551 // the interface, since this was originally written to support Java, with its
552 // packages and names that correspond to file system structure.
553 // Since we can't have two distinct classes with the same name and package,
554 // we can't actually declare parcelables in the same file.
555 if (parsed_doc == nullptr ||
556 parsed_doc->item_type != INTERFACE_TYPE_BINDER ||
557 parsed_doc->next != nullptr) {
558 cerr << "aidl expects exactly one interface per input file";
Christopher Wileya2f516d2015-09-24 10:12:31 -0700559 return 1;
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700560 }
561 interface_type* interface = (interface_type*)parsed_doc;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700562 err |= check_filename(input_file_name.c_str(),
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700563 interface->package, &interface->name);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800564
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700565 // parse the imports of the input file
566 for (import_info* import = p.GetImports(); import; import = import->next) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700567 if (types->HasType(import->neededClass)) {
568 // There are places in the Android tree where an import doesn't resolve,
569 // but we'll pick the type up through the preprocessed types.
570 // This seems like an error, but legacy support demands we support it...
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700571 continue;
572 }
573 import->filename = find_import_file(import->neededClass);
574 if (!import->filename) {
575 cerr << import->from << ":" << import->statement.lineno
576 << ": couldn't find import for class "
577 << import->neededClass << endl;
578 err |= 1;
579 continue;
580 }
581 Parser p{import->filename};
582 if (!p.OpenFileFromDisk() || !p.RunParser() || p.GetDocument() == nullptr) {
583 cerr << "error while parsing import for class "
584 << import->neededClass << endl;
585 err |= 1;
586 continue;
587 }
588 import->doc = p.GetDocument();
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700589 err |= check_filenames(import->filename, import->doc);
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700590 }
591 if (err != 0) {
592 return err;
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700593 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800594
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700595 // gather the types that have been declared
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700596 if (!gather_types(input_file_name.c_str(), parsed_doc, types)) {
597 err |= 1;
598 }
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700599 for (import_info* import = p.GetImports(); import; import = import->next) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700600 if (!gather_types(import->filename, import->doc, types)) {
601 err |= 1;
602 }
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700603 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800604
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700605 // check the referenced types in parsed_doc to make sure we've imported them
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700606 err |= check_types(input_file_name, interface, types);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800607
Adam Lesinskiffa16862014-01-23 18:17:42 -0800608
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700609 // assign method ids and validate.
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700610 err |= check_and_assign_method_ids(input_file_name.c_str(),
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700611 interface->interface_items);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800612
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700613 // after this, there shouldn't be any more errors because of the
614 // input.
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700615 if (err != 0) {
616 return err;
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700617 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800618
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700619 *returned_interface = interface;
620 *returned_imports = p.GetImports();
621 return 0;
622}
623
624} // namespace
625
626int compile_aidl_to_cpp(const CppOptions& options) {
627 interface_type* interface = nullptr;
628 import_info* imports = nullptr;
Christopher Wileydb154a52015-09-28 16:32:25 -0700629 unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700630 int err = load_and_validate_aidl(std::vector<std::string>{},
631 options.ImportPaths(),
632 options.InputFileName(),
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -0700633 types.get(),
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700634 &interface,
635 &imports);
636 if (err != 0) {
637 return err;
638 }
639
640 // TODO(wiley) b/23600457 generate a dependency file if requested with -b
641
Christopher Wiley9a8e1d92015-09-19 10:34:33 -0700642 return (GenerateCpp(options, interface)) ? 0 : 1;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700643}
644
645int compile_aidl_to_java(const JavaOptions& options) {
646 interface_type* interface = nullptr;
647 import_info* imports = nullptr;
Christopher Wileydb154a52015-09-28 16:32:25 -0700648 unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700649 int err = load_and_validate_aidl(options.preprocessed_files_,
650 options.import_paths_,
651 options.input_file_name_,
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -0700652 types.get(),
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700653 &interface,
654 &imports);
655 if (err != 0) {
656 return err;
657 }
658 document_item_type* parsed_doc = (document_item_type*)interface;
659
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700660 string output_file_name = options.output_file_name_;
661 // if needed, generate the output file name from the base folder
662 if (output_file_name.length() == 0 &&
663 options.output_base_folder_.length() > 0) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700664 output_file_name = generate_outputFileName(options, parsed_doc);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700665 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800666
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700667 // if we were asked to, generate a make dependency file
668 // unless it's a parcelable *and* it's supposed to fail on parcelable
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700669 if (options.auto_dep_file_ || options.dep_file_name_ != "") {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800670 // make sure the folders of the output file all exists
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700671 check_outputFilePath(output_file_name);
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700672 generate_dep_file(options, parsed_doc, imports);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700673 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800674
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700675 // make sure the folders of the output file all exists
676 check_outputFilePath(output_file_name);
677
678 err = generate_java(output_file_name, options.input_file_name_.c_str(),
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -0700679 interface, types.get());
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700680
681 return err;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800682}
683
Christopher Wileyf690be52015-09-14 15:19:10 -0700684int preprocess_aidl(const JavaOptions& options) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800685 vector<string> lines;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800686
687 // read files
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700688 int N = options.files_to_preprocess_.size();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800689 for (int i=0; i<N; i++) {
Casey Dahline2507492015-09-14 17:11:20 -0700690 Parser p{options.files_to_preprocess_[i]};
Casey Dahlin99801812015-09-15 18:19:25 -0700691 if (!p.OpenFileFromDisk())
Casey Dahline2507492015-09-14 17:11:20 -0700692 return 1;
Casey Dahlin99801812015-09-15 18:19:25 -0700693 if (!p.RunParser())
694 return 1;
Casey Dahline2507492015-09-14 17:11:20 -0700695 document_item_type* doc = p.GetDocument();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800696 string line;
697 if (doc->item_type == USER_DATA_TYPE) {
698 user_data_type* parcelable = (user_data_type*)doc;
Casey Dahlin88868fc2015-09-01 13:21:26 -0700699 if (parcelable->parcelable) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800700 line = "parcelable ";
701 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800702 if (parcelable->package) {
703 line += parcelable->package;
704 line += '.';
705 }
706 line += parcelable->name.data;
707 } else {
708 line = "interface ";
709 interface_type* iface = (interface_type*)doc;
710 if (iface->package) {
711 line += iface->package;
712 line += '.';
713 }
714 line += iface->name.data;
715 }
716 line += ";\n";
717 lines.push_back(line);
718 }
719
720 // write preprocessed file
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700721 int fd = open( options.output_file_name_.c_str(),
Adam Lesinskiffa16862014-01-23 18:17:42 -0800722 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
Elliott Hughes549b6e22015-08-17 12:41:46 -0700723#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800724 _S_IREAD|_S_IWRITE);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700725#else
Adam Lesinskiffa16862014-01-23 18:17:42 -0800726 S_IRUSR|S_IWUSR|S_IRGRP);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700727#endif
Adam Lesinskiffa16862014-01-23 18:17:42 -0800728 if (fd == -1) {
729 fprintf(stderr, "aidl: could not open file for write: %s\n",
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700730 options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800731 return 1;
732 }
733
734 N = lines.size();
735 for (int i=0; i<N; i++) {
736 const string& s = lines[i];
737 int len = s.length();
738 if (len != write(fd, s.c_str(), len)) {
739 fprintf(stderr, "aidl: error writing to file %s\n",
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700740 options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800741 close(fd);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700742 unlink(options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800743 return 1;
744 }
745 }
746
747 close(fd);
748 return 0;
749}
Christopher Wileyfdeb0f42015-09-11 15:38:22 -0700750
751} // namespace android
752} // namespace aidl