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