blob: 46a931744726b6da675ddfe98f2b89de3dcc2670 [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;
Casey Dahlindff80e52015-09-29 13:57:06 -0700207 for (method_type* m = c->interface_items; m; m = m->next) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700208 if (!types->AddContainerType(m->type.type.data) ||
209 !types->IsValidReturnType(&m->type, filename)) {
210 err = 1; // return type is invalid
Adam Lesinskiffa16862014-01-23 18:17:42 -0800211 }
212
213 int index = 1;
Casey Dahlinbc7a50a2015-09-28 19:20:50 -0700214 for (const std::unique_ptr<AidlArgument>& arg : *m->args) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700215 if (!types->AddContainerType(arg->type.type.data) ||
Casey Dahlinbc7a50a2015-09-28 19:20:50 -0700216 !types->IsValidArg(*arg, index, filename)) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700217 err = 1;
218 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800219 }
220
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700221 // prevent duplicate methods
222 if (method_names.find(m->name.data) == method_names.end()) {
223 method_names[m->name.data] = m;
224 } else {
225 cerr << filename << ":" << m->name.lineno
226 << " attempt to redefine method " << m->name.data << "," << endl
227 << filename << ":" << m->name.lineno
228 << " previously defined here." << endl;
229 err = 1;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800230 }
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700231 }
232 return err;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800233}
234
Christopher Wileyf690be52015-09-14 15:19:10 -0700235void generate_dep_file(const JavaOptions& options,
236 const document_item_type* items,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700237 import_info* import_head) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800238 /* we open the file in binary mode to ensure that the same output is
239 * generated on all platforms !!
240 */
241 FILE* to = NULL;
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700242 if (options.auto_dep_file_) {
243 string fileName = options.output_file_name_ + ".d";
Adam Lesinskiffa16862014-01-23 18:17:42 -0800244 to = fopen(fileName.c_str(), "wb");
245 } else {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700246 to = fopen(options.dep_file_name_.c_str(), "wb");
Adam Lesinskiffa16862014-01-23 18:17:42 -0800247 }
248
249 if (to == NULL) {
250 return;
251 }
252
253 const char* slash = "\\";
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700254 import_info* import = import_head;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800255 if (import == NULL) {
256 slash = "";
257 }
258
Casey Dahlin88868fc2015-09-01 13:21:26 -0700259 if (items->item_type == INTERFACE_TYPE_BINDER) {
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700260 fprintf(to, "%s: \\\n", options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800261 } else {
262 // parcelable: there's no output file.
263 fprintf(to, " : \\\n");
264 }
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700265 fprintf(to, " %s %s\n", options.input_file_name_.c_str(), slash);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800266
267 while (import) {
268 if (import->next == NULL) {
269 slash = "";
270 }
271 if (import->filename) {
272 fprintf(to, " %s %s\n", import->filename, slash);
273 }
274 import = import->next;
275 }
276
277 fprintf(to, "\n");
278
Ying Wang0e4861a2015-07-22 17:42:35 -0700279 // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
280 // has been deleted, moved or renamed in incremental build.
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700281 fprintf(to, "%s :\n", options.input_file_name_.c_str());
Ying Wang0e4861a2015-07-22 17:42:35 -0700282
Adam Lesinskiffa16862014-01-23 18:17:42 -0800283 // Output "<imported_file>: " so make won't fail if the imported file has
284 // been deleted, moved or renamed in incremental build.
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700285 import = import_head;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800286 while (import) {
287 if (import->filename) {
288 fprintf(to, "%s :\n", import->filename);
289 }
290 import = import->next;
291 }
292
293 fclose(to);
294}
295
Christopher Wileyf690be52015-09-14 15:19:10 -0700296string generate_outputFileName2(const JavaOptions& options,
297 const buffer_type& name,
298 const char* package) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800299 string result;
300
301 // create the path to the destination folder based on the
302 // interface package name
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700303 result = options.output_base_folder_;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800304 result += OS_PATH_SEPARATOR;
305
306 string packageStr = package;
307 size_t len = packageStr.length();
308 for (size_t i=0; i<len; i++) {
309 if (packageStr[i] == '.') {
310 packageStr[i] = OS_PATH_SEPARATOR;
311 }
312 }
313
314 result += packageStr;
315
316 // add the filename by replacing the .aidl extension to .java
317 const char* p = strchr(name.data, '.');
318 len = p ? p-name.data : strlen(name.data);
319
320 result += OS_PATH_SEPARATOR;
321 result.append(name.data, len);
322 result += ".java";
323
324 return result;
325}
326
Christopher Wileyf690be52015-09-14 15:19:10 -0700327string generate_outputFileName(const JavaOptions& options,
328 const document_item_type* items) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800329 // items has already been checked to have only one interface.
Casey Dahlin88868fc2015-09-01 13:21:26 -0700330 if (items->item_type == INTERFACE_TYPE_BINDER) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800331 interface_type* type = (interface_type*)items;
332
333 return generate_outputFileName2(options, type->name, type->package);
334 } else if (items->item_type == USER_DATA_TYPE) {
335 user_data_type* type = (user_data_type*)items;
336 return generate_outputFileName2(options, type->name, type->package);
337 }
338
339 // I don't think we can come here, but safer than returning NULL.
340 string result;
341 return result;
342}
343
344
Christopher Wileyf690be52015-09-14 15:19:10 -0700345void check_outputFilePath(const string& path) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800346 size_t len = path.length();
347 for (size_t i=0; i<len ; i++) {
348 if (path[i] == OS_PATH_SEPARATOR) {
349 string p = path.substr(0, i);
350 if (access(path.data(), F_OK) != 0) {
Elliott Hughes549b6e22015-08-17 12:41:46 -0700351#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800352 _mkdir(p.data());
353#else
354 mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
355#endif
356 }
357 }
358 }
359}
360
361
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700362int parse_preprocessed_file(const string& filename, TypeNamespace* types) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800363 FILE* f = fopen(filename.c_str(), "rb");
364 if (f == NULL) {
365 fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
366 filename.c_str());
367 return 1;
368 }
369
370 int lineno = 1;
371 char line[1024];
372 char type[1024];
373 char fullname[1024];
374 while (fgets(line, sizeof(line), f)) {
375 // skip comments and empty lines
376 if (!line[0] || strncmp(line, "//", 2) == 0) {
377 continue;
378 }
379
380 sscanf(line, "%s %[^; \r\n\t];", type, fullname);
381
382 char* packagename;
383 char* classname = rfind(fullname, '.');
384 if (classname != NULL) {
385 *classname = '\0';
386 classname++;
387 packagename = fullname;
388 } else {
389 classname = fullname;
390 packagename = NULL;
391 }
392
393 //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
394 // type, packagename, classname);
395 document_item_type* doc;
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700396
Adam Lesinskiffa16862014-01-23 18:17:42 -0800397 if (0 == strcmp("parcelable", type)) {
Casey Dahlin030977a2015-09-29 11:29:35 -0700398 user_data_type* parcl = new user_data_type();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800399 memset(parcl, 0, sizeof(user_data_type));
400 parcl->document_item.item_type = USER_DATA_TYPE;
401 parcl->keyword_token.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700402 parcl->keyword_token.data = cpp_strdup(type);
403 parcl->package = packagename ? cpp_strdup(packagename) : NULL;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800404 parcl->name.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700405 parcl->name.data = cpp_strdup(classname);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800406 parcl->semicolon_token.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700407 parcl->semicolon_token.data = cpp_strdup(";");
Casey Dahlin88868fc2015-09-01 13:21:26 -0700408 parcl->parcelable = true;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800409 doc = (document_item_type*)parcl;
410 }
411 else if (0 == strcmp("interface", type)) {
Casey Dahlin030977a2015-09-29 11:29:35 -0700412 interface_type* iface = new interface_type();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800413 memset(iface, 0, sizeof(interface_type));
414 iface->document_item.item_type = INTERFACE_TYPE_BINDER;
415 iface->interface_token.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700416 iface->interface_token.data = cpp_strdup(type);
417 iface->package = packagename ? cpp_strdup(packagename) : NULL;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800418 iface->name.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700419 iface->name.data = cpp_strdup(classname);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800420 iface->open_brace_token.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700421 iface->open_brace_token.data = cpp_strdup("{");
Adam Lesinskiffa16862014-01-23 18:17:42 -0800422 iface->close_brace_token.lineno = lineno;
Casey Dahlin030977a2015-09-29 11:29:35 -0700423 iface->close_brace_token.data = cpp_strdup("}");
Adam Lesinskiffa16862014-01-23 18:17:42 -0800424 doc = (document_item_type*)iface;
425 }
426 else {
427 fprintf(stderr, "%s:%d: bad type in line: %s\n",
428 filename.c_str(), lineno, line);
Elliott Hughes5cd06072013-10-29 15:25:52 -0700429 fclose(f);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800430 return 1;
431 }
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700432 if (!gather_types(filename.c_str(), doc, types)) {
433 fprintf(stderr, "Failed to gather types for preprocessed aidl.\n");
434 fclose(f);
435 return 1;
436 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800437 lineno++;
438 }
439
440 if (!feof(f)) {
441 fprintf(stderr, "%s:%d: error reading file, line to long.\n",
442 filename.c_str(), lineno);
443 return 1;
444 }
445
446 fclose(f);
447 return 0;
448}
449
Christopher Wileyf690be52015-09-14 15:19:10 -0700450int check_and_assign_method_ids(const char * filename,
Casey Dahlindff80e52015-09-29 13:57:06 -0700451 method_type* first_item) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800452 // Check whether there are any methods with manually assigned id's and any that are not.
453 // Either all method id's must be manually assigned or all of them must not.
454 // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
455 set<int> usedIds;
Casey Dahlindff80e52015-09-29 13:57:06 -0700456 method_type* item = first_item;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800457 bool hasUnassignedIds = false;
458 bool hasAssignedIds = false;
459 while (item != NULL) {
Casey Dahlindff80e52015-09-29 13:57:06 -0700460 if (item->hasId) {
461 hasAssignedIds = true;
462 item->assigned_id = atoi(item->id.data);
463 // Ensure that the user set id is not duplicated.
464 if (usedIds.find(item->assigned_id) != usedIds.end()) {
465 // We found a duplicate id, so throw an error.
Adam Lesinskiffa16862014-01-23 18:17:42 -0800466 fprintf(stderr,
Casey Dahlindff80e52015-09-29 13:57:06 -0700467 "%s:%d Found duplicate method id (%d) for method: %s\n",
468 filename, item->id.lineno,
469 item->assigned_id, item->name.data);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800470 return 1;
471 }
Casey Dahlindff80e52015-09-29 13:57:06 -0700472 // Ensure that the user set id is within the appropriate limits
473 if (item->assigned_id < kMinUserSetMethodId ||
474 item->assigned_id > kMaxUserSetMethodId) {
475 fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
476 filename, item->id.lineno,
477 item->assigned_id, item->name.data);
478 fprintf(stderr, " Value for id must be between %d and %d inclusive.\n",
479 kMinUserSetMethodId, kMaxUserSetMethodId);
480 return 1;
481 }
482 usedIds.insert(item->assigned_id);
483 } else {
484 hasUnassignedIds = true;
485 }
486 if (hasAssignedIds && hasUnassignedIds) {
487 fprintf(stderr,
488 "%s: You must either assign id's to all methods or to none of them.\n",
489 filename);
490 return 1;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800491 }
492 item = item->next;
493 }
494
495 // In the case that all methods have unassigned id's, set a unique id for them.
496 if (hasUnassignedIds) {
497 int newId = 0;
498 item = first_item;
499 while (item != NULL) {
Casey Dahlindff80e52015-09-29 13:57:06 -0700500 item->assigned_id = newId++;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800501 item = item->next;
502 }
503 }
504
505 // success
506 return 0;
507}
508
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700509int load_and_validate_aidl(const std::vector<std::string> preprocessed_files,
510 const std::vector<std::string> import_paths,
511 const std::string& input_file_name,
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700512 TypeNamespace* types,
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700513 interface_type** returned_interface,
514 import_info** returned_imports) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700515 int err = 0;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800516
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700517 set_import_paths(import_paths);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800518
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700519 // import the preprocessed file
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700520 for (const string& s : preprocessed_files) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700521 err |= parse_preprocessed_file(s, types);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700522 }
523 if (err != 0) {
524 return err;
525 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800526
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700527 // parse the input file
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700528 Parser p{input_file_name};
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700529 if (!p.OpenFileFromDisk() || !p.RunParser()) {
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700530 return 1;
531 }
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700532 document_item_type* parsed_doc = p.GetDocument();
533 // We could in theory declare parcelables in the same file as the interface.
534 // In practice, those parcelables would have to have the same name as
535 // the interface, since this was originally written to support Java, with its
536 // packages and names that correspond to file system structure.
537 // Since we can't have two distinct classes with the same name and package,
538 // we can't actually declare parcelables in the same file.
539 if (parsed_doc == nullptr ||
540 parsed_doc->item_type != INTERFACE_TYPE_BINDER ||
541 parsed_doc->next != nullptr) {
542 cerr << "aidl expects exactly one interface per input file";
Christopher Wileya2f516d2015-09-24 10:12:31 -0700543 return 1;
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700544 }
545 interface_type* interface = (interface_type*)parsed_doc;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700546 err |= check_filename(input_file_name.c_str(),
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700547 interface->package, &interface->name);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800548
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700549 // parse the imports of the input file
550 for (import_info* import = p.GetImports(); import; import = import->next) {
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700551 if (types->HasType(import->neededClass)) {
552 // There are places in the Android tree where an import doesn't resolve,
553 // but we'll pick the type up through the preprocessed types.
554 // This seems like an error, but legacy support demands we support it...
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700555 continue;
556 }
557 import->filename = find_import_file(import->neededClass);
558 if (!import->filename) {
559 cerr << import->from << ":" << import->statement.lineno
560 << ": couldn't find import for class "
561 << import->neededClass << endl;
562 err |= 1;
563 continue;
564 }
565 Parser p{import->filename};
566 if (!p.OpenFileFromDisk() || !p.RunParser() || p.GetDocument() == nullptr) {
567 cerr << "error while parsing import for class "
568 << import->neededClass << endl;
569 err |= 1;
570 continue;
571 }
572 import->doc = p.GetDocument();
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700573 err |= check_filenames(import->filename, import->doc);
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700574 }
575 if (err != 0) {
576 return err;
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700577 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800578
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700579 // gather the types that have been declared
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700580 if (!gather_types(input_file_name.c_str(), parsed_doc, types)) {
581 err |= 1;
582 }
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700583 for (import_info* import = p.GetImports(); import; import = import->next) {
Christopher Wiley84c1eac2015-09-23 13:29:28 -0700584 if (!gather_types(import->filename, import->doc, types)) {
585 err |= 1;
586 }
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700587 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800588
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700589 // check the referenced types in parsed_doc to make sure we've imported them
Christopher Wileyfb4b22d2015-09-25 15:16:13 -0700590 err |= check_types(input_file_name, interface, types);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800591
Adam Lesinskiffa16862014-01-23 18:17:42 -0800592
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700593 // assign method ids and validate.
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700594 err |= check_and_assign_method_ids(input_file_name.c_str(),
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700595 interface->interface_items);
Adam Lesinskiffa16862014-01-23 18:17:42 -0800596
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700597 // after this, there shouldn't be any more errors because of the
598 // input.
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700599 if (err != 0) {
600 return err;
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700601 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800602
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700603 *returned_interface = interface;
604 *returned_imports = p.GetImports();
605 return 0;
606}
607
608} // namespace
609
610int compile_aidl_to_cpp(const CppOptions& options) {
611 interface_type* interface = nullptr;
612 import_info* imports = nullptr;
Christopher Wileydb154a52015-09-28 16:32:25 -0700613 unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700614 int err = load_and_validate_aidl(std::vector<std::string>{},
615 options.ImportPaths(),
616 options.InputFileName(),
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -0700617 types.get(),
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700618 &interface,
619 &imports);
620 if (err != 0) {
621 return err;
622 }
623
624 // TODO(wiley) b/23600457 generate a dependency file if requested with -b
625
Christopher Wileyf944e792015-09-29 10:00:46 -0700626 return (cpp::GenerateCpp(options, interface)) ? 0 : 1;
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700627}
628
629int compile_aidl_to_java(const JavaOptions& options) {
630 interface_type* interface = nullptr;
631 import_info* imports = nullptr;
Christopher Wileydb154a52015-09-28 16:32:25 -0700632 unique_ptr<java::JavaTypeNamespace> types(new java::JavaTypeNamespace());
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700633 int err = load_and_validate_aidl(options.preprocessed_files_,
634 options.import_paths_,
635 options.input_file_name_,
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -0700636 types.get(),
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700637 &interface,
638 &imports);
639 if (err != 0) {
640 return err;
641 }
642 document_item_type* parsed_doc = (document_item_type*)interface;
643
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700644 string output_file_name = options.output_file_name_;
645 // if needed, generate the output file name from the base folder
646 if (output_file_name.length() == 0 &&
647 options.output_base_folder_.length() > 0) {
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700648 output_file_name = generate_outputFileName(options, parsed_doc);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700649 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800650
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700651 // if we were asked to, generate a make dependency file
652 // unless it's a parcelable *and* it's supposed to fail on parcelable
Christopher Wileyc16e5e72015-09-16 10:49:40 -0700653 if (options.auto_dep_file_ || options.dep_file_name_ != "") {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800654 // make sure the folders of the output file all exists
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700655 check_outputFilePath(output_file_name);
Christopher Wileyeb1acc12015-09-16 11:25:13 -0700656 generate_dep_file(options, parsed_doc, imports);
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700657 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800658
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700659 // make sure the folders of the output file all exists
660 check_outputFilePath(output_file_name);
661
662 err = generate_java(output_file_name, options.input_file_name_.c_str(),
Christopher Wiley8b2d3ee2015-09-23 15:43:01 -0700663 interface, types.get());
Christopher Wiley3a9d1582015-09-16 12:42:14 -0700664
665 return err;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800666}
667
Christopher Wileyf690be52015-09-14 15:19:10 -0700668int preprocess_aidl(const JavaOptions& options) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800669 vector<string> lines;
Adam Lesinskiffa16862014-01-23 18:17:42 -0800670
671 // read files
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700672 int N = options.files_to_preprocess_.size();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800673 for (int i=0; i<N; i++) {
Casey Dahline2507492015-09-14 17:11:20 -0700674 Parser p{options.files_to_preprocess_[i]};
Casey Dahlin99801812015-09-15 18:19:25 -0700675 if (!p.OpenFileFromDisk())
Casey Dahline2507492015-09-14 17:11:20 -0700676 return 1;
Casey Dahlin99801812015-09-15 18:19:25 -0700677 if (!p.RunParser())
678 return 1;
Casey Dahline2507492015-09-14 17:11:20 -0700679 document_item_type* doc = p.GetDocument();
Adam Lesinskiffa16862014-01-23 18:17:42 -0800680 string line;
681 if (doc->item_type == USER_DATA_TYPE) {
682 user_data_type* parcelable = (user_data_type*)doc;
Casey Dahlin88868fc2015-09-01 13:21:26 -0700683 if (parcelable->parcelable) {
Adam Lesinskiffa16862014-01-23 18:17:42 -0800684 line = "parcelable ";
685 }
Adam Lesinskiffa16862014-01-23 18:17:42 -0800686 if (parcelable->package) {
687 line += parcelable->package;
688 line += '.';
689 }
690 line += parcelable->name.data;
691 } else {
692 line = "interface ";
693 interface_type* iface = (interface_type*)doc;
694 if (iface->package) {
695 line += iface->package;
696 line += '.';
697 }
698 line += iface->name.data;
699 }
700 line += ";\n";
701 lines.push_back(line);
702 }
703
704 // write preprocessed file
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700705 int fd = open( options.output_file_name_.c_str(),
Adam Lesinskiffa16862014-01-23 18:17:42 -0800706 O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
Elliott Hughes549b6e22015-08-17 12:41:46 -0700707#ifdef _WIN32
Adam Lesinskiffa16862014-01-23 18:17:42 -0800708 _S_IREAD|_S_IWRITE);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700709#else
Adam Lesinskiffa16862014-01-23 18:17:42 -0800710 S_IRUSR|S_IWUSR|S_IRGRP);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700711#endif
Adam Lesinskiffa16862014-01-23 18:17:42 -0800712 if (fd == -1) {
713 fprintf(stderr, "aidl: could not open file for write: %s\n",
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700714 options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800715 return 1;
716 }
717
718 N = lines.size();
719 for (int i=0; i<N; i++) {
720 const string& s = lines[i];
721 int len = s.length();
722 if (len != write(fd, s.c_str(), len)) {
723 fprintf(stderr, "aidl: error writing to file %s\n",
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700724 options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800725 close(fd);
Christopher Wiley8f8cc9b2015-09-14 13:47:40 -0700726 unlink(options.output_file_name_.c_str());
Adam Lesinskiffa16862014-01-23 18:17:42 -0800727 return 1;
728 }
729 }
730
731 close(fd);
732 return 0;
733}
Christopher Wileyfdeb0f42015-09-11 15:38:22 -0700734
735} // namespace android
736} // namespace aidl