1 /*
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
17 #include "VectorType.h"
18
19 #include "ArrayType.h"
20 #include "CompoundType.h"
21 #include "HidlTypeAssertion.h"
22
23 #include <hidl-util/Formatter.h>
24 #include <android-base/logging.h>
25
26 namespace android {
27
VectorType(Scope * parent)28 VectorType::VectorType(Scope* parent) : TemplatedType(parent, "vec") {}
29
templatedTypeName() const30 std::string VectorType::templatedTypeName() const {
31 return "vector";
32 }
33
isCompatibleElementType(const Type * elementType) const34 bool VectorType::isCompatibleElementType(const Type* elementType) const {
35 if (elementType->isScalar()) {
36 return true;
37 }
38 if (elementType->isString()) {
39 return true;
40 }
41 if (elementType->isEnum()) {
42 return true;
43 }
44 if (elementType->isBitField()) {
45 return true;
46 }
47 if (elementType->isCompoundType()) {
48 if (static_cast<const CompoundType*>(elementType)->containsInterface()) {
49 return false;
50 }
51 return true;
52 }
53 if (elementType->isInterface()) {
54 return true;
55 }
56 if (elementType->isHandle()) {
57 return true;
58 }
59 if (elementType->isMemory()) {
60 return true;
61 }
62 if (elementType->isTemplatedType()) {
63 const Type* inner = static_cast<const TemplatedType*>(elementType)->getElementType();
64 return this->isCompatibleElementType(inner) && !inner->isInterface();
65 }
66 if (elementType->isArray()) {
67 const Type* inner = static_cast<const ArrayType*>(elementType)->getElementType();
68 return this->isCompatibleElementType(inner) && !inner->isInterface();
69 }
70 return false;
71 }
72
isVector() const73 bool VectorType::isVector() const {
74 return true;
75 }
76
isVectorOfBinders() const77 bool VectorType::isVectorOfBinders() const {
78 return mElementType->isInterface();
79 }
80
deepCanCheckEquality(std::unordered_set<const Type * > * visited) const81 bool VectorType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
82 return mElementType->canCheckEquality(visited);
83 }
84
getStrongReferences() const85 std::vector<const Reference<Type>*> VectorType::getStrongReferences() const {
86 return {};
87 }
88
getCppType(StorageMode mode,bool specifyNamespaces) const89 std::string VectorType::getCppType(StorageMode mode,
90 bool specifyNamespaces) const {
91 const std::string base =
92 std::string(specifyNamespaces ? "::android::hardware::" : "")
93 + "hidl_vec<"
94 + mElementType->getCppStackType( specifyNamespaces)
95 + ">";
96
97 switch (mode) {
98 case StorageMode_Stack:
99 return base;
100
101 case StorageMode_Argument:
102 return "const " + base + "&";
103
104 case StorageMode_Result:
105 {
106 if (isVectorOfBinders()) {
107 return base;
108 }
109
110 return "const " + base + "*";
111 }
112 }
113 }
114
getJavaType(bool) const115 std::string VectorType::getJavaType(bool /* forInitializer */) const {
116 // this will break if the type is templated in Java, but there are no types
117 // like this currently
118 const std::string elementJavaType = mElementType->getJavaTypeClass();
119 return "java.util.ArrayList<" + elementJavaType + ">";
120 }
121
getJavaTypeClass() const122 std::string VectorType::getJavaTypeClass() const {
123 return "java.util.ArrayList";
124 }
125
getVtsType() const126 std::string VectorType::getVtsType() const {
127 return "TYPE_VECTOR";
128 }
129
getVtsValueName() const130 std::string VectorType::getVtsValueName() const {
131 return "vector_value";
132 }
133
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const134 void VectorType::emitReaderWriter(
135 Formatter &out,
136 const std::string &name,
137 const std::string &parcelObj,
138 bool parcelObjIsPointer,
139 bool isReader,
140 ErrorMode mode) const {
141 if (isVectorOfBinders()) {
142 emitReaderWriterForVectorOfBinders(
143 out, name, parcelObj, parcelObjIsPointer, isReader, mode);
144
145 return;
146 }
147
148 std::string baseType = mElementType->getCppStackType();
149
150 const std::string parentName = "_hidl_" + name + "_parent";
151
152 out << "size_t " << parentName << ";\n\n";
153
154 const std::string parcelObjDeref =
155 parcelObj + (parcelObjIsPointer ? "->" : ".");
156
157 if (isReader) {
158 out << "_hidl_err = "
159 << parcelObjDeref
160 << "readBuffer("
161 << "sizeof(*"
162 << name
163 << "), &"
164 << parentName
165 << ", "
166 << " reinterpret_cast<const void **>("
167 << "&" << name
168 << "));\n\n";
169
170 handleError(out, mode);
171 } else {
172 out << "_hidl_err = "
173 << parcelObjDeref
174 << "writeBuffer(&"
175 << name
176 << ", sizeof("
177 << name
178 << "), &"
179 << parentName
180 << ");\n";
181
182 handleError(out, mode);
183 }
184
185 emitReaderWriterEmbedded(
186 out,
187 0 /* depth */,
188 name,
189 name /* sanitizedName */ ,
190 isReader /* nameIsPointer */,
191 parcelObj,
192 parcelObjIsPointer,
193 isReader,
194 mode,
195 parentName,
196 "0 /* parentOffset */");
197 }
198
emitReaderWriterForVectorOfBinders(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const199 void VectorType::emitReaderWriterForVectorOfBinders(
200 Formatter &out,
201 const std::string &name,
202 const std::string &parcelObj,
203 bool parcelObjIsPointer,
204 bool isReader,
205 ErrorMode mode) const {
206 const std::string parcelObjDeref =
207 parcelObj + (parcelObjIsPointer ? "->" : ".");
208
209 if (isReader) {
210 out << "{\n";
211 out.indent();
212
213 const std::string sizeName = "_hidl_" + name + "_size";
214
215 out << "uint64_t "
216 << sizeName
217 << ";\n";
218
219 out << "_hidl_err = "
220 << parcelObjDeref
221 << "readUint64(&"
222 << sizeName
223 << ");\n";
224
225 handleError(out, mode);
226
227 out << name
228 << ".resize("
229 << sizeName
230 << ");\n\n"
231 << "for (size_t _hidl_index = 0; _hidl_index < "
232 << sizeName
233 << "; ++_hidl_index) {\n";
234
235 out.indent();
236
237 out << mElementType->getCppStackType(true /* specifyNamespaces */)
238 << " _hidl_base;\n";
239
240 mElementType->emitReaderWriter(
241 out,
242 "_hidl_base",
243 parcelObj,
244 parcelObjIsPointer,
245 isReader,
246 mode);
247
248 out << name
249 << "[_hidl_index] = _hidl_base;\n";
250
251 out.unindent();
252 out << "}\n";
253
254 out.unindent();
255 out << "}\n";
256 } else {
257 out << "_hidl_err = "
258 << parcelObjDeref
259 << "writeUint64("
260 << name
261 << ".size());\n";
262
263 handleError(out, mode);
264
265 out << "for (size_t _hidl_index = 0; _hidl_index < "
266 << name
267 << ".size(); ++_hidl_index) {\n";
268
269 out.indent();
270
271 mElementType->emitReaderWriter(
272 out,
273 name + "[_hidl_index]",
274 parcelObj,
275 parcelObjIsPointer,
276 isReader,
277 mode);
278
279 out.unindent();
280 out << "}\n";
281 }
282 }
283
emitReaderWriterEmbedded(Formatter & out,size_t depth,const std::string & name,const std::string & sanitizedName,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode,const std::string & parentName,const std::string & offsetText) const284 void VectorType::emitReaderWriterEmbedded(
285 Formatter &out,
286 size_t depth,
287 const std::string &name,
288 const std::string &sanitizedName,
289 bool nameIsPointer,
290 const std::string &parcelObj,
291 bool parcelObjIsPointer,
292 bool isReader,
293 ErrorMode mode,
294 const std::string &parentName,
295 const std::string &offsetText) const {
296 std::string baseType = getCppStackType();
297
298 const std::string childName = "_hidl_" + sanitizedName + "_child";
299 out << "size_t " << childName << ";\n\n";
300
301 emitReaderWriterEmbeddedForTypeName(
302 out,
303 name,
304 nameIsPointer,
305 parcelObj,
306 parcelObjIsPointer,
307 isReader,
308 mode,
309 parentName,
310 offsetText,
311 baseType,
312 childName,
313 "::android::hardware");
314
315 if (!mElementType->needsEmbeddedReadWrite()) {
316 return;
317 }
318
319 const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
320
321 baseType = mElementType->getCppStackType();
322
323 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
324
325 out << "for (size_t "
326 << iteratorName
327 << " = 0; "
328 << iteratorName
329 << " < "
330 << nameDeref
331 << "size(); ++"
332 << iteratorName
333 << ") {\n";
334
335 out.indent();
336
337 mElementType->emitReaderWriterEmbedded(
338 out,
339 depth + 1,
340 (nameIsPointer ? "(*" + name + ")" : name)
341 + "[" + iteratorName + "]",
342 sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
343 false /* nameIsPointer */,
344 parcelObj,
345 parcelObjIsPointer,
346 isReader,
347 mode,
348 childName,
349 iteratorName + " * sizeof(" + baseType + ")");
350
351 out.unindent();
352
353 out << "}\n\n";
354 }
355
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const356 void VectorType::emitJavaReaderWriter(
357 Formatter &out,
358 const std::string &parcelObj,
359 const std::string &argName,
360 bool isReader) const {
361 if (mElementType->isCompoundType()) {
362
363 if (isReader) {
364 out << mElementType->getJavaType()
365 << ".readVectorFromParcel("
366 << parcelObj
367 << ");\n";
368 } else {
369 out << mElementType->getJavaType()
370 << ".writeVectorToParcel("
371 << parcelObj
372 << ", "
373 << argName
374 << ");\n";
375 }
376
377 return;
378 }
379
380 if (mElementType->isArray()) {
381 size_t align, size;
382 getAlignmentAndSize(&align, &size);
383 if (isReader) {
384 out << " new "
385 << getJavaType(false /* forInitializer */)
386 << "();\n";
387 }
388
389 out << "{\n";
390 out.indent();
391
392 out << "android.os.HwBlob _hidl_blob = ";
393
394 if (isReader) {
395 out << parcelObj
396 << ".readBuffer("
397 << size
398 << " /* size */);\n";
399 } else {
400
401 out << "new android.os.HwBlob("
402 << size
403 << " /* size */);\n";
404 }
405
406 emitJavaFieldReaderWriter(
407 out,
408 0 /* depth */,
409 parcelObj,
410 "_hidl_blob",
411 argName,
412 "0 /* offset */",
413 isReader);
414
415 if (!isReader) {
416 out << parcelObj << ".writeBuffer(_hidl_blob);\n";
417 };
418
419 out.unindent();
420 out << "}\n";
421
422 return;
423 }
424
425 emitJavaReaderWriterWithSuffix(
426 out,
427 parcelObj,
428 argName,
429 isReader,
430 mElementType->getJavaSuffix() + "Vector",
431 "" /* extra */);
432 }
433
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const434 void VectorType::emitJavaFieldInitializer(
435 Formatter &out, const std::string &fieldName) const {
436 const std::string typeName = getJavaType(false /* forInitializer */);
437 const std::string fieldDeclaration = typeName + " " + fieldName;
438
439 emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
440 }
441
emitJavaFieldDefaultInitialValue(Formatter & out,const std::string & declaredFieldName) const442 void VectorType::emitJavaFieldDefaultInitialValue(
443 Formatter &out, const std::string &declaredFieldName) const {
444 out << declaredFieldName
445 << " = new "
446 << getJavaType(false /* forInitializer */)
447 << "();\n";
448 }
449
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const450 void VectorType::emitJavaFieldReaderWriter(
451 Formatter &out,
452 size_t depth,
453 const std::string &parcelName,
454 const std::string &blobName,
455 const std::string &fieldName,
456 const std::string &offset,
457 bool isReader) const {
458
459 const std::string fieldNameWithCast = isReader
460 ? "(" + getJavaTypeCast(fieldName) + ")"
461 : fieldName;
462
463 VectorType::EmitJavaFieldReaderWriterForElementType(
464 out,
465 depth,
466 mElementType.get(),
467 parcelName,
468 blobName,
469 fieldNameWithCast,
470 offset,
471 isReader);
472 }
473
EmitJavaFieldReaderWriterForElementType(Formatter & out,size_t depth,const Type * elementType,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader)474 void VectorType::EmitJavaFieldReaderWriterForElementType(
475 Formatter &out,
476 size_t depth,
477 const Type *elementType,
478 const std::string &parcelName,
479 const std::string &blobName,
480 const std::string &fieldName,
481 const std::string &offset,
482 bool isReader) {
483 size_t elementAlign, elementSize;
484 elementType->getAlignmentAndSize(&elementAlign, &elementSize);
485
486 if (isReader) {
487 out << "{\n";
488 out.indent();
489
490 out << "int _hidl_vec_size = "
491 << blobName
492 << ".getInt32("
493 << offset
494 << " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
495
496 out << "android.os.HwBlob childBlob = "
497 << parcelName
498 << ".readEmbeddedBuffer(\n";
499
500 out.indent();
501 out.indent();
502
503 out << "_hidl_vec_size * "
504 << elementSize << ","
505 << blobName
506 << ".handle(),\n"
507 << offset
508 << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */,"
509 << "true /* nullable */);\n\n";
510
511 out.unindent();
512 out.unindent();
513
514 out << fieldName << ".clear();\n";
515 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
516
517 out << "for (int "
518 << iteratorName
519 << " = 0; "
520 << iteratorName
521 << " < _hidl_vec_size; "
522 << "++"
523 << iteratorName
524 << ") {\n";
525
526 out.indent();
527
528 elementType->emitJavaFieldInitializer(out, "_hidl_vec_element");
529
530 elementType->emitJavaFieldReaderWriter(
531 out,
532 depth + 1,
533 parcelName,
534 "childBlob",
535 "_hidl_vec_element",
536 iteratorName + " * " + std::to_string(elementSize),
537 true /* isReader */);
538
539 out << fieldName
540 << ".add(_hidl_vec_element);\n";
541
542 out.unindent();
543
544 out << "}\n";
545
546 out.unindent();
547 out << "}\n";
548
549 return;
550 }
551
552 out << "{\n";
553 out.indent();
554
555 out << "int _hidl_vec_size = "
556 << fieldName
557 << ".size();\n";
558
559 out << blobName
560 << ".putInt32("
561 << offset
562 << " + 8 /* offsetof(hidl_vec<T>, mSize) */, _hidl_vec_size);\n";
563
564 out << blobName
565 << ".putBool("
566 << offset
567 << " + 12 /* offsetof(hidl_vec<T>, mOwnsBuffer) */, false);\n";
568
569 // XXX make HwBlob constructor take a long instead of an int?
570 out << "android.os.HwBlob childBlob = new android.os.HwBlob((int)(_hidl_vec_size * "
571 << elementSize
572 << "));\n";
573
574 std::string iteratorName = "_hidl_index_" + std::to_string(depth);
575
576 out << "for (int "
577 << iteratorName
578 << " = 0; "
579 << iteratorName
580 << " < _hidl_vec_size; "
581 << "++"
582 << iteratorName
583 << ") {\n";
584
585 out.indent();
586
587 elementType->emitJavaFieldReaderWriter(
588 out,
589 depth + 1,
590 parcelName,
591 "childBlob",
592 fieldName + ".get(" + iteratorName + ")",
593 iteratorName + " * " + std::to_string(elementSize),
594 false /* isReader */);
595
596 out.unindent();
597
598 out << "}\n";
599
600 out << blobName
601 << ".putBlob("
602 << offset
603 << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */, childBlob);\n";
604
605 out.unindent();
606 out << "}\n";
607 }
608
needsEmbeddedReadWrite() const609 bool VectorType::needsEmbeddedReadWrite() const {
610 return true;
611 }
612
resultNeedsDeref() const613 bool VectorType::resultNeedsDeref() const {
614 return !isVectorOfBinders();
615 }
616
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const617 bool VectorType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
618 if (!mElementType->isJavaCompatible(visited)) {
619 return false;
620 }
621
622 if (mElementType->isArray()) {
623 return static_cast<const ArrayType*>(mElementType.get())->countDimensions() == 1;
624 }
625
626 if (mElementType->isVector()) {
627 return false;
628 }
629
630 if (mElementType->isMemory()) {
631 return false;
632 }
633
634 if (isVectorOfBinders()) {
635 return false;
636 }
637
638 return TemplatedType::deepIsJavaCompatible(visited);
639 }
640
deepContainsPointer(std::unordered_set<const Type * > * visited) const641 bool VectorType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
642 if (mElementType->containsPointer(visited)) {
643 return true;
644 }
645 return TemplatedType::deepContainsPointer(visited);
646 }
647
648 // All hidl_vec<T> have the same size.
649 static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
650
getAlignmentAndSizeStatic(size_t * align,size_t * size)651 void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
652 *align = 8; // hidl_vec<T>
653 *size = assertion.size();
654 }
655
getAlignmentAndSize(size_t * align,size_t * size) const656 void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
657 VectorType::getAlignmentAndSizeStatic(align, size);
658 }
659
660 } // namespace android
661
662