• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) {}
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         return true;
49     }
50     if (elementType->isInterface()) {
51         return true;
52     }
53     if (elementType->isHandle()) {
54         return true;
55     }
56     if (elementType->isMemory()) {
57         return true;
58     }
59     if (elementType->isTemplatedType()) {
60         const Type* inner = static_cast<const TemplatedType*>(elementType)->getElementType();
61         return this->isCompatibleElementType(inner) && !inner->isInterface();
62     }
63     if (elementType->isArray()) {
64         const Type* inner = static_cast<const ArrayType*>(elementType)->getElementType();
65         return this->isCompatibleElementType(inner) && !inner->isInterface();
66     }
67     return false;
68 }
69 
isVector() const70 bool VectorType::isVector() const {
71     return true;
72 }
73 
isVectorOfBinders() const74 bool VectorType::isVectorOfBinders() const {
75     return mElementType->isBinder();
76 }
77 
deepCanCheckEquality(std::unordered_set<const Type * > * visited) const78 bool VectorType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
79     return mElementType->canCheckEquality(visited);
80 }
81 
getStrongReferences() const82 std::vector<const Reference<Type>*> VectorType::getStrongReferences() const {
83     return {};
84 }
85 
getCppType(StorageMode mode,bool specifyNamespaces) const86 std::string VectorType::getCppType(StorageMode mode,
87                                    bool specifyNamespaces) const {
88     const std::string base =
89           std::string(specifyNamespaces ? "::android::hardware::" : "")
90         + "hidl_vec<"
91         + mElementType->getCppStackType( specifyNamespaces)
92         + ">";
93 
94     switch (mode) {
95         case StorageMode_Stack:
96             return base;
97 
98         case StorageMode_Argument:
99             return "const " + base + "&";
100 
101         case StorageMode_Result:
102         {
103             if (isVectorOfBinders()) {
104                 return base;
105             }
106 
107             return "const " + base + "*";
108         }
109     }
110 }
111 
getJavaType(bool) const112 std::string VectorType::getJavaType(bool /* forInitializer */) const {
113 
114     std::string elementJavaType;
115     if (mElementType->isArray()) {
116         elementJavaType = mElementType->getJavaType();
117     } else {
118         elementJavaType = mElementType->getJavaWrapperType();
119     }
120 
121     return "java.util.ArrayList<"
122         + elementJavaType
123         + ">";
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 
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const356 void VectorType::emitResolveReferences(
357             Formatter &out,
358             const std::string &name,
359             bool nameIsPointer,
360             const std::string &parcelObj,
361             bool parcelObjIsPointer,
362             bool isReader,
363             ErrorMode mode) const {
364     emitResolveReferencesEmbeddedHelper(
365         out,
366         0, /* depth */
367         name,
368         name /* sanitizedName */,
369         nameIsPointer,
370         parcelObj,
371         parcelObjIsPointer,
372         isReader,
373         mode,
374         "_hidl_" + name + "_child",
375         "0 /* parentOffset */");
376 }
377 
emitResolveReferencesEmbedded(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 &,const std::string &) const378 void VectorType::emitResolveReferencesEmbedded(
379             Formatter &out,
380             size_t depth,
381             const std::string &name,
382             const std::string &sanitizedName,
383             bool nameIsPointer,
384             const std::string &parcelObj,
385             bool parcelObjIsPointer,
386             bool isReader,
387             ErrorMode mode,
388             const std::string & /* parentName */,
389             const std::string & /* offsetText */) const {
390     emitResolveReferencesEmbeddedHelper(
391         out, depth, name, sanitizedName, nameIsPointer, parcelObj,
392         parcelObjIsPointer, isReader, mode, "", "");
393 }
394 
useParentInEmitResolveReferencesEmbedded() const395 bool VectorType::useParentInEmitResolveReferencesEmbedded() const {
396     // parentName and offsetText is not used in emitResolveReferencesEmbedded
397     return false;
398 }
399 
emitResolveReferencesEmbeddedHelper(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 & childName,const std::string & childOffsetText) const400 void VectorType::emitResolveReferencesEmbeddedHelper(
401             Formatter &out,
402             size_t depth,
403             const std::string &name,
404             const std::string &sanitizedName,
405             bool nameIsPointer,
406             const std::string &parcelObj,
407             bool parcelObjIsPointer,
408             bool isReader,
409             ErrorMode mode,
410             const std::string &childName,
411             const std::string &childOffsetText) const {
412     CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
413 
414     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
415     const std::string nameDerefed = (nameIsPointer ? "*" : "") + name;
416     std::string elementType = mElementType->getCppStackType();
417 
418     std::string myChildName = childName, myChildOffset = childOffsetText;
419 
420     if(myChildName.empty() && myChildOffset.empty()) {
421         myChildName = "_hidl_" + sanitizedName + "_child";
422         myChildOffset = "0";
423 
424         out << "size_t " << myChildName << ";\n";
425         out << "_hidl_err = ::android::hardware::findInParcel("
426             << nameDerefed << ", "
427             << (parcelObjIsPointer ? "*" : "") << parcelObj << ", "
428             << "&" << myChildName
429             << ");\n";
430 
431         handleError(out, mode);
432     }
433 
434     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
435 
436     out << "for (size_t "
437         << iteratorName
438         << " = 0; "
439         << iteratorName
440         << " < "
441         << nameDeref
442         << "size(); ++"
443         << iteratorName
444         << ") {\n";
445 
446     out.indent();
447 
448     mElementType->emitResolveReferencesEmbedded(
449         out,
450         depth + 1,
451         (nameIsPointer ? "(*" + name + ")" : name) + "[" + iteratorName + "]",
452         sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
453         false /* nameIsPointer */,
454         parcelObj,
455         parcelObjIsPointer,
456         isReader,
457         mode,
458         myChildName,
459         myChildOffset + " + " +
460                 iteratorName + " * sizeof(" + elementType + ")");
461 
462     out.unindent();
463 
464     out << "}\n\n";
465 }
466 
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const467 void VectorType::emitJavaReaderWriter(
468         Formatter &out,
469         const std::string &parcelObj,
470         const std::string &argName,
471         bool isReader) const {
472     if (mElementType->isCompoundType()) {
473 
474         if (isReader) {
475             out << mElementType->getJavaType()
476                 << ".readVectorFromParcel("
477                 << parcelObj
478                 << ");\n";
479         } else {
480             out << mElementType->getJavaType()
481                 << ".writeVectorToParcel("
482                 << parcelObj
483                 << ", "
484                 << argName
485                 << ");\n";
486         }
487 
488         return;
489     }
490 
491     if (mElementType->isArray()) {
492         size_t align, size;
493         getAlignmentAndSize(&align, &size);
494         if (isReader) {
495             out << " new "
496                 << getJavaType(false /* forInitializer */)
497                 << "();\n";
498         }
499 
500         out << "{\n";
501         out.indent();
502 
503         out << "android.os.HwBlob _hidl_blob = ";
504 
505         if (isReader) {
506             out << parcelObj
507                 << ".readBuffer("
508                 << size
509                 << " /* size */);\n";
510         } else {
511 
512             out << "new android.os.HwBlob("
513                 << size
514                 << " /* size */);\n";
515         }
516 
517         emitJavaFieldReaderWriter(
518                 out,
519                 0 /* depth */,
520                 parcelObj,
521                 "_hidl_blob",
522                 argName,
523                 "0 /* offset */",
524                 isReader);
525 
526         if (!isReader) {
527             out << parcelObj << ".writeBuffer(_hidl_blob);\n";
528         };
529 
530         out.unindent();
531         out << "}\n";
532 
533         return;
534     }
535 
536     emitJavaReaderWriterWithSuffix(
537             out,
538             parcelObj,
539             argName,
540             isReader,
541             mElementType->getJavaSuffix() + "Vector",
542             "" /* extra */);
543 }
544 
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const545 void VectorType::emitJavaFieldInitializer(
546         Formatter &out, const std::string &fieldName) const {
547     std::string javaType = getJavaType(false /* forInitializer */);
548 
549     out << "final "
550         << javaType
551         << " "
552         << fieldName
553         << " = new "
554         << javaType
555         << "();\n";
556 }
557 
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const558 void VectorType::emitJavaFieldReaderWriter(
559         Formatter &out,
560         size_t depth,
561         const std::string &parcelName,
562         const std::string &blobName,
563         const std::string &fieldName,
564         const std::string &offset,
565         bool isReader) const {
566     VectorType::EmitJavaFieldReaderWriterForElementType(
567             out,
568             depth,
569             mElementType.get(),
570             parcelName,
571             blobName,
572             fieldName,
573             offset,
574             isReader);
575 }
576 
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)577 void VectorType::EmitJavaFieldReaderWriterForElementType(
578         Formatter &out,
579         size_t depth,
580         const Type *elementType,
581         const std::string &parcelName,
582         const std::string &blobName,
583         const std::string &fieldName,
584         const std::string &offset,
585         bool isReader) {
586     size_t elementAlign, elementSize;
587     elementType->getAlignmentAndSize(&elementAlign, &elementSize);
588 
589     if (isReader) {
590         out << "{\n";
591         out.indent();
592 
593         out << "int _hidl_vec_size = "
594             << blobName
595             << ".getInt32("
596             << offset
597             << " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
598 
599         out << "android.os.HwBlob childBlob = "
600             << parcelName
601             << ".readEmbeddedBuffer(\n";
602 
603         out.indent();
604         out.indent();
605 
606         out << "_hidl_vec_size * "
607             << elementSize << ","
608             << blobName
609             << ".handle(),\n"
610             << offset
611             << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */,"
612             << "true /* nullable */);\n\n";
613 
614         out.unindent();
615         out.unindent();
616 
617         out << fieldName << ".clear();\n";
618         std::string iteratorName = "_hidl_index_" + std::to_string(depth);
619 
620         out << "for (int "
621             << iteratorName
622             << " = 0; "
623             << iteratorName
624             << " < _hidl_vec_size; "
625             << "++"
626             << iteratorName
627             << ") {\n";
628 
629         out.indent();
630 
631         elementType->emitJavaFieldInitializer(out, "_hidl_vec_element");
632 
633         elementType->emitJavaFieldReaderWriter(
634                 out,
635                 depth + 1,
636                 parcelName,
637                 "childBlob",
638                 "_hidl_vec_element",
639                 iteratorName + " * " + std::to_string(elementSize),
640                 true /* isReader */);
641 
642         out << fieldName
643             << ".add(_hidl_vec_element);\n";
644 
645         out.unindent();
646 
647         out << "}\n";
648 
649         out.unindent();
650         out << "}\n";
651 
652         return;
653     }
654 
655     out << "{\n";
656     out.indent();
657 
658     out << "int _hidl_vec_size = "
659         << fieldName
660         << ".size();\n";
661 
662     out << blobName
663         << ".putInt32("
664         << offset
665         << " + 8 /* offsetof(hidl_vec<T>, mSize) */, _hidl_vec_size);\n";
666 
667     out << blobName
668         << ".putBool("
669         << offset
670         << " + 12 /* offsetof(hidl_vec<T>, mOwnsBuffer) */, false);\n";
671 
672     // XXX make HwBlob constructor take a long instead of an int?
673     out << "android.os.HwBlob childBlob = new android.os.HwBlob((int)(_hidl_vec_size * "
674         << elementSize
675         << "));\n";
676 
677     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
678 
679     out << "for (int "
680         << iteratorName
681         << " = 0; "
682         << iteratorName
683         << " < _hidl_vec_size; "
684         << "++"
685         << iteratorName
686         << ") {\n";
687 
688     out.indent();
689 
690     elementType->emitJavaFieldReaderWriter(
691             out,
692             depth + 1,
693             parcelName,
694             "childBlob",
695             fieldName + ".get(" + iteratorName + ")",
696             iteratorName + " * " + std::to_string(elementSize),
697             false /* isReader */);
698 
699     out.unindent();
700 
701     out << "}\n";
702 
703     out << blobName
704         << ".putBlob("
705         << offset
706         << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */, childBlob);\n";
707 
708     out.unindent();
709     out << "}\n";
710 }
711 
needsEmbeddedReadWrite() const712 bool VectorType::needsEmbeddedReadWrite() const {
713     return true;
714 }
715 
deepNeedsResolveReferences(std::unordered_set<const Type * > * visited) const716 bool VectorType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
717     if (mElementType->needsResolveReferences(visited)) {
718         return true;
719     }
720     return TemplatedType::deepNeedsResolveReferences(visited);
721 }
722 
resultNeedsDeref() const723 bool VectorType::resultNeedsDeref() const {
724     return !isVectorOfBinders();
725 }
726 
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const727 bool VectorType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
728     if (!mElementType->isJavaCompatible(visited)) {
729         return false;
730     }
731 
732     if (mElementType->isArray()) {
733         return static_cast<const ArrayType*>(mElementType.get())->countDimensions() == 1;
734     }
735 
736     if (mElementType->isVector()) {
737         return false;
738     }
739 
740     if (isVectorOfBinders()) {
741         return false;
742     }
743 
744     return TemplatedType::deepIsJavaCompatible(visited);
745 }
746 
deepContainsPointer(std::unordered_set<const Type * > * visited) const747 bool VectorType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
748     if (mElementType->containsPointer(visited)) {
749         return true;
750     }
751     return TemplatedType::deepContainsPointer(visited);
752 }
753 
754 // All hidl_vec<T> have the same size.
755 static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
756 
getAlignmentAndSizeStatic(size_t * align,size_t * size)757 void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
758     *align = 8;  // hidl_vec<T>
759     *size = assertion.size();
760 }
761 
getAlignmentAndSize(size_t * align,size_t * size) const762 void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
763     VectorType::getAlignmentAndSizeStatic(align, size);
764 }
765 
766 }  // namespace android
767 
768