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