blob: 2d8f0acf8bb5509e134c89efb67be0d1190338e7 [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001
2#include "aidl_language.h"
3#include "options.h"
Elliott Hughes9ec96f92015-07-29 14:35:18 -07004#include "os.h"
Adam Lesinski282e1812014-01-23 18:17:42 -08005#include "search_path.h"
6#include "Type.h"
7#include "generate_java.h"
8#include <unistd.h>
9#include <fcntl.h>
10#include <sys/param.h>
11#include <sys/stat.h>
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <map>
17
Elliott Hughese17788c2015-08-17 12:41:46 -070018#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -080019#include <io.h>
Andrew Hsiehc9d32392014-05-07 20:14:30 +080020#include <direct.h>
Adam Lesinski282e1812014-01-23 18:17:42 -080021#include <sys/stat.h>
22#endif
23
24#ifndef O_BINARY
25# define O_BINARY 0
26#endif
27
28// The following are gotten as the offset from the allowable id's between
29// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
30// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
31#define MIN_USER_SET_METHOD_ID 0
32#define MAX_USER_SET_METHOD_ID 16777214
33
Christopher Wiley1eaa9ed2015-08-24 14:07:32 -070034using std::map;
35using std::set;
36using std::string;
37using std::vector;
Adam Lesinski282e1812014-01-23 18:17:42 -080038
39static void
40test_document(document_item_type* d)
41{
42 while (d) {
43 if (d->item_type == INTERFACE_TYPE_BINDER) {
44 interface_type* c = (interface_type*)d;
45 printf("interface %s %s {\n", c->package, c->name.data);
46 interface_item_type *q = (interface_item_type*)c->interface_items;
47 while (q) {
48 if (q->item_type == METHOD_TYPE) {
49 method_type *m = (method_type*)q;
50 printf(" %s %s(", m->type.type.data, m->name.data);
51 arg_type *p = m->args;
52 while (p) {
53 printf("%s %s",p->type.type.data,p->name.data);
54 if (p->next) printf(", ");
55 p=p->next;
56 }
57 printf(")");
58 printf(";\n");
59 }
60 q=q->next;
61 }
62 printf("}\n");
63 }
64 else if (d->item_type == USER_DATA_TYPE) {
65 user_data_type* b = (user_data_type*)d;
66 if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
67 printf("parcelable %s %s;\n", b->package, b->name.data);
68 }
69 if ((b->flattening_methods & RPC_DATA) != 0) {
70 printf("flattenable %s %s;\n", b->package, b->name.data);
71 }
72 }
73 else {
74 printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
75 }
76 d = d->next;
77 }
78}
79
80// ==========================================================
81int
82convert_direction(const char* direction)
83{
84 if (direction == NULL) {
85 return IN_PARAMETER;
86 }
87 if (0 == strcmp(direction, "in")) {
88 return IN_PARAMETER;
89 }
90 if (0 == strcmp(direction, "out")) {
91 return OUT_PARAMETER;
92 }
93 return INOUT_PARAMETER;
94}
95
96// ==========================================================
97struct import_info {
98 const char* from;
99 const char* filename;
100 buffer_type statement;
101 const char* neededClass;
102 document_item_type* doc;
103 struct import_info* next;
104};
105
106document_item_type* g_document = NULL;
107import_info* g_imports = NULL;
108
109static void
110main_document_parsed(document_item_type* d)
111{
112 g_document = d;
113}
114
115static void
116main_import_parsed(buffer_type* statement)
117{
118 import_info* import = (import_info*)malloc(sizeof(import_info));
119 memset(import, 0, sizeof(import_info));
120 import->from = strdup(g_currentFilename);
121 import->statement.lineno = statement->lineno;
122 import->statement.data = strdup(statement->data);
123 import->statement.extra = NULL;
124 import->next = g_imports;
125 import->neededClass = parse_import_statement(statement->data);
126 g_imports = import;
127}
128
129static ParserCallbacks g_mainCallbacks = {
130 &main_document_parsed,
131 &main_import_parsed
132};
133
134char*
135parse_import_statement(const char* text)
136{
137 const char* end;
138 int len;
139
140 while (isspace(*text)) {
141 text++;
142 }
143 while (!isspace(*text)) {
144 text++;
145 }
146 while (isspace(*text)) {
147 text++;
148 }
149 end = text;
150 while (!isspace(*end) && *end != ';') {
151 end++;
152 }
153 len = end-text;
154
155 char* rv = (char*)malloc(len+1);
156 memcpy(rv, text, len);
157 rv[len] = '\0';
158
159 return rv;
160}
161
162// ==========================================================
163static void
164import_import_parsed(buffer_type* statement)
165{
166}
167
168static ParserCallbacks g_importCallbacks = {
169 &main_document_parsed,
170 &import_import_parsed
171};
172
173// ==========================================================
174static int
175check_filename(const char* filename, const char* package, buffer_type* name)
176{
177 const char* p;
178 string expected;
179 string fn;
180 size_t len;
181 char cwd[MAXPATHLEN];
182 bool valid = false;
183
Elliott Hughes98c11b52015-07-29 08:44:17 -0700184#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800185 if (isalpha(filename[0]) && filename[1] == ':'
186 && filename[2] == OS_PATH_SEPARATOR) {
187#else
188 if (filename[0] == OS_PATH_SEPARATOR) {
189#endif
190 fn = filename;
191 } else {
192 fn = getcwd(cwd, sizeof(cwd));
193 len = fn.length();
194 if (fn[len-1] != OS_PATH_SEPARATOR) {
195 fn += OS_PATH_SEPARATOR;
196 }
197 fn += filename;
198 }
199
200 if (package) {
201 expected = package;
202 expected += '.';
203 }
204
205 len = expected.length();
206 for (size_t i=0; i<len; i++) {
207 if (expected[i] == '.') {
208 expected[i] = OS_PATH_SEPARATOR;
209 }
210 }
211
212 p = strchr(name->data, '.');
213 len = p ? p-name->data : strlen(name->data);
214 expected.append(name->data, len);
215
216 expected += ".aidl";
217
218 len = fn.length();
219 valid = (len >= expected.length());
220
221 if (valid) {
222 p = fn.c_str() + (len - expected.length());
223
Elliott Hughes98c11b52015-07-29 08:44:17 -0700224#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800225 if (OS_PATH_SEPARATOR != '/') {
226 // Input filename under cygwin most likely has / separators
227 // whereas the expected string uses \\ separators. Adjust
228 // them accordingly.
229 for (char *c = const_cast<char *>(p); *c; ++c) {
230 if (*c == '/') *c = OS_PATH_SEPARATOR;
231 }
232 }
233#endif
234
Yabin Cuifb8e2b12014-11-10 15:01:43 -0800235 // aidl assumes case-insensitivity on Mac Os and Windows.
236#if defined(__linux__)
Adam Lesinski282e1812014-01-23 18:17:42 -0800237 valid = (expected == p);
238#else
239 valid = !strcasecmp(expected.c_str(), p);
240#endif
241 }
242
243 if (!valid) {
244 fprintf(stderr, "%s:%d interface %s should be declared in a file"
245 " called %s.\n",
246 filename, name->lineno, name->data, expected.c_str());
247 return 1;
248 }
249
250 return 0;
251}
252
253static int
254check_filenames(const char* filename, document_item_type* items)
255{
256 int err = 0;
257 while (items) {
258 if (items->item_type == USER_DATA_TYPE) {
259 user_data_type* p = (user_data_type*)items;
260 err |= check_filename(filename, p->package, &p->name);
261 }
262 else if (items->item_type == INTERFACE_TYPE_BINDER
263 || items->item_type == INTERFACE_TYPE_RPC) {
264 interface_type* c = (interface_type*)items;
265 err |= check_filename(filename, c->package, &c->name);
266 }
267 else {
268 fprintf(stderr, "aidl: internal error unkown document type %d.\n",
269 items->item_type);
270 return 1;
271 }
272 items = items->next;
273 }
274 return err;
275}
276
277// ==========================================================
278static const char*
279kind_to_string(int kind)
280{
281 switch (kind)
282 {
283 case Type::INTERFACE:
284 return "an interface";
285 case Type::USERDATA:
286 return "a user data";
287 default:
288 return "ERROR";
289 }
290}
291
292static char*
293rfind(char* str, char c)
294{
295 char* p = str + strlen(str) - 1;
296 while (p >= str) {
297 if (*p == c) {
298 return p;
299 }
300 p--;
301 }
302 return NULL;
303}
304
305static int
306gather_types(const char* filename, document_item_type* items)
307{
308 int err = 0;
309 while (items) {
310 Type* type;
311 if (items->item_type == USER_DATA_TYPE) {
312 user_data_type* p = (user_data_type*)items;
313 type = new UserDataType(p->package ? p->package : "", p->name.data,
314 false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
315 ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
316 }
317 else if (items->item_type == INTERFACE_TYPE_BINDER
318 || items->item_type == INTERFACE_TYPE_RPC) {
319 interface_type* c = (interface_type*)items;
320 type = new InterfaceType(c->package ? c->package : "",
321 c->name.data, false, c->oneway,
322 filename, c->name.lineno);
323 }
324 else {
325 fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
326 return 1;
327 }
328
329 Type* old = NAMES.Find(type->QualifiedName());
330 if (old == NULL) {
331 NAMES.Add(type);
332
333 if (items->item_type == INTERFACE_TYPE_BINDER) {
334 // for interfaces, also add the stub and proxy types, we don't
335 // bother checking these for duplicates, because the parser
336 // won't let us do it.
337 interface_type* c = (interface_type*)items;
338
339 string name = c->name.data;
340 name += ".Stub";
341 Type* stub = new Type(c->package ? c->package : "",
342 name, Type::GENERATED, false, false, false,
343 filename, c->name.lineno);
344 NAMES.Add(stub);
345
346 name = c->name.data;
347 name += ".Stub.Proxy";
348 Type* proxy = new Type(c->package ? c->package : "",
349 name, Type::GENERATED, false, false, false,
350 filename, c->name.lineno);
351 NAMES.Add(proxy);
352 }
353 else if (items->item_type == INTERFACE_TYPE_RPC) {
354 // for interfaces, also add the service base type, we don't
355 // bother checking these for duplicates, because the parser
356 // won't let us do it.
357 interface_type* c = (interface_type*)items;
358
359 string name = c->name.data;
360 name += ".ServiceBase";
361 Type* base = new Type(c->package ? c->package : "",
362 name, Type::GENERATED, false, false, false,
363 filename, c->name.lineno);
364 NAMES.Add(base);
365 }
366 } else {
367 if (old->Kind() == Type::BUILT_IN) {
368 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
369 filename, type->DeclLine(),
370 type->QualifiedName().c_str());
371 err = 1;
372 }
373 else if (type->Kind() != old->Kind()) {
374 const char* oldKind = kind_to_string(old->Kind());
375 const char* newKind = kind_to_string(type->Kind());
376
377 fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
378 filename, type->DeclLine(),
379 type->QualifiedName().c_str(), newKind);
380 fprintf(stderr, "%s:%d previously defined here as %s.\n",
381 old->DeclFile().c_str(), old->DeclLine(), oldKind);
382 err = 1;
383 }
384 }
385
386 items = items->next;
387 }
388 return err;
389}
390
391// ==========================================================
392static bool
393matches_keyword(const char* str)
394{
395 static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
396 "byte", "case", "catch", "char", "class", "const", "continue",
397 "default", "do", "double", "else", "enum", "extends", "final",
398 "finally", "float", "for", "goto", "if", "implements", "import",
399 "instanceof", "int", "interface", "long", "native", "new", "package",
400 "private", "protected", "public", "return", "short", "static",
401 "strictfp", "super", "switch", "synchronized", "this", "throw",
402 "throws", "transient", "try", "void", "volatile", "while",
403 "true", "false", "null",
404 NULL
405 };
406 const char** k = KEYWORDS;
407 while (*k) {
408 if (0 == strcmp(str, *k)) {
409 return true;
410 }
411 k++;
412 }
413 return false;
414}
415
416static int
417check_method(const char* filename, int kind, method_type* m)
418{
419 int err = 0;
420
421 // return type
422 Type* returnType = NAMES.Search(m->type.type.data);
423 if (returnType == NULL) {
424 fprintf(stderr, "%s:%d unknown return type %s\n", filename,
425 m->type.type.lineno, m->type.type.data);
426 err = 1;
427 return err;
428 }
429
430 if (returnType == EVENT_FAKE_TYPE) {
431 if (kind != INTERFACE_TYPE_RPC) {
432 fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
433 filename, m->type.type.lineno);
434 err = 1;
435 }
436 } else {
437 if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
438 : returnType->CanWriteToRpcData())) {
439 fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
440 m->type.type.lineno, m->type.type.data);
441 err = 1;
442 }
443 }
444
445 if (m->type.dimension > 0 && !returnType->CanBeArray()) {
446 fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
447 m->type.array_token.lineno, m->type.type.data,
448 m->type.array_token.data);
449 err = 1;
450 }
451
452 if (m->type.dimension > 1) {
453 fprintf(stderr, "%s:%d return type %s%s only one"
454 " dimensional arrays are supported\n", filename,
455 m->type.array_token.lineno, m->type.type.data,
456 m->type.array_token.data);
457 err = 1;
458 }
459
460 int index = 1;
461
462 arg_type* arg = m->args;
463 while (arg) {
464 Type* t = NAMES.Search(arg->type.type.data);
465
466 // check the arg type
467 if (t == NULL) {
468 fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
469 filename, m->type.type.lineno, arg->name.data, index,
470 arg->type.type.data);
471 err = 1;
472 goto next;
473 }
474
475 if (t == EVENT_FAKE_TYPE) {
476 fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
477 filename, m->type.type.lineno, arg->name.data, index,
478 arg->type.type.data);
479 err = 1;
480 goto next;
481 }
482
483 if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
484 fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
485 filename, m->type.type.lineno, index,
486 arg->type.type.data, arg->name.data);
487 err = 1;
488 }
489
490 if (returnType == EVENT_FAKE_TYPE
491 && convert_direction(arg->direction.data) != IN_PARAMETER) {
492 fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
493 filename, m->type.type.lineno, index,
494 arg->type.type.data, arg->name.data);
495 err = 1;
496 goto next;
497 }
498
499 if (arg->direction.data == NULL
500 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
501 fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
502 " parameter, so you must declare it as in,"
503 " out or inout.\n",
504 filename, m->type.type.lineno, index,
505 arg->type.type.data, arg->name.data);
506 err = 1;
507 }
508
509 if (convert_direction(arg->direction.data) != IN_PARAMETER
510 && !t->CanBeOutParameter()
511 && arg->type.dimension == 0) {
512 fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
513 " parameter.\n",
514 filename, m->type.type.lineno, index,
515 arg->direction.data, arg->type.type.data,
516 arg->name.data);
517 err = 1;
518 }
519
520 if (arg->type.dimension > 0 && !t->CanBeArray()) {
521 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
522 " array.\n", filename,
523 m->type.array_token.lineno, index, arg->direction.data,
524 arg->type.type.data, arg->type.array_token.data,
525 arg->name.data);
526 err = 1;
527 }
528
529 if (arg->type.dimension > 1) {
530 fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
531 " dimensional arrays are supported\n", filename,
532 m->type.array_token.lineno, index, arg->direction.data,
533 arg->type.type.data, arg->type.array_token.data,
534 arg->name.data);
535 err = 1;
536 }
537
538 // check that the name doesn't match a keyword
539 if (matches_keyword(arg->name.data)) {
540 fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
541 " Java or aidl keyword\n",
542 filename, m->name.lineno, index, arg->name.data);
543 err = 1;
544 }
545
546next:
547 index++;
548 arg = arg->next;
549 }
550
551 return err;
552}
553
554static int
555check_types(const char* filename, document_item_type* items)
556{
557 int err = 0;
558 while (items) {
559 // (nothing to check for USER_DATA_TYPE)
560 if (items->item_type == INTERFACE_TYPE_BINDER
561 || items->item_type == INTERFACE_TYPE_RPC) {
562 map<string,method_type*> methodNames;
563 interface_type* c = (interface_type*)items;
564
565 interface_item_type* member = c->interface_items;
566 while (member) {
567 if (member->item_type == METHOD_TYPE) {
568 method_type* m = (method_type*)member;
569
570 err |= check_method(filename, items->item_type, m);
571
572 // prevent duplicate methods
573 if (methodNames.find(m->name.data) == methodNames.end()) {
574 methodNames[m->name.data] = m;
575 } else {
576 fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
577 filename, m->name.lineno, m->name.data);
578 method_type* old = methodNames[m->name.data];
579 fprintf(stderr, "%s:%d previously defined here.\n",
580 filename, old->name.lineno);
581 err = 1;
582 }
583 }
584 member = member->next;
585 }
586 }
587
588 items = items->next;
589 }
590 return err;
591}
592
593// ==========================================================
594static int
595exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
596 bool* onlyParcelable)
597{
598 if (items == NULL) {
599 fprintf(stderr, "%s: file does not contain any interfaces\n",
600 filename);
601 return 1;
602 }
603
604 const document_item_type* next = items->next;
605 // Allow parcelables to skip the "one-only" rule.
606 if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
607 int lineno = -1;
608 if (next->item_type == INTERFACE_TYPE_BINDER) {
609 lineno = ((interface_type*)next)->interface_token.lineno;
610 }
611 else if (next->item_type == INTERFACE_TYPE_RPC) {
612 lineno = ((interface_type*)next)->interface_token.lineno;
613 }
614 fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
615 filename, lineno);
616 return 1;
617 }
618
619 if (items->item_type == USER_DATA_TYPE) {
620 *onlyParcelable = true;
621 if (options.failOnParcelable) {
622 fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
623 " parcelables or flattenables,\n", filename,
624 ((user_data_type*)items)->keyword_token.lineno);
625 fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
626 "may not go in the Makefile.\n", filename,
627 ((user_data_type*)items)->keyword_token.lineno);
628 return 1;
629 }
630 } else {
631 *onlyParcelable = false;
632 }
633
634 return 0;
635}
636
637// ==========================================================
638void
639generate_dep_file(const Options& options, const document_item_type* items)
640{
641 /* we open the file in binary mode to ensure that the same output is
642 * generated on all platforms !!
643 */
644 FILE* to = NULL;
645 if (options.autoDepFile) {
646 string fileName = options.outputFileName + ".d";
647 to = fopen(fileName.c_str(), "wb");
648 } else {
649 to = fopen(options.depFileName.c_str(), "wb");
650 }
651
652 if (to == NULL) {
653 return;
654 }
655
656 const char* slash = "\\";
657 import_info* import = g_imports;
658 if (import == NULL) {
659 slash = "";
660 }
661
662 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
663 fprintf(to, "%s: \\\n", options.outputFileName.c_str());
664 } else {
665 // parcelable: there's no output file.
666 fprintf(to, " : \\\n");
667 }
668 fprintf(to, " %s %s\n", options.inputFileName.c_str(), slash);
669
670 while (import) {
671 if (import->next == NULL) {
672 slash = "";
673 }
674 if (import->filename) {
675 fprintf(to, " %s %s\n", import->filename, slash);
676 }
677 import = import->next;
678 }
679
680 fprintf(to, "\n");
681
Ying Wang50fb02d2015-07-22 17:42:35 -0700682 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
683 // has been deleted, moved or renamed in incremental build.
684 fprintf(to, "%s :\n", options.inputFileName.c_str());
685
Adam Lesinski282e1812014-01-23 18:17:42 -0800686 // Output "<imported_file>: " so make won't fail if the imported file has
687 // been deleted, moved or renamed in incremental build.
688 import = g_imports;
689 while (import) {
690 if (import->filename) {
691 fprintf(to, "%s :\n", import->filename);
692 }
693 import = import->next;
694 }
695
696 fclose(to);
697}
698
699// ==========================================================
700static string
701generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
702{
703 string result;
704
705 // create the path to the destination folder based on the
706 // interface package name
707 result = options.outputBaseFolder;
708 result += OS_PATH_SEPARATOR;
709
710 string packageStr = package;
711 size_t len = packageStr.length();
712 for (size_t i=0; i<len; i++) {
713 if (packageStr[i] == '.') {
714 packageStr[i] = OS_PATH_SEPARATOR;
715 }
716 }
717
718 result += packageStr;
719
720 // add the filename by replacing the .aidl extension to .java
721 const char* p = strchr(name.data, '.');
722 len = p ? p-name.data : strlen(name.data);
723
724 result += OS_PATH_SEPARATOR;
725 result.append(name.data, len);
726 result += ".java";
727
728 return result;
729}
730
731// ==========================================================
732static string
733generate_outputFileName(const Options& options, const document_item_type* items)
734{
735 // items has already been checked to have only one interface.
736 if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
737 interface_type* type = (interface_type*)items;
738
739 return generate_outputFileName2(options, type->name, type->package);
740 } else if (items->item_type == USER_DATA_TYPE) {
741 user_data_type* type = (user_data_type*)items;
742 return generate_outputFileName2(options, type->name, type->package);
743 }
744
745 // I don't think we can come here, but safer than returning NULL.
746 string result;
747 return result;
748}
749
750
751
752// ==========================================================
753static void
754check_outputFilePath(const string& path) {
755 size_t len = path.length();
756 for (size_t i=0; i<len ; i++) {
757 if (path[i] == OS_PATH_SEPARATOR) {
758 string p = path.substr(0, i);
759 if (access(path.data(), F_OK) != 0) {
Elliott Hughese17788c2015-08-17 12:41:46 -0700760#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -0800761 _mkdir(p.data());
762#else
763 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
764#endif
765 }
766 }
767 }
768}
769
770
771// ==========================================================
772static int
773parse_preprocessed_file(const string& filename)
774{
775 int err;
776
777 FILE* f = fopen(filename.c_str(), "rb");
778 if (f == NULL) {
779 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
780 filename.c_str());
781 return 1;
782 }
783
784 int lineno = 1;
785 char line[1024];
786 char type[1024];
787 char fullname[1024];
788 while (fgets(line, sizeof(line), f)) {
789 // skip comments and empty lines
790 if (!line[0] || strncmp(line, "//", 2) == 0) {
791 continue;
792 }
793
794 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
795
796 char* packagename;
797 char* classname = rfind(fullname, '.');
798 if (classname != NULL) {
799 *classname = '\0';
800 classname++;
801 packagename = fullname;
802 } else {
803 classname = fullname;
804 packagename = NULL;
805 }
806
807 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
808 // type, packagename, classname);
809 document_item_type* doc;
810
811 if (0 == strcmp("parcelable", type)) {
812 user_data_type* parcl = (user_data_type*)malloc(
813 sizeof(user_data_type));
814 memset(parcl, 0, sizeof(user_data_type));
815 parcl->document_item.item_type = USER_DATA_TYPE;
816 parcl->keyword_token.lineno = lineno;
817 parcl->keyword_token.data = strdup(type);
818 parcl->package = packagename ? strdup(packagename) : NULL;
819 parcl->name.lineno = lineno;
820 parcl->name.data = strdup(classname);
821 parcl->semicolon_token.lineno = lineno;
822 parcl->semicolon_token.data = strdup(";");
823 parcl->flattening_methods = PARCELABLE_DATA;
824 doc = (document_item_type*)parcl;
825 }
826 else if (0 == strcmp("flattenable", type)) {
827 user_data_type* parcl = (user_data_type*)malloc(
828 sizeof(user_data_type));
829 memset(parcl, 0, sizeof(user_data_type));
830 parcl->document_item.item_type = USER_DATA_TYPE;
831 parcl->keyword_token.lineno = lineno;
832 parcl->keyword_token.data = strdup(type);
833 parcl->package = packagename ? strdup(packagename) : NULL;
834 parcl->name.lineno = lineno;
835 parcl->name.data = strdup(classname);
836 parcl->semicolon_token.lineno = lineno;
837 parcl->semicolon_token.data = strdup(";");
838 parcl->flattening_methods = RPC_DATA;
839 doc = (document_item_type*)parcl;
840 }
841 else if (0 == strcmp("interface", type)) {
842 interface_type* iface = (interface_type*)malloc(
843 sizeof(interface_type));
844 memset(iface, 0, sizeof(interface_type));
845 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
846 iface->interface_token.lineno = lineno;
847 iface->interface_token.data = strdup(type);
848 iface->package = packagename ? strdup(packagename) : NULL;
849 iface->name.lineno = lineno;
850 iface->name.data = strdup(classname);
851 iface->open_brace_token.lineno = lineno;
852 iface->open_brace_token.data = strdup("{");
853 iface->close_brace_token.lineno = lineno;
854 iface->close_brace_token.data = strdup("}");
855 doc = (document_item_type*)iface;
856 }
857 else {
858 fprintf(stderr, "%s:%d: bad type in line: %s\n",
859 filename.c_str(), lineno, line);
Elliott Hughesb30296b2013-10-29 15:25:52 -0700860 fclose(f);
Adam Lesinski282e1812014-01-23 18:17:42 -0800861 return 1;
862 }
863 err = gather_types(filename.c_str(), doc);
864 lineno++;
865 }
866
867 if (!feof(f)) {
868 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
869 filename.c_str(), lineno);
870 return 1;
871 }
872
873 fclose(f);
874 return 0;
875}
876
877static int
878check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
879{
880 // Check whether there are any methods with manually assigned id's and any that are not.
881 // Either all method id's must be manually assigned or all of them must not.
882 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
883 set<int> usedIds;
884 interface_item_type* item = first_item;
885 bool hasUnassignedIds = false;
886 bool hasAssignedIds = false;
887 while (item != NULL) {
888 if (item->item_type == METHOD_TYPE) {
889 method_type* method_item = (method_type*)item;
890 if (method_item->hasId) {
891 hasAssignedIds = true;
892 method_item->assigned_id = atoi(method_item->id.data);
893 // Ensure that the user set id is not duplicated.
894 if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
895 // We found a duplicate id, so throw an error.
896 fprintf(stderr,
897 "%s:%d Found duplicate method id (%d) for method: %s\n",
898 filename, method_item->id.lineno,
899 method_item->assigned_id, method_item->name.data);
900 return 1;
901 }
902 // Ensure that the user set id is within the appropriate limits
903 if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
904 method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
905 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
906 filename, method_item->id.lineno,
907 method_item->assigned_id, method_item->name.data);
908 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
909 MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
910 return 1;
911 }
912 usedIds.insert(method_item->assigned_id);
913 } else {
914 hasUnassignedIds = true;
915 }
916 if (hasAssignedIds && hasUnassignedIds) {
917 fprintf(stderr,
918 "%s: You must either assign id's to all methods or to none of them.\n",
919 filename);
920 return 1;
921 }
922 }
923 item = item->next;
924 }
925
926 // In the case that all methods have unassigned id's, set a unique id for them.
927 if (hasUnassignedIds) {
928 int newId = 0;
929 item = first_item;
930 while (item != NULL) {
931 if (item->item_type == METHOD_TYPE) {
932 method_type* method_item = (method_type*)item;
933 method_item->assigned_id = newId++;
934 }
935 item = item->next;
936 }
937 }
938
939 // success
940 return 0;
941}
942
943// ==========================================================
944static int
945compile_aidl(Options& options)
946{
947 int err = 0, N;
948
949 set_import_paths(options.importPaths);
950
951 register_base_types();
952
953 // import the preprocessed file
954 N = options.preprocessedFiles.size();
955 for (int i=0; i<N; i++) {
956 const string& s = options.preprocessedFiles[i];
957 err |= parse_preprocessed_file(s);
958 }
959 if (err != 0) {
960 return err;
961 }
962
963 // parse the main file
964 g_callbacks = &g_mainCallbacks;
965 err = parse_aidl(options.inputFileName.c_str());
966 document_item_type* mainDoc = g_document;
967 g_document = NULL;
968
969 // parse the imports
970 g_callbacks = &g_mainCallbacks;
971 import_info* import = g_imports;
972 while (import) {
973 if (NAMES.Find(import->neededClass) == NULL) {
974 import->filename = find_import_file(import->neededClass);
975 if (!import->filename) {
976 fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
977 import->from, import->statement.lineno,
978 import->neededClass);
979 err |= 1;
980 } else {
981 err |= parse_aidl(import->filename);
982 import->doc = g_document;
983 if (import->doc == NULL) {
984 err |= 1;
985 }
986 }
987 }
988 import = import->next;
989 }
990 // bail out now if parsing wasn't successful
991 if (err != 0 || mainDoc == NULL) {
992 //fprintf(stderr, "aidl: parsing failed, stopping.\n");
993 return 1;
994 }
995
996 // complain about ones that aren't in the right files
997 err |= check_filenames(options.inputFileName.c_str(), mainDoc);
998 import = g_imports;
999 while (import) {
1000 err |= check_filenames(import->filename, import->doc);
1001 import = import->next;
1002 }
1003
1004 // gather the types that have been declared
1005 err |= gather_types(options.inputFileName.c_str(), mainDoc);
1006 import = g_imports;
1007 while (import) {
1008 err |= gather_types(import->filename, import->doc);
1009 import = import->next;
1010 }
1011
1012#if 0
1013 printf("---- main doc ----\n");
1014 test_document(mainDoc);
1015
1016 import = g_imports;
1017 while (import) {
1018 printf("---- import doc ----\n");
1019 test_document(import->doc);
1020 import = import->next;
1021 }
1022 NAMES.Dump();
1023#endif
1024
1025 // check the referenced types in mainDoc to make sure we've imported them
1026 err |= check_types(options.inputFileName.c_str(), mainDoc);
1027
1028 // finally, there really only needs to be one thing in mainDoc, and it
1029 // needs to be an interface.
1030 bool onlyParcelable = false;
1031 err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
1032
1033 // If this includes an interface definition, then assign method ids and validate.
1034 if (!onlyParcelable) {
1035 err |= check_and_assign_method_ids(options.inputFileName.c_str(),
1036 ((interface_type*)mainDoc)->interface_items);
1037 }
1038
1039 // after this, there shouldn't be any more errors because of the
1040 // input.
1041 if (err != 0 || mainDoc == NULL) {
1042 return 1;
1043 }
1044
1045 // if needed, generate the outputFileName from the outputBaseFolder
1046 if (options.outputFileName.length() == 0 &&
1047 options.outputBaseFolder.length() > 0) {
1048 options.outputFileName = generate_outputFileName(options, mainDoc);
1049 }
1050
1051 // if we were asked to, generate a make dependency file
1052 // unless it's a parcelable *and* it's supposed to fail on parcelable
1053 if ((options.autoDepFile || options.depFileName != "") &&
1054 !(onlyParcelable && options.failOnParcelable)) {
1055 // make sure the folders of the output file all exists
1056 check_outputFilePath(options.outputFileName);
1057 generate_dep_file(options, mainDoc);
1058 }
1059
1060 // they didn't ask to fail on parcelables, so just exit quietly.
1061 if (onlyParcelable && !options.failOnParcelable) {
1062 return 0;
1063 }
1064
1065 // make sure the folders of the output file all exists
1066 check_outputFilePath(options.outputFileName);
1067
1068 err = generate_java(options.outputFileName, options.inputFileName.c_str(),
1069 (interface_type*)mainDoc);
1070
1071 return err;
1072}
1073
1074static int
1075preprocess_aidl(const Options& options)
1076{
1077 vector<string> lines;
1078 int err;
1079
1080 // read files
1081 int N = options.filesToPreprocess.size();
1082 for (int i=0; i<N; i++) {
1083 g_callbacks = &g_mainCallbacks;
1084 err = parse_aidl(options.filesToPreprocess[i].c_str());
1085 if (err != 0) {
1086 return err;
1087 }
1088 document_item_type* doc = g_document;
1089 string line;
1090 if (doc->item_type == USER_DATA_TYPE) {
1091 user_data_type* parcelable = (user_data_type*)doc;
1092 if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
1093 line = "parcelable ";
1094 }
1095 if ((parcelable->flattening_methods & RPC_DATA) != 0) {
1096 line = "flattenable ";
1097 }
1098 if (parcelable->package) {
1099 line += parcelable->package;
1100 line += '.';
1101 }
1102 line += parcelable->name.data;
1103 } else {
1104 line = "interface ";
1105 interface_type* iface = (interface_type*)doc;
1106 if (iface->package) {
1107 line += iface->package;
1108 line += '.';
1109 }
1110 line += iface->name.data;
1111 }
1112 line += ";\n";
1113 lines.push_back(line);
1114 }
1115
1116 // write preprocessed file
1117 int fd = open( options.outputFileName.c_str(),
1118 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
Elliott Hughese17788c2015-08-17 12:41:46 -07001119#ifdef _WIN32
Adam Lesinski282e1812014-01-23 18:17:42 -08001120 _S_IREAD|_S_IWRITE);
1121#else
1122 S_IRUSR|S_IWUSR|S_IRGRP);
1123#endif
1124 if (fd == -1) {
1125 fprintf(stderr, "aidl: could not open file for write: %s\n",
1126 options.outputFileName.c_str());
1127 return 1;
1128 }
1129
1130 N = lines.size();
1131 for (int i=0; i<N; i++) {
1132 const string& s = lines[i];
1133 int len = s.length();
1134 if (len != write(fd, s.c_str(), len)) {
1135 fprintf(stderr, "aidl: error writing to file %s\n",
1136 options.outputFileName.c_str());
1137 close(fd);
1138 unlink(options.outputFileName.c_str());
1139 return 1;
1140 }
1141 }
1142
1143 close(fd);
1144 return 0;
1145}
1146
1147// ==========================================================
1148int
1149main(int argc, const char **argv)
1150{
1151 Options options;
1152 int result = parse_options(argc, argv, &options);
1153 if (result) {
1154 return result;
1155 }
1156
1157 switch (options.task)
1158 {
1159 case COMPILE_AIDL:
1160 return compile_aidl(options);
1161 case PREPROCESS_AIDL:
1162 return preprocess_aidl(options);
1163 }
1164 fprintf(stderr, "aidl: internal error\n");
1165 return 1;
1166}