blob: 051ed60635cd4852d65fa55cf417fb8b31e15337 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andreas Huberc9410c72016-07-28 12:18:40 -070017#include "CompoundType.h"
18
19#include "Formatter.h"
20
Andreas Huber5a545442016-08-03 10:44:56 -070021#include <android-base/logging.h>
22
Andreas Huberc9410c72016-07-28 12:18:40 -070023namespace android {
24
Andreas Huber9ed827c2016-08-22 12:31:13 -070025CompoundType::CompoundType(Style style, const char *localName)
26 : Scope(localName),
27 mStyle(style),
Andreas Huberc9410c72016-07-28 12:18:40 -070028 mFields(NULL) {
29}
30
Andreas Huber0d0f9a22016-08-17 10:26:11 -070031bool CompoundType::setFields(
32 std::vector<CompoundField *> *fields, std::string *errorMsg) {
Andreas Huberc9410c72016-07-28 12:18:40 -070033 mFields = fields;
Andreas Huber5a545442016-08-03 10:44:56 -070034
35 for (const auto &field : *fields) {
36 const Type &type = field->type();
37
Andreas Huber295ad302016-08-16 11:35:00 -070038 if (type.isBinder()) {
Andreas Huber0d0f9a22016-08-17 10:26:11 -070039 *errorMsg =
40 "Structs/Unions must not contain references to interfaces.";
Andreas Huberb95ea8a2016-08-15 15:35:42 -070041
42 return false;
43 }
44
Andreas Huber5a545442016-08-03 10:44:56 -070045 if (mStyle == STYLE_UNION) {
46 if (type.needsEmbeddedReadWrite()) {
47 // Can't have those in a union.
48
Andreas Huber0d0f9a22016-08-17 10:26:11 -070049 *errorMsg =
50 "Unions must not contain any types that need fixup.";
Andreas Huber5a545442016-08-03 10:44:56 -070051
52 return false;
53 }
Andreas Huber5a545442016-08-03 10:44:56 -070054 }
55 }
56
57 return true;
Andreas Huberc9410c72016-07-28 12:18:40 -070058}
59
Andreas Huber881227d2016-08-02 14:20:21 -070060std::string CompoundType::getCppType(
Steven Moreland979e0992016-09-07 09:18:08 -070061 StorageMode mode,
62 std::string *extra,
63 bool specifyNamespaces) const {
64
Andreas Huber881227d2016-08-02 14:20:21 -070065 extra->clear();
Steven Moreland979e0992016-09-07 09:18:08 -070066 const std::string base =
67 specifyNamespaces ? fullName() : partialCppName();
Andreas Huber881227d2016-08-02 14:20:21 -070068
69 switch (mode) {
70 case StorageMode_Stack:
71 return base;
72
73 case StorageMode_Argument:
74 return "const " + base + "&";
75
76 case StorageMode_Result:
77 return "const " + base + "*";
78 }
79}
80
Andreas Huber85eabdb2016-08-25 11:24:49 -070081std::string CompoundType::getJavaType() const {
82 return fullJavaName();
83}
84
Andreas Huber881227d2016-08-02 14:20:21 -070085void CompoundType::emitReaderWriter(
86 Formatter &out,
87 const std::string &name,
88 const std::string &parcelObj,
89 bool parcelObjIsPointer,
90 bool isReader,
91 ErrorMode mode) const {
Iliyan Malchev549e2592016-08-10 08:59:12 -070092 const std::string parentName = "_hidl_" + name + "_parent";
Andreas Huber881227d2016-08-02 14:20:21 -070093
94 out << "size_t " << parentName << ";\n\n";
95
96 const std::string parcelObjDeref =
97 parcelObj + (parcelObjIsPointer ? "->" : ".");
98
99 if (isReader) {
100 out << name
101 << " = (const "
Andreas Huber0e00de42016-08-03 09:56:02 -0700102 << fullName()
Andreas Huber881227d2016-08-02 14:20:21 -0700103 << " *)"
104 << parcelObjDeref
105 << "readBuffer("
106 << "&"
107 << parentName
108 << ");\n";
109
110 out << "if ("
111 << name
112 << " == nullptr) {\n";
113
114 out.indent();
115
Iliyan Malchev549e2592016-08-10 08:59:12 -0700116 out << "_hidl_err = ::android::UNKNOWN_ERROR;\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700117 handleError2(out, mode);
118
119 out.unindent();
120 out << "}\n\n";
121 } else {
Iliyan Malchev549e2592016-08-10 08:59:12 -0700122 out << "_hidl_err = "
Andreas Huber881227d2016-08-02 14:20:21 -0700123 << parcelObjDeref
124 << "writeBuffer(&"
125 << name
126 << ", sizeof("
127 << name
128 << "), &"
129 << parentName
130 << ");\n";
131
132 handleError(out, mode);
133 }
134
135 if (mStyle != STYLE_STRUCT || !needsEmbeddedReadWrite()) {
136 return;
137 }
138
139 emitReaderWriterEmbedded(
140 out,
141 name,
142 isReader /* nameIsPointer */,
143 parcelObj,
144 parcelObjIsPointer,
145 isReader,
146 mode,
147 parentName,
148 "0 /* parentOffset */");
149}
150
151void CompoundType::emitReaderWriterEmbedded(
152 Formatter &out,
153 const std::string &name,
154 bool nameIsPointer,
155 const std::string &parcelObj,
156 bool parcelObjIsPointer,
157 bool isReader,
158 ErrorMode mode,
159 const std::string &parentName,
160 const std::string &offsetText) const {
161 emitReaderWriterEmbeddedForTypeName(
162 out,
163 name,
164 nameIsPointer,
165 parcelObj,
166 parcelObjIsPointer,
167 isReader,
168 mode,
169 parentName,
170 offsetText,
Andreas Huber0e00de42016-08-03 09:56:02 -0700171 fullName(),
Andreas Huber881227d2016-08-02 14:20:21 -0700172 "" /* childName */);
173}
174
Andreas Huber85eabdb2016-08-25 11:24:49 -0700175void CompoundType::emitJavaReaderWriter(
176 Formatter &out,
177 const std::string &parcelObj,
178 const std::string &argName,
179 bool isReader) const {
180 if (isReader) {
181 out << "new " << fullJavaName() << "();\n";
182 }
183
184 out << argName
185 << "."
186 << (isReader ? "readFromParcel" : "writeToParcel")
187 << "("
188 << parcelObj
189 << ");\n";
190}
191
192void CompoundType::emitJavaFieldInitializer(
193 Formatter &out, const std::string &fieldName) const {
194 out << "final "
195 << fullJavaName()
196 << " "
197 << fieldName
198 << " = new "
199 << fullJavaName()
200 << "();\n";
201}
202
203void CompoundType::emitJavaFieldReaderWriter(
204 Formatter &out,
205 const std::string &blobName,
206 const std::string &fieldName,
207 const std::string &offset,
208 bool isReader) const {
209 if (isReader) {
210 out << fieldName
211 << ".readEmbeddedFromParcel(parcel, "
212 << blobName
213 << ", "
214 << offset
215 << ");\n";
216
217 return;
218 }
219
220 out << fieldName
221 << ".writeEmbeddedToBlob("
222 << blobName
223 << ", "
224 << offset
225 << ");\n";
226}
227
Andreas Huber881227d2016-08-02 14:20:21 -0700228status_t CompoundType::emitTypeDeclarations(Formatter &out) const {
229 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
230 << " "
Andreas Huber0e00de42016-08-03 09:56:02 -0700231 << localName()
Andreas Huber881227d2016-08-02 14:20:21 -0700232 << " {\n";
233
234 out.indent();
235
236 Scope::emitTypeDeclarations(out);
237
238 for (const auto &field : *mFields) {
239 std::string extra;
240 out << field->type().getCppType(&extra)
241 << " "
242 << field->name()
243 << extra
244 << ";\n";
245 }
246
247 if (needsEmbeddedReadWrite()) {
248 out << "\n::android::status_t readEmbeddedFromParcel(\n";
249
250 out.indent();
251 out.indent();
252
Andreas Huber8a82ff72016-08-04 10:29:39 -0700253 out << "const ::android::hardware::Parcel &parcel,\n"
Andreas Huber881227d2016-08-02 14:20:21 -0700254 << "size_t parentHandle,\n"
255 << "size_t parentOffset);\n\n";
256
257 out.unindent();
258 out.unindent();
259
260 out << "::android::status_t writeEmbeddedToParcel(\n";
261
262 out.indent();
263 out.indent();
264
Andreas Huber8a82ff72016-08-04 10:29:39 -0700265 out << "::android::hardware::Parcel *parcel,\n"
Andreas Huber881227d2016-08-02 14:20:21 -0700266 << "size_t parentHandle,\n"
267 << "size_t parentOffset) const;\n";
268
269 out.unindent();
270 out.unindent();
271 }
272
273 out.unindent();
274 out << "};\n\n";
275
276 return OK;
277}
278
279status_t CompoundType::emitTypeDefinitions(
280 Formatter &out, const std::string prefix) const {
Andreas Huber0e00de42016-08-03 09:56:02 -0700281 status_t err = Scope::emitTypeDefinitions(out, prefix + "::" + localName());
Andreas Huber881227d2016-08-02 14:20:21 -0700282
283 if (err != OK) {
284 return err;
285 }
286
287 if (!needsEmbeddedReadWrite()) {
288 return OK;
289 }
290
291 emitStructReaderWriter(out, prefix, true /* isReader */);
292 emitStructReaderWriter(out, prefix, false /* isReader */);
293
294 return OK;
295}
296
Andreas Huber85eabdb2016-08-25 11:24:49 -0700297status_t CompoundType::emitJavaTypeDeclarations(
298 Formatter &out, bool atTopLevel) const {
299 out << "public final ";
300
301 if (!atTopLevel) {
302 out << "static ";
303 }
304
305 out << "class "
306 << localName()
307 << " {\n";
308
309 out.indent();
310
311 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
312
313 for (const auto &field : *mFields) {
314 const bool isScope = field->type().isScope(); // really isStruct...
315
316 out << "public ";
317
318 field->type().emitJavaFieldInitializer(out, field->name());
319 }
320
321 if (!mFields->empty()) {
322 out << "\n";
323 }
324
325 out << "public final void readFromParcel(HwParcel parcel) {\n";
326 out.indent();
327 out << "HwBlob blob = parcel.readBuffer();\n";
328 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
329 out.unindent();
330 out << "}\n\n";
331
332 out << "public final void readEmbeddedFromParcel(\n";
333 out.indent();
334 out.indent();
335 out << "HwParcel parcel, HwBlob _hidl_blob, long _hidl_offset) {\n";
336 out.unindent();
337
338 size_t offset = 0;
339 for (const auto &field : *mFields) {
340 size_t fieldAlign, fieldSize;
341 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
342
343 size_t pad = offset % fieldAlign;
344 if (pad > 0) {
345 offset += fieldAlign - pad;
346 }
347
348 field->type().emitJavaFieldReaderWriter(
349 out,
350 "_hidl_blob",
351 field->name(),
352 "_hidl_offset + " + std::to_string(offset),
353 true /* isReader */);
354
355 offset += fieldSize;
356 }
357
358 out.unindent();
359 out << "}\n\n";
360
361 out << "public final void writeToParcel(HwParcel parcel) {\n";
362 out.indent();
363
364 size_t structAlign, structSize;
365 getAlignmentAndSize(&structAlign, &structSize);
366
367 out << "HwBlob _hidl_blob = new HwBlob("
368 << structSize
369 << " /* size */);\n";
370
371 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
372 << "parcel.writeBuffer(_hidl_blob);\n";
373
374 out.unindent();
375 out << "}\n\n";
376
377 out << "public final void writeEmbeddedToBlob(\n";
378 out.indent();
379 out.indent();
380 out << "HwBlob _hidl_blob, long _hidl_offset) {\n";
381 out.unindent();
382
383 offset = 0;
384 for (const auto &field : *mFields) {
385 size_t fieldAlign, fieldSize;
386 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
387
388 size_t pad = offset % fieldAlign;
389 if (pad > 0) {
390 offset += fieldAlign - pad;
391 }
392
393 field->type().emitJavaFieldReaderWriter(
394 out,
395 "_hidl_blob",
396 field->name(),
397 "_hidl_offset + " + std::to_string(offset),
398 false /* isReader */);
399
400 offset += fieldSize;
401 }
402
403 out.unindent();
404 out << "}\n";
405
406 out.unindent();
407 out << "};\n\n";
408
409 return OK;
410}
411
Andreas Huber881227d2016-08-02 14:20:21 -0700412void CompoundType::emitStructReaderWriter(
413 Formatter &out, const std::string &prefix, bool isReader) const {
414 out << "::android::status_t "
415 << (prefix.empty() ? "" : (prefix + "::"))
Andreas Huber0e00de42016-08-03 09:56:02 -0700416 << localName()
Andreas Huber881227d2016-08-02 14:20:21 -0700417 << (isReader ? "::readEmbeddedFromParcel"
418 : "::writeEmbeddedToParcel")
419 << "(\n";
420
421 out.indent();
422 out.indent();
423
424 if (isReader) {
Andreas Huber8a82ff72016-08-04 10:29:39 -0700425 out << "const ::android::hardware::Parcel &parcel,\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700426 } else {
Andreas Huber8a82ff72016-08-04 10:29:39 -0700427 out << "::android::hardware::Parcel *parcel,\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700428 }
429
430 out << "size_t parentHandle,\n"
431 << "size_t parentOffset)";
432
433 if (!isReader) {
434 out << " const";
435 }
436
437 out << " {\n";
438
439 out.unindent();
440 out.unindent();
441 out.indent();
442
Iliyan Malchev549e2592016-08-10 08:59:12 -0700443 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700444
445 for (const auto &field : *mFields) {
446 if (!field->type().needsEmbeddedReadWrite()) {
447 continue;
448 }
449
450 field->type().emitReaderWriterEmbedded(
451 out,
452 field->name(),
453 false /* nameIsPointer */,
454 "parcel",
455 !isReader /* parcelObjIsPointer */,
456 isReader,
Andreas Huber737080b2016-08-02 15:38:04 -0700457 ErrorMode_Return,
Andreas Huber881227d2016-08-02 14:20:21 -0700458 "parentHandle",
Andreas Huber0e00de42016-08-03 09:56:02 -0700459 "parentOffset + offsetof("
460 + fullName()
461 + ", "
462 + field->name()
463 + ")");
Andreas Huber881227d2016-08-02 14:20:21 -0700464 }
465
466 out.unindent();
Iliyan Malchev549e2592016-08-10 08:59:12 -0700467 out << "_hidl_error:\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700468 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -0700469 out << "return _hidl_err;\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700470
471 out.unindent();
472 out << "}\n\n";
473}
474
475bool CompoundType::needsEmbeddedReadWrite() const {
476 if (mStyle != STYLE_STRUCT) {
477 return false;
478 }
479
480 for (const auto &field : *mFields) {
481 if (field->type().needsEmbeddedReadWrite()) {
482 return true;
483 }
484 }
485
486 return false;
487}
488
489bool CompoundType::resultNeedsDeref() const {
490 return true;
491}
492
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700493status_t CompoundType::emitVtsTypeDeclarations(Formatter &out) const {
494 out << "name: \"" << localName() << "\"\n";
495 switch (mStyle) {
496 case STYLE_STRUCT:
497 {
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700498 out << "type: TYPE_STRUCT\n";
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700499 break;
500 }
501 case STYLE_UNION:
502 {
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700503 out << "type: TYPE_UNION\n";
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700504 break;
505 }
506 default:
507 break;
508 }
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700509
510 // Emit declaration for each subtype.
511 for (const auto &type : getSubTypes()) {
512 switch (mStyle) {
513 case STYLE_STRUCT:
514 {
515 out << "struct_value: {\n";
516 break;
517 }
518 case STYLE_UNION:
519 {
520 out << "union_value: {\n";
521 break;
522 }
523 default:
524 break;
525 }
526 out.indent();
527 status_t status(type->emitVtsTypeDeclarations(out));
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700528 if (status != OK) {
529 return status;
530 }
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700531 out.unindent();
532 out << "}\n";
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700533 }
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700534
535 // Emit declaration for each field.
536 for (const auto &field : *mFields) {
537 switch (mStyle) {
538 case STYLE_STRUCT:
539 {
540 out << "struct_value: {\n";
541 break;
542 }
543 case STYLE_UNION:
544 {
545 out << "union_value: {\n";
546 break;
547 }
548 default:
549 break;
550 }
551 out.indent();
552 out << "name: \"" << field->name() << "\"\n";
553 status_t status = field->type().emitVtsAttributeType(out);
554 if (status != OK) {
555 return status;
556 }
557 out.unindent();
558 out << "}\n";
559 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700560
561 return OK;
562}
563
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700564status_t CompoundType::emitVtsAttributeType(Formatter &out) const {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700565 switch (mStyle) {
566 case STYLE_STRUCT:
567 {
568 out << "type: TYPE_STRUCT\n";
569 break;
570 }
571 case STYLE_UNION:
572 {
573 out << "type: TYPE_UNION\n";
574 break;
575 }
576 default:
577 break;
578 }
579 out << "predefined_type: \"" << localName() << "\"\n";
580 return OK;
581}
582
Andreas Huber70a59e12016-08-16 12:57:01 -0700583bool CompoundType::isJavaCompatible() const {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700584 if (mStyle != STYLE_STRUCT || !Scope::isJavaCompatible()) {
585 return false;
586 }
587
588 for (const auto &field : *mFields) {
589 if (!field->type().isJavaCompatible()) {
590 return false;
591 }
592 }
593
594 return true;
Andreas Huber85eabdb2016-08-25 11:24:49 -0700595}
596
597void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
598 *align = 1;
599
600 size_t offset = 0;
601 for (const auto &field : *mFields) {
602 // Each field is aligned according to its alignment requirement.
603 // The surrounding structure's alignment is the maximum of its
604 // fields' aligments.
605
606 size_t fieldAlign, fieldSize;
607 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
608
609 size_t pad = offset % fieldAlign;
610 if (pad > 0) {
611 offset += fieldAlign - pad;
612 }
613
614 offset += fieldSize;
615
616 if (fieldAlign > (*align)) {
617 *align = fieldAlign;
618 }
619 }
620
621 // Final padding to account for the structure's alignment.
622 size_t pad = offset % (*align);
623 if (pad > 0) {
624 offset += (*align) - pad;
625 }
626
627 *size = offset;
Andreas Huber70a59e12016-08-16 12:57:01 -0700628}
629
Andreas Huber31629bc2016-08-03 09:06:40 -0700630////////////////////////////////////////////////////////////////////////////////
631
632CompoundField::CompoundField(const char *name, Type *type)
633 : mName(name),
634 mType(type) {
635}
636
637std::string CompoundField::name() const {
638 return mName;
639}
640
641const Type &CompoundField::type() const {
642 return *mType;
643}
644
Andreas Huberc9410c72016-07-28 12:18:40 -0700645} // namespace android
646