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()28 VectorType::VectorType() {
29 }
30 
typeName() const31 std::string VectorType::typeName() const {
32     return "vector" + (mElementType == nullptr ? "" : (" of " + mElementType->typeName()));
33 }
34 
isCompatibleElementType(Type * elementType) const35 bool VectorType::isCompatibleElementType(Type *elementType) const {
36     if (elementType->isScalar()) {
37         return true;
38     }
39     if (elementType->isString()) {
40         return true;
41     }
42     if (elementType->isEnum()) {
43         return true;
44     }
45     if (elementType->isBitField()) {
46         return true;
47     }
48     if (elementType->isCompoundType()
49             && static_cast<CompoundType *>(elementType)->style() == CompoundType::STYLE_STRUCT) {
50         return true;
51     }
52     if (elementType->isInterface()) {
53         return true;
54     }
55     if (elementType->isHandle()) {
56         return true;
57     }
58     if (elementType->isMemory()) {
59         return true;
60     }
61     if (elementType->isTemplatedType()) {
62         Type *inner = static_cast<TemplatedType *>(elementType)->getElementType();
63         return this->isCompatibleElementType(inner) && !inner->isInterface();
64     }
65     if (elementType->isArray()) {
66         Type *inner = static_cast<ArrayType *>(elementType)->getElementType();
67         return this->isCompatibleElementType(inner) && !inner->isInterface();
68     }
69     return false;
70 }
71 
addNamedTypesToSet(std::set<const FQName> & set) const72 void VectorType::addNamedTypesToSet(std::set<const FQName> &set) const {
73     mElementType->addNamedTypesToSet(set);
74 }
75 
isVector() const76 bool VectorType::isVector() const {
77     return true;
78 }
79 
isVectorOfBinders() const80 bool VectorType::isVectorOfBinders() const {
81     return mElementType->isBinder();
82 }
83 
canCheckEquality() const84 bool VectorType::canCheckEquality() const {
85     return mElementType->canCheckEquality();
86 }
87 
getCppType(StorageMode mode,bool specifyNamespaces) const88 std::string VectorType::getCppType(StorageMode mode,
89                                    bool specifyNamespaces) const {
90     const std::string base =
91           std::string(specifyNamespaces ? "::android::hardware::" : "")
92         + "hidl_vec<"
93         + mElementType->getCppStackType( specifyNamespaces)
94         + ">";
95 
96     switch (mode) {
97         case StorageMode_Stack:
98             return base;
99 
100         case StorageMode_Argument:
101             return "const " + base + "&";
102 
103         case StorageMode_Result:
104         {
105             if (isVectorOfBinders()) {
106                 return base;
107             }
108 
109             return "const " + base + "*";
110         }
111     }
112 }
113 
getJavaType(bool) const114 std::string VectorType::getJavaType(bool /* forInitializer */) const {
115 
116     std::string elementJavaType;
117     if (mElementType->isArray()) {
118         elementJavaType = mElementType->getJavaType();
119     } else {
120         elementJavaType = mElementType->getJavaWrapperType();
121     }
122 
123     return "java.util.ArrayList<"
124         + elementJavaType
125         + ">";
126 }
127 
getVtsType() const128 std::string VectorType::getVtsType() const {
129     return "TYPE_VECTOR";
130 }
131 
getVtsValueName() const132 std::string VectorType::getVtsValueName() const {
133     return "vector_value";
134 }
135 
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const136 void VectorType::emitReaderWriter(
137         Formatter &out,
138         const std::string &name,
139         const std::string &parcelObj,
140         bool parcelObjIsPointer,
141         bool isReader,
142         ErrorMode mode) const {
143     if (isVectorOfBinders()) {
144         emitReaderWriterForVectorOfBinders(
145                 out, name, parcelObj, parcelObjIsPointer, isReader, mode);
146 
147         return;
148     }
149 
150     std::string baseType = mElementType->getCppStackType();
151 
152     const std::string parentName = "_hidl_" + name + "_parent";
153 
154     out << "size_t " << parentName << ";\n\n";
155 
156     const std::string parcelObjDeref =
157         parcelObj + (parcelObjIsPointer ? "->" : ".");
158 
159     if (isReader) {
160         out << "_hidl_err = "
161             << parcelObjDeref
162             << "readBuffer("
163             << "sizeof(*"
164             << name
165             << "), &"
166             << parentName
167             << ", "
168             << " reinterpret_cast<const void **>("
169             << "&" << name
170             << "));\n\n";
171 
172         handleError(out, mode);
173     } else {
174         out << "_hidl_err = "
175             << parcelObjDeref
176             << "writeBuffer(&"
177             << name
178             << ", sizeof("
179             << name
180             << "), &"
181             << parentName
182             << ");\n";
183 
184         handleError(out, mode);
185     }
186 
187     emitReaderWriterEmbedded(
188             out,
189             0 /* depth */,
190             name,
191             name /* sanitizedName */ ,
192             isReader /* nameIsPointer */,
193             parcelObj,
194             parcelObjIsPointer,
195             isReader,
196             mode,
197             parentName,
198             "0 /* parentOffset */");
199 }
200 
emitReaderWriterForVectorOfBinders(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const201 void VectorType::emitReaderWriterForVectorOfBinders(
202         Formatter &out,
203         const std::string &name,
204         const std::string &parcelObj,
205         bool parcelObjIsPointer,
206         bool isReader,
207         ErrorMode mode) const {
208     const std::string parcelObjDeref =
209         parcelObj + (parcelObjIsPointer ? "->" : ".");
210 
211     if (isReader) {
212         out << "{\n";
213         out.indent();
214 
215         const std::string sizeName = "_hidl_" + name + "_size";
216 
217         out << "uint64_t "
218             << sizeName
219             << ";\n";
220 
221         out << "_hidl_err = "
222             << parcelObjDeref
223             << "readUint64(&"
224             << sizeName
225             << ");\n";
226 
227         handleError(out, mode);
228 
229         out << name
230             << ".resize("
231             << sizeName
232             << ");\n\n"
233             << "for (size_t _hidl_index = 0; _hidl_index < "
234             << sizeName
235             << "; ++_hidl_index) {\n";
236 
237         out.indent();
238 
239         out << mElementType->getCppStackType(true /* specifyNamespaces */)
240             << " _hidl_base;\n";
241 
242         mElementType->emitReaderWriter(
243                 out,
244                 "_hidl_base",
245                 parcelObj,
246                 parcelObjIsPointer,
247                 isReader,
248                 mode);
249 
250         out << name
251             << "[_hidl_index] = _hidl_base;\n";
252 
253         out.unindent();
254         out << "}\n";
255 
256         out.unindent();
257         out << "}\n";
258     } else {
259         out << "_hidl_err = "
260             << parcelObjDeref
261             << "writeUint64("
262             << name
263             << ".size());\n";
264 
265         handleError(out, mode);
266 
267         out << "for (size_t _hidl_index = 0; _hidl_index < "
268             << name
269             << ".size(); ++_hidl_index) {\n";
270 
271         out.indent();
272 
273         mElementType->emitReaderWriter(
274                 out,
275                 name + "[_hidl_index]",
276                 parcelObj,
277                 parcelObjIsPointer,
278                 isReader,
279                 mode);
280 
281         out.unindent();
282         out << "}\n";
283     }
284 }
285 
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) const286 void VectorType::emitReaderWriterEmbedded(
287         Formatter &out,
288         size_t depth,
289         const std::string &name,
290         const std::string &sanitizedName,
291         bool nameIsPointer,
292         const std::string &parcelObj,
293         bool parcelObjIsPointer,
294         bool isReader,
295         ErrorMode mode,
296         const std::string &parentName,
297         const std::string &offsetText) const {
298     std::string baseType = getCppStackType();
299 
300     const std::string childName = "_hidl_" + sanitizedName + "_child";
301     out << "size_t " << childName << ";\n\n";
302 
303     emitReaderWriterEmbeddedForTypeName(
304             out,
305             name,
306             nameIsPointer,
307             parcelObj,
308             parcelObjIsPointer,
309             isReader,
310             mode,
311             parentName,
312             offsetText,
313             baseType,
314             childName,
315             "::android::hardware");
316 
317     if (!mElementType->needsEmbeddedReadWrite()) {
318         return;
319     }
320 
321     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
322 
323     baseType = mElementType->getCppStackType();
324 
325     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
326 
327     out << "for (size_t "
328         << iteratorName
329         << " = 0; "
330         << iteratorName
331         << " < "
332         << nameDeref
333         << "size(); ++"
334         << iteratorName
335         << ") {\n";
336 
337     out.indent();
338 
339     mElementType->emitReaderWriterEmbedded(
340             out,
341             depth + 1,
342             (nameIsPointer ? "(*" + name + ")" : name)
343                 + "[" + iteratorName + "]",
344             sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
345             false /* nameIsPointer */,
346             parcelObj,
347             parcelObjIsPointer,
348             isReader,
349             mode,
350             childName,
351             iteratorName + " * sizeof(" + baseType + ")");
352 
353     out.unindent();
354 
355     out << "}\n\n";
356 }
357 
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const358 void VectorType::emitResolveReferences(
359             Formatter &out,
360             const std::string &name,
361             bool nameIsPointer,
362             const std::string &parcelObj,
363             bool parcelObjIsPointer,
364             bool isReader,
365             ErrorMode mode) const {
366     emitResolveReferencesEmbeddedHelper(
367         out,
368         0, /* depth */
369         name,
370         name /* sanitizedName */,
371         nameIsPointer,
372         parcelObj,
373         parcelObjIsPointer,
374         isReader,
375         mode,
376         "_hidl_" + name + "_child",
377         "0 /* parentOffset */");
378 }
379 
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 &) const380 void VectorType::emitResolveReferencesEmbedded(
381             Formatter &out,
382             size_t depth,
383             const std::string &name,
384             const std::string &sanitizedName,
385             bool nameIsPointer,
386             const std::string &parcelObj,
387             bool parcelObjIsPointer,
388             bool isReader,
389             ErrorMode mode,
390             const std::string & /* parentName */,
391             const std::string & /* offsetText */) const {
392     emitResolveReferencesEmbeddedHelper(
393         out, depth, name, sanitizedName, nameIsPointer, parcelObj,
394         parcelObjIsPointer, isReader, mode, "", "");
395 }
396 
useParentInEmitResolveReferencesEmbedded() const397 bool VectorType::useParentInEmitResolveReferencesEmbedded() const {
398     // parentName and offsetText is not used in emitResolveReferencesEmbedded
399     return false;
400 }
401 
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) const402 void VectorType::emitResolveReferencesEmbeddedHelper(
403             Formatter &out,
404             size_t depth,
405             const std::string &name,
406             const std::string &sanitizedName,
407             bool nameIsPointer,
408             const std::string &parcelObj,
409             bool parcelObjIsPointer,
410             bool isReader,
411             ErrorMode mode,
412             const std::string &childName,
413             const std::string &childOffsetText) const {
414     CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
415 
416     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
417     const std::string nameDerefed = (nameIsPointer ? "*" : "") + name;
418     std::string elementType = mElementType->getCppStackType();
419 
420     std::string myChildName = childName, myChildOffset = childOffsetText;
421 
422     if(myChildName.empty() && myChildOffset.empty()) {
423         myChildName = "_hidl_" + sanitizedName + "_child";
424         myChildOffset = "0";
425 
426         out << "size_t " << myChildName << ";\n";
427         out << "_hidl_err = ::android::hardware::findInParcel("
428             << nameDerefed << ", "
429             << (parcelObjIsPointer ? "*" : "") << parcelObj << ", "
430             << "&" << myChildName
431             << ");\n";
432 
433         handleError(out, mode);
434     }
435 
436     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
437 
438     out << "for (size_t "
439         << iteratorName
440         << " = 0; "
441         << iteratorName
442         << " < "
443         << nameDeref
444         << "size(); ++"
445         << iteratorName
446         << ") {\n";
447 
448     out.indent();
449 
450     mElementType->emitResolveReferencesEmbedded(
451         out,
452         depth + 1,
453         (nameIsPointer ? "(*" + name + ")" : name) + "[" + iteratorName + "]",
454         sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
455         false /* nameIsPointer */,
456         parcelObj,
457         parcelObjIsPointer,
458         isReader,
459         mode,
460         myChildName,
461         myChildOffset + " + " +
462                 iteratorName + " * sizeof(" + elementType + ")");
463 
464     out.unindent();
465 
466     out << "}\n\n";
467 }
468 
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const469 void VectorType::emitJavaReaderWriter(
470         Formatter &out,
471         const std::string &parcelObj,
472         const std::string &argName,
473         bool isReader) const {
474     if (mElementType->isCompoundType()) {
475 
476         if (isReader) {
477             out << mElementType->getJavaType()
478                 << ".readVectorFromParcel("
479                 << parcelObj
480                 << ");\n";
481         } else {
482             out << mElementType->getJavaType()
483                 << ".writeVectorToParcel("
484                 << parcelObj
485                 << ", "
486                 << argName
487                 << ");\n";
488         }
489 
490         return;
491     }
492 
493     if (mElementType->isArray()) {
494         size_t align, size;
495         getAlignmentAndSize(&align, &size);
496         if (isReader) {
497             out << " new "
498                 << getJavaType(false /* forInitializer */)
499                 << "();\n";
500         }
501 
502         out << "{\n";
503         out.indent();
504 
505         out << "android.os.HwBlob _hidl_blob = ";
506 
507         if (isReader) {
508             out << parcelObj
509                 << ".readBuffer("
510                 << size
511                 << " /* size */);\n";
512         } else {
513 
514             out << "new android.os.HwBlob("
515                 << size
516                 << " /* size */);\n";
517         }
518 
519         emitJavaFieldReaderWriter(
520                 out,
521                 0 /* depth */,
522                 parcelObj,
523                 "_hidl_blob",
524                 argName,
525                 "0 /* offset */",
526                 isReader);
527 
528         if (!isReader) {
529             out << parcelObj << ".writeBuffer(_hidl_blob);\n";
530         };
531 
532         out.unindent();
533         out << "}\n";
534 
535         return;
536     }
537 
538     emitJavaReaderWriterWithSuffix(
539             out,
540             parcelObj,
541             argName,
542             isReader,
543             mElementType->getJavaSuffix() + "Vector",
544             "" /* extra */);
545 }
546 
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const547 void VectorType::emitJavaFieldInitializer(
548         Formatter &out, const std::string &fieldName) const {
549     std::string javaType = getJavaType(false /* forInitializer */);
550 
551     out << "final "
552         << javaType
553         << " "
554         << fieldName
555         << " = new "
556         << javaType
557         << "();\n";
558 }
559 
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const560 void VectorType::emitJavaFieldReaderWriter(
561         Formatter &out,
562         size_t depth,
563         const std::string &parcelName,
564         const std::string &blobName,
565         const std::string &fieldName,
566         const std::string &offset,
567         bool isReader) const {
568     VectorType::EmitJavaFieldReaderWriterForElementType(
569             out,
570             depth,
571             mElementType,
572             parcelName,
573             blobName,
574             fieldName,
575             offset,
576             isReader);
577 }
578 
579 // static
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)580 void VectorType::EmitJavaFieldReaderWriterForElementType(
581         Formatter &out,
582         size_t depth,
583         const Type *elementType,
584         const std::string &parcelName,
585         const std::string &blobName,
586         const std::string &fieldName,
587         const std::string &offset,
588         bool isReader) {
589     size_t elementAlign, elementSize;
590     elementType->getAlignmentAndSize(&elementAlign, &elementSize);
591 
592     if (isReader) {
593         out << "{\n";
594         out.indent();
595 
596         out << "int _hidl_vec_size = "
597             << blobName
598             << ".getInt32("
599             << offset
600             << " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
601 
602         out << "android.os.HwBlob childBlob = "
603             << parcelName
604             << ".readEmbeddedBuffer(\n";
605 
606         out.indent();
607         out.indent();
608 
609         out << "_hidl_vec_size * "
610             << elementSize << ","
611             << blobName
612             << ".handle(),\n"
613             << offset
614             << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */,"
615             << "true /* nullable */);\n\n";
616 
617         out.unindent();
618         out.unindent();
619 
620         out << fieldName << ".clear();\n";
621         std::string iteratorName = "_hidl_index_" + std::to_string(depth);
622 
623         out << "for (int "
624             << iteratorName
625             << " = 0; "
626             << iteratorName
627             << " < _hidl_vec_size; "
628             << "++"
629             << iteratorName
630             << ") {\n";
631 
632         out.indent();
633 
634         elementType->emitJavaFieldInitializer(out, "_hidl_vec_element");
635 
636         elementType->emitJavaFieldReaderWriter(
637                 out,
638                 depth + 1,
639                 parcelName,
640                 "childBlob",
641                 "_hidl_vec_element",
642                 iteratorName + " * " + std::to_string(elementSize),
643                 true /* isReader */);
644 
645         out << fieldName
646             << ".add(_hidl_vec_element);\n";
647 
648         out.unindent();
649 
650         out << "}\n";
651 
652         out.unindent();
653         out << "}\n";
654 
655         return;
656     }
657 
658     out << "{\n";
659     out.indent();
660 
661     out << "int _hidl_vec_size = "
662         << fieldName
663         << ".size();\n";
664 
665     out << blobName
666         << ".putInt32("
667         << offset
668         << " + 8 /* offsetof(hidl_vec<T>, mSize) */, _hidl_vec_size);\n";
669 
670     out << blobName
671         << ".putBool("
672         << offset
673         << " + 12 /* offsetof(hidl_vec<T>, mOwnsBuffer) */, false);\n";
674 
675     // XXX make HwBlob constructor take a long instead of an int?
676     out << "android.os.HwBlob childBlob = new android.os.HwBlob((int)(_hidl_vec_size * "
677         << elementSize
678         << "));\n";
679 
680     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
681 
682     out << "for (int "
683         << iteratorName
684         << " = 0; "
685         << iteratorName
686         << " < _hidl_vec_size; "
687         << "++"
688         << iteratorName
689         << ") {\n";
690 
691     out.indent();
692 
693     elementType->emitJavaFieldReaderWriter(
694             out,
695             depth + 1,
696             parcelName,
697             "childBlob",
698             fieldName + ".get(" + iteratorName + ")",
699             iteratorName + " * " + std::to_string(elementSize),
700             false /* isReader */);
701 
702     out.unindent();
703 
704     out << "}\n";
705 
706     out << blobName
707         << ".putBlob("
708         << offset
709         << " + 0 /* offsetof(hidl_vec<T>, mBuffer) */, childBlob);\n";
710 
711     out.unindent();
712     out << "}\n";
713 }
714 
needsEmbeddedReadWrite() const715 bool VectorType::needsEmbeddedReadWrite() const {
716     return true;
717 }
718 
needsResolveReferences() const719 bool VectorType::needsResolveReferences() const {
720     return mElementType->needsResolveReferences();
721 }
722 
resultNeedsDeref() const723 bool VectorType::resultNeedsDeref() const {
724     return !isVectorOfBinders();
725 }
726 
isJavaCompatible() const727 bool VectorType::isJavaCompatible() const {
728     if (!mElementType->isJavaCompatible()) {
729         return false;
730     }
731 
732     if (mElementType->isArray()) {
733         return static_cast<ArrayType *>(mElementType)->countDimensions() == 1;
734     }
735 
736     if (mElementType->isVector()) {
737         return false;
738     }
739 
740     if (isVectorOfBinders()) {
741         return false;
742     }
743 
744     return true;
745 }
746 
containsPointer() const747 bool VectorType::containsPointer() const {
748     return mElementType->containsPointer();
749 }
750 
751 // All hidl_vec<T> have the same size.
752 static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
753 
754 // static
getAlignmentAndSizeStatic(size_t * align,size_t * size)755 void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
756     *align = 8;  // hidl_vec<T>
757     *size = assertion.size();
758 }
759 
getAlignmentAndSize(size_t * align,size_t * size) const760 void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
761     VectorType::getAlignmentAndSizeStatic(align, size);
762 }
763 
764 }  // namespace android
765 
766