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