blob: 74df0a40455917fc01484b738e74866d9424df28 [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(
61 StorageMode mode, std::string *extra) const {
62 extra->clear();
Andreas Huber0e00de42016-08-03 09:56:02 -070063 const std::string base = fullName();
Andreas Huber881227d2016-08-02 14:20:21 -070064
65 switch (mode) {
66 case StorageMode_Stack:
67 return base;
68
69 case StorageMode_Argument:
70 return "const " + base + "&";
71
72 case StorageMode_Result:
73 return "const " + base + "*";
74 }
75}
76
Andreas Huber85eabdb2016-08-25 11:24:49 -070077std::string CompoundType::getJavaType() const {
78 return fullJavaName();
79}
80
Andreas Huber881227d2016-08-02 14:20:21 -070081void CompoundType::emitReaderWriter(
82 Formatter &out,
83 const std::string &name,
84 const std::string &parcelObj,
85 bool parcelObjIsPointer,
86 bool isReader,
87 ErrorMode mode) const {
Iliyan Malchev549e2592016-08-10 08:59:12 -070088 const std::string parentName = "_hidl_" + name + "_parent";
Andreas Huber881227d2016-08-02 14:20:21 -070089
90 out << "size_t " << parentName << ";\n\n";
91
92 const std::string parcelObjDeref =
93 parcelObj + (parcelObjIsPointer ? "->" : ".");
94
95 if (isReader) {
96 out << name
97 << " = (const "
Andreas Huber0e00de42016-08-03 09:56:02 -070098 << fullName()
Andreas Huber881227d2016-08-02 14:20:21 -070099 << " *)"
100 << parcelObjDeref
101 << "readBuffer("
102 << "&"
103 << parentName
104 << ");\n";
105
106 out << "if ("
107 << name
108 << " == nullptr) {\n";
109
110 out.indent();
111
Iliyan Malchev549e2592016-08-10 08:59:12 -0700112 out << "_hidl_err = ::android::UNKNOWN_ERROR;\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700113 handleError2(out, mode);
114
115 out.unindent();
116 out << "}\n\n";
117 } else {
Iliyan Malchev549e2592016-08-10 08:59:12 -0700118 out << "_hidl_err = "
Andreas Huber881227d2016-08-02 14:20:21 -0700119 << parcelObjDeref
120 << "writeBuffer(&"
121 << name
122 << ", sizeof("
123 << name
124 << "), &"
125 << parentName
126 << ");\n";
127
128 handleError(out, mode);
129 }
130
131 if (mStyle != STYLE_STRUCT || !needsEmbeddedReadWrite()) {
132 return;
133 }
134
135 emitReaderWriterEmbedded(
136 out,
137 name,
138 isReader /* nameIsPointer */,
139 parcelObj,
140 parcelObjIsPointer,
141 isReader,
142 mode,
143 parentName,
144 "0 /* parentOffset */");
145}
146
147void CompoundType::emitReaderWriterEmbedded(
148 Formatter &out,
149 const std::string &name,
150 bool nameIsPointer,
151 const std::string &parcelObj,
152 bool parcelObjIsPointer,
153 bool isReader,
154 ErrorMode mode,
155 const std::string &parentName,
156 const std::string &offsetText) const {
157 emitReaderWriterEmbeddedForTypeName(
158 out,
159 name,
160 nameIsPointer,
161 parcelObj,
162 parcelObjIsPointer,
163 isReader,
164 mode,
165 parentName,
166 offsetText,
Andreas Huber0e00de42016-08-03 09:56:02 -0700167 fullName(),
Andreas Huber881227d2016-08-02 14:20:21 -0700168 "" /* childName */);
169}
170
Andreas Huber85eabdb2016-08-25 11:24:49 -0700171void CompoundType::emitJavaReaderWriter(
172 Formatter &out,
173 const std::string &parcelObj,
174 const std::string &argName,
175 bool isReader) const {
176 if (isReader) {
177 out << "new " << fullJavaName() << "();\n";
178 }
179
180 out << argName
181 << "."
182 << (isReader ? "readFromParcel" : "writeToParcel")
183 << "("
184 << parcelObj
185 << ");\n";
186}
187
188void CompoundType::emitJavaFieldInitializer(
189 Formatter &out, const std::string &fieldName) const {
190 out << "final "
191 << fullJavaName()
192 << " "
193 << fieldName
194 << " = new "
195 << fullJavaName()
196 << "();\n";
197}
198
199void CompoundType::emitJavaFieldReaderWriter(
200 Formatter &out,
201 const std::string &blobName,
202 const std::string &fieldName,
203 const std::string &offset,
204 bool isReader) const {
205 if (isReader) {
206 out << fieldName
207 << ".readEmbeddedFromParcel(parcel, "
208 << blobName
209 << ", "
210 << offset
211 << ");\n";
212
213 return;
214 }
215
216 out << fieldName
217 << ".writeEmbeddedToBlob("
218 << blobName
219 << ", "
220 << offset
221 << ");\n";
222}
223
Andreas Huber881227d2016-08-02 14:20:21 -0700224status_t CompoundType::emitTypeDeclarations(Formatter &out) const {
225 out << ((mStyle == STYLE_STRUCT) ? "struct" : "union")
226 << " "
Andreas Huber0e00de42016-08-03 09:56:02 -0700227 << localName()
Andreas Huber881227d2016-08-02 14:20:21 -0700228 << " {\n";
229
230 out.indent();
231
232 Scope::emitTypeDeclarations(out);
233
234 for (const auto &field : *mFields) {
235 std::string extra;
236 out << field->type().getCppType(&extra)
237 << " "
238 << field->name()
239 << extra
240 << ";\n";
241 }
242
243 if (needsEmbeddedReadWrite()) {
244 out << "\n::android::status_t readEmbeddedFromParcel(\n";
245
246 out.indent();
247 out.indent();
248
Andreas Huber8a82ff72016-08-04 10:29:39 -0700249 out << "const ::android::hardware::Parcel &parcel,\n"
Andreas Huber881227d2016-08-02 14:20:21 -0700250 << "size_t parentHandle,\n"
251 << "size_t parentOffset);\n\n";
252
253 out.unindent();
254 out.unindent();
255
256 out << "::android::status_t writeEmbeddedToParcel(\n";
257
258 out.indent();
259 out.indent();
260
Andreas Huber8a82ff72016-08-04 10:29:39 -0700261 out << "::android::hardware::Parcel *parcel,\n"
Andreas Huber881227d2016-08-02 14:20:21 -0700262 << "size_t parentHandle,\n"
263 << "size_t parentOffset) const;\n";
264
265 out.unindent();
266 out.unindent();
267 }
268
269 out.unindent();
270 out << "};\n\n";
271
272 return OK;
273}
274
275status_t CompoundType::emitTypeDefinitions(
276 Formatter &out, const std::string prefix) const {
Andreas Huber0e00de42016-08-03 09:56:02 -0700277 status_t err = Scope::emitTypeDefinitions(out, prefix + "::" + localName());
Andreas Huber881227d2016-08-02 14:20:21 -0700278
279 if (err != OK) {
280 return err;
281 }
282
283 if (!needsEmbeddedReadWrite()) {
284 return OK;
285 }
286
287 emitStructReaderWriter(out, prefix, true /* isReader */);
288 emitStructReaderWriter(out, prefix, false /* isReader */);
289
290 return OK;
291}
292
Andreas Huber85eabdb2016-08-25 11:24:49 -0700293status_t CompoundType::emitJavaTypeDeclarations(
294 Formatter &out, bool atTopLevel) const {
295 out << "public final ";
296
297 if (!atTopLevel) {
298 out << "static ";
299 }
300
301 out << "class "
302 << localName()
303 << " {\n";
304
305 out.indent();
306
307 Scope::emitJavaTypeDeclarations(out, false /* atTopLevel */);
308
309 for (const auto &field : *mFields) {
310 const bool isScope = field->type().isScope(); // really isStruct...
311
312 out << "public ";
313
314 field->type().emitJavaFieldInitializer(out, field->name());
315 }
316
317 if (!mFields->empty()) {
318 out << "\n";
319 }
320
321 out << "public final void readFromParcel(HwParcel parcel) {\n";
322 out.indent();
323 out << "HwBlob blob = parcel.readBuffer();\n";
324 out << "readEmbeddedFromParcel(parcel, blob, 0 /* parentOffset */);\n";
325 out.unindent();
326 out << "}\n\n";
327
328 out << "public final void readEmbeddedFromParcel(\n";
329 out.indent();
330 out.indent();
331 out << "HwParcel parcel, HwBlob _hidl_blob, long _hidl_offset) {\n";
332 out.unindent();
333
334 size_t offset = 0;
335 for (const auto &field : *mFields) {
336 size_t fieldAlign, fieldSize;
337 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
338
339 size_t pad = offset % fieldAlign;
340 if (pad > 0) {
341 offset += fieldAlign - pad;
342 }
343
344 field->type().emitJavaFieldReaderWriter(
345 out,
346 "_hidl_blob",
347 field->name(),
348 "_hidl_offset + " + std::to_string(offset),
349 true /* isReader */);
350
351 offset += fieldSize;
352 }
353
354 out.unindent();
355 out << "}\n\n";
356
357 out << "public final void writeToParcel(HwParcel parcel) {\n";
358 out.indent();
359
360 size_t structAlign, structSize;
361 getAlignmentAndSize(&structAlign, &structSize);
362
363 out << "HwBlob _hidl_blob = new HwBlob("
364 << structSize
365 << " /* size */);\n";
366
367 out << "writeEmbeddedToBlob(_hidl_blob, 0 /* parentOffset */);\n"
368 << "parcel.writeBuffer(_hidl_blob);\n";
369
370 out.unindent();
371 out << "}\n\n";
372
373 out << "public final void writeEmbeddedToBlob(\n";
374 out.indent();
375 out.indent();
376 out << "HwBlob _hidl_blob, long _hidl_offset) {\n";
377 out.unindent();
378
379 offset = 0;
380 for (const auto &field : *mFields) {
381 size_t fieldAlign, fieldSize;
382 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
383
384 size_t pad = offset % fieldAlign;
385 if (pad > 0) {
386 offset += fieldAlign - pad;
387 }
388
389 field->type().emitJavaFieldReaderWriter(
390 out,
391 "_hidl_blob",
392 field->name(),
393 "_hidl_offset + " + std::to_string(offset),
394 false /* isReader */);
395
396 offset += fieldSize;
397 }
398
399 out.unindent();
400 out << "}\n";
401
402 out.unindent();
403 out << "};\n\n";
404
405 return OK;
406}
407
Andreas Huber881227d2016-08-02 14:20:21 -0700408void CompoundType::emitStructReaderWriter(
409 Formatter &out, const std::string &prefix, bool isReader) const {
410 out << "::android::status_t "
411 << (prefix.empty() ? "" : (prefix + "::"))
Andreas Huber0e00de42016-08-03 09:56:02 -0700412 << localName()
Andreas Huber881227d2016-08-02 14:20:21 -0700413 << (isReader ? "::readEmbeddedFromParcel"
414 : "::writeEmbeddedToParcel")
415 << "(\n";
416
417 out.indent();
418 out.indent();
419
420 if (isReader) {
Andreas Huber8a82ff72016-08-04 10:29:39 -0700421 out << "const ::android::hardware::Parcel &parcel,\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700422 } else {
Andreas Huber8a82ff72016-08-04 10:29:39 -0700423 out << "::android::hardware::Parcel *parcel,\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700424 }
425
426 out << "size_t parentHandle,\n"
427 << "size_t parentOffset)";
428
429 if (!isReader) {
430 out << " const";
431 }
432
433 out << " {\n";
434
435 out.unindent();
436 out.unindent();
437 out.indent();
438
Iliyan Malchev549e2592016-08-10 08:59:12 -0700439 out << "::android::status_t _hidl_err = ::android::OK;\n\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700440
441 for (const auto &field : *mFields) {
442 if (!field->type().needsEmbeddedReadWrite()) {
443 continue;
444 }
445
446 field->type().emitReaderWriterEmbedded(
447 out,
448 field->name(),
449 false /* nameIsPointer */,
450 "parcel",
451 !isReader /* parcelObjIsPointer */,
452 isReader,
Andreas Huber737080b2016-08-02 15:38:04 -0700453 ErrorMode_Return,
Andreas Huber881227d2016-08-02 14:20:21 -0700454 "parentHandle",
Andreas Huber0e00de42016-08-03 09:56:02 -0700455 "parentOffset + offsetof("
456 + fullName()
457 + ", "
458 + field->name()
459 + ")");
Andreas Huber881227d2016-08-02 14:20:21 -0700460 }
461
462 out.unindent();
Iliyan Malchev549e2592016-08-10 08:59:12 -0700463 out << "_hidl_error:\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700464 out.indent();
Iliyan Malchev549e2592016-08-10 08:59:12 -0700465 out << "return _hidl_err;\n";
Andreas Huber881227d2016-08-02 14:20:21 -0700466
467 out.unindent();
468 out << "}\n\n";
469}
470
471bool CompoundType::needsEmbeddedReadWrite() const {
472 if (mStyle != STYLE_STRUCT) {
473 return false;
474 }
475
476 for (const auto &field : *mFields) {
477 if (field->type().needsEmbeddedReadWrite()) {
478 return true;
479 }
480 }
481
482 return false;
483}
484
485bool CompoundType::resultNeedsDeref() const {
486 return true;
487}
488
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700489status_t CompoundType::emitVtsTypeDeclarations(Formatter &out) const {
490 out << "name: \"" << localName() << "\"\n";
491 switch (mStyle) {
492 case STYLE_STRUCT:
493 {
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700494 out << "type: TYPE_STRUCT\n";
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700495 break;
496 }
497 case STYLE_UNION:
498 {
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700499 out << "type: TYPE_UNION\n";
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700500 break;
501 }
502 default:
503 break;
504 }
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700505
506 // Emit declaration for each subtype.
507 for (const auto &type : getSubTypes()) {
508 switch (mStyle) {
509 case STYLE_STRUCT:
510 {
511 out << "struct_value: {\n";
512 break;
513 }
514 case STYLE_UNION:
515 {
516 out << "union_value: {\n";
517 break;
518 }
519 default:
520 break;
521 }
522 out.indent();
523 status_t status(type->emitVtsTypeDeclarations(out));
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700524 if (status != OK) {
525 return status;
526 }
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700527 out.unindent();
528 out << "}\n";
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700529 }
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700530
531 // Emit declaration for each field.
532 for (const auto &field : *mFields) {
533 switch (mStyle) {
534 case STYLE_STRUCT:
535 {
536 out << "struct_value: {\n";
537 break;
538 }
539 case STYLE_UNION:
540 {
541 out << "union_value: {\n";
542 break;
543 }
544 default:
545 break;
546 }
547 out.indent();
548 out << "name: \"" << field->name() << "\"\n";
549 status_t status = field->type().emitVtsAttributeType(out);
550 if (status != OK) {
551 return status;
552 }
553 out.unindent();
554 out << "}\n";
555 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700556
557 return OK;
558}
559
Zhuoyao Zhang864c7712016-08-16 15:35:28 -0700560status_t CompoundType::emitVtsAttributeType(Formatter &out) const {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700561 switch (mStyle) {
562 case STYLE_STRUCT:
563 {
564 out << "type: TYPE_STRUCT\n";
565 break;
566 }
567 case STYLE_UNION:
568 {
569 out << "type: TYPE_UNION\n";
570 break;
571 }
572 default:
573 break;
574 }
575 out << "predefined_type: \"" << localName() << "\"\n";
576 return OK;
577}
578
Andreas Huber70a59e12016-08-16 12:57:01 -0700579bool CompoundType::isJavaCompatible() const {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700580 if (mStyle != STYLE_STRUCT || !Scope::isJavaCompatible()) {
581 return false;
582 }
583
584 for (const auto &field : *mFields) {
585 if (!field->type().isJavaCompatible()) {
586 return false;
587 }
588 }
589
590 return true;
Andreas Huber85eabdb2016-08-25 11:24:49 -0700591}
592
593void CompoundType::getAlignmentAndSize(size_t *align, size_t *size) const {
594 *align = 1;
595
596 size_t offset = 0;
597 for (const auto &field : *mFields) {
598 // Each field is aligned according to its alignment requirement.
599 // The surrounding structure's alignment is the maximum of its
600 // fields' aligments.
601
602 size_t fieldAlign, fieldSize;
603 field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
604
605 size_t pad = offset % fieldAlign;
606 if (pad > 0) {
607 offset += fieldAlign - pad;
608 }
609
610 offset += fieldSize;
611
612 if (fieldAlign > (*align)) {
613 *align = fieldAlign;
614 }
615 }
616
617 // Final padding to account for the structure's alignment.
618 size_t pad = offset % (*align);
619 if (pad > 0) {
620 offset += (*align) - pad;
621 }
622
623 *size = offset;
Andreas Huber70a59e12016-08-16 12:57:01 -0700624}
625
Andreas Huber31629bc2016-08-03 09:06:40 -0700626////////////////////////////////////////////////////////////////////////////////
627
628CompoundField::CompoundField(const char *name, Type *type)
629 : mName(name),
630 mType(type) {
631}
632
633std::string CompoundField::name() const {
634 return mName;
635}
636
637const Type &CompoundField::type() const {
638 return *mType;
639}
640
Andreas Huberc9410c72016-07-28 12:18:40 -0700641} // namespace android
642