VectorType.cpp revision b2a861cf36ba30b0365d42b33fca0188d543c73c
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
69void VectorType::addNamedTypesToSet(std::set<const FQName> &set) const {
70    mElementType->addNamedTypesToSet(set);
71}
72
73bool VectorType::isVector() const {
74    return true;
75}
76
77bool VectorType::isVectorOfBinders() const {
78    return mElementType->isBinder();
79}
80
81bool VectorType::canCheckEquality() const {
82    return mElementType->canCheckEquality();
83}
84
85std::string VectorType::getCppType(StorageMode mode,
86                                   bool specifyNamespaces) const {
87    const std::string base =
88          std::string(specifyNamespaces ? "::android::hardware::" : "")
89        + "hidl_vec<"
90        + mElementType->getCppStackType( specifyNamespaces)
91        + ">";
92
93    switch (mode) {
94        case StorageMode_Stack:
95            return base;
96
97        case StorageMode_Argument:
98            return "const " + base + "&";
99
100        case StorageMode_Result:
101        {
102            if (isVectorOfBinders()) {
103                return base;
104            }
105
106            return "const " + base + "*";
107        }
108    }
109}
110
111std::string VectorType::getJavaType(bool /* forInitializer */) const {
112
113    std::string elementJavaType;
114    if (mElementType->isArray()) {
115        elementJavaType = mElementType->getJavaType();
116    } else {
117        elementJavaType = mElementType->getJavaWrapperType();
118    }
119
120    return "java.util.ArrayList<"
121        + elementJavaType
122        + ">";
123}
124
125std::string VectorType::getVtsType() const {
126    return "TYPE_VECTOR";
127}
128
129std::string VectorType::getVtsValueName() const {
130    return "vector_value";
131}
132
133void VectorType::emitReaderWriter(
134        Formatter &out,
135        const std::string &name,
136        const std::string &parcelObj,
137        bool parcelObjIsPointer,
138        bool isReader,
139        ErrorMode mode) const {
140    if (isVectorOfBinders()) {
141        emitReaderWriterForVectorOfBinders(
142                out, name, parcelObj, parcelObjIsPointer, isReader, mode);
143
144        return;
145    }
146
147    std::string baseType = mElementType->getCppStackType();
148
149    const std::string parentName = "_hidl_" + name + "_parent";
150
151    out << "size_t " << parentName << ";\n\n";
152
153    const std::string parcelObjDeref =
154        parcelObj + (parcelObjIsPointer ? "->" : ".");
155
156    if (isReader) {
157        out << "_hidl_err = "
158            << parcelObjDeref
159            << "readBuffer("
160            << "sizeof(*"
161            << name
162            << "), &"
163            << parentName
164            << ", "
165            << " reinterpret_cast<const void **>("
166            << "&" << name
167            << "));\n\n";
168
169        handleError(out, mode);
170    } else {
171        out << "_hidl_err = "
172            << parcelObjDeref
173            << "writeBuffer(&"
174            << name
175            << ", sizeof("
176            << name
177            << "), &"
178            << parentName
179            << ");\n";
180
181        handleError(out, mode);
182    }
183
184    emitReaderWriterEmbedded(
185            out,
186            0 /* depth */,
187            name,
188            name /* sanitizedName */ ,
189            isReader /* nameIsPointer */,
190            parcelObj,
191            parcelObjIsPointer,
192            isReader,
193            mode,
194            parentName,
195            "0 /* parentOffset */");
196}
197
198void VectorType::emitReaderWriterForVectorOfBinders(
199        Formatter &out,
200        const std::string &name,
201        const std::string &parcelObj,
202        bool parcelObjIsPointer,
203        bool isReader,
204        ErrorMode mode) const {
205    const std::string parcelObjDeref =
206        parcelObj + (parcelObjIsPointer ? "->" : ".");
207
208    if (isReader) {
209        out << "{\n";
210        out.indent();
211
212        const std::string sizeName = "_hidl_" + name + "_size";
213
214        out << "uint64_t "
215            << sizeName
216            << ";\n";
217
218        out << "_hidl_err = "
219            << parcelObjDeref
220            << "readUint64(&"
221            << sizeName
222            << ");\n";
223
224        handleError(out, mode);
225
226        out << name
227            << ".resize("
228            << sizeName
229            << ");\n\n"
230            << "for (size_t _hidl_index = 0; _hidl_index < "
231            << sizeName
232            << "; ++_hidl_index) {\n";
233
234        out.indent();
235
236        out << mElementType->getCppStackType(true /* specifyNamespaces */)
237            << " _hidl_base;\n";
238
239        mElementType->emitReaderWriter(
240                out,
241                "_hidl_base",
242                parcelObj,
243                parcelObjIsPointer,
244                isReader,
245                mode);
246
247        out << name
248            << "[_hidl_index] = _hidl_base;\n";
249
250        out.unindent();
251        out << "}\n";
252
253        out.unindent();
254        out << "}\n";
255    } else {
256        out << "_hidl_err = "
257            << parcelObjDeref
258            << "writeUint64("
259            << name
260            << ".size());\n";
261
262        handleError(out, mode);
263
264        out << "for (size_t _hidl_index = 0; _hidl_index < "
265            << name
266            << ".size(); ++_hidl_index) {\n";
267
268        out.indent();
269
270        mElementType->emitReaderWriter(
271                out,
272                name + "[_hidl_index]",
273                parcelObj,
274                parcelObjIsPointer,
275                isReader,
276                mode);
277
278        out.unindent();
279        out << "}\n";
280    }
281}
282
283void VectorType::emitReaderWriterEmbedded(
284        Formatter &out,
285        size_t depth,
286        const std::string &name,
287        const std::string &sanitizedName,
288        bool nameIsPointer,
289        const std::string &parcelObj,
290        bool parcelObjIsPointer,
291        bool isReader,
292        ErrorMode mode,
293        const std::string &parentName,
294        const std::string &offsetText) const {
295    std::string baseType = getCppStackType();
296
297    const std::string childName = "_hidl_" + sanitizedName + "_child";
298    out << "size_t " << childName << ";\n\n";
299
300    emitReaderWriterEmbeddedForTypeName(
301            out,
302            name,
303            nameIsPointer,
304            parcelObj,
305            parcelObjIsPointer,
306            isReader,
307            mode,
308            parentName,
309            offsetText,
310            baseType,
311            childName,
312            "::android::hardware");
313
314    if (!mElementType->needsEmbeddedReadWrite()) {
315        return;
316    }
317
318    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
319
320    baseType = mElementType->getCppStackType();
321
322    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
323
324    out << "for (size_t "
325        << iteratorName
326        << " = 0; "
327        << iteratorName
328        << " < "
329        << nameDeref
330        << "size(); ++"
331        << iteratorName
332        << ") {\n";
333
334    out.indent();
335
336    mElementType->emitReaderWriterEmbedded(
337            out,
338            depth + 1,
339            (nameIsPointer ? "(*" + name + ")" : name)
340                + "[" + iteratorName + "]",
341            sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
342            false /* nameIsPointer */,
343            parcelObj,
344            parcelObjIsPointer,
345            isReader,
346            mode,
347            childName,
348            iteratorName + " * sizeof(" + baseType + ")");
349
350    out.unindent();
351
352    out << "}\n\n";
353}
354
355void VectorType::emitResolveReferences(
356            Formatter &out,
357            const std::string &name,
358            bool nameIsPointer,
359            const std::string &parcelObj,
360            bool parcelObjIsPointer,
361            bool isReader,
362            ErrorMode mode) const {
363    emitResolveReferencesEmbeddedHelper(
364        out,
365        0, /* depth */
366        name,
367        name /* sanitizedName */,
368        nameIsPointer,
369        parcelObj,
370        parcelObjIsPointer,
371        isReader,
372        mode,
373        "_hidl_" + name + "_child",
374        "0 /* parentOffset */");
375}
376
377void VectorType::emitResolveReferencesEmbedded(
378            Formatter &out,
379            size_t depth,
380            const std::string &name,
381            const std::string &sanitizedName,
382            bool nameIsPointer,
383            const std::string &parcelObj,
384            bool parcelObjIsPointer,
385            bool isReader,
386            ErrorMode mode,
387            const std::string & /* parentName */,
388            const std::string & /* offsetText */) const {
389    emitResolveReferencesEmbeddedHelper(
390        out, depth, name, sanitizedName, nameIsPointer, parcelObj,
391        parcelObjIsPointer, isReader, mode, "", "");
392}
393
394bool VectorType::useParentInEmitResolveReferencesEmbedded() const {
395    // parentName and offsetText is not used in emitResolveReferencesEmbedded
396    return false;
397}
398
399void VectorType::emitResolveReferencesEmbeddedHelper(
400            Formatter &out,
401            size_t depth,
402            const std::string &name,
403            const std::string &sanitizedName,
404            bool nameIsPointer,
405            const std::string &parcelObj,
406            bool parcelObjIsPointer,
407            bool isReader,
408            ErrorMode mode,
409            const std::string &childName,
410            const std::string &childOffsetText) const {
411    CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
412
413    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
414    const std::string nameDerefed = (nameIsPointer ? "*" : "") + name;
415    std::string elementType = mElementType->getCppStackType();
416
417    std::string myChildName = childName, myChildOffset = childOffsetText;
418
419    if(myChildName.empty() && myChildOffset.empty()) {
420        myChildName = "_hidl_" + sanitizedName + "_child";
421        myChildOffset = "0";
422
423        out << "size_t " << myChildName << ";\n";
424        out << "_hidl_err = ::android::hardware::findInParcel("
425            << nameDerefed << ", "
426            << (parcelObjIsPointer ? "*" : "") << parcelObj << ", "
427            << "&" << myChildName
428            << ");\n";
429
430        handleError(out, mode);
431    }
432
433    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
434
435    out << "for (size_t "
436        << iteratorName
437        << " = 0; "
438        << iteratorName
439        << " < "
440        << nameDeref
441        << "size(); ++"
442        << iteratorName
443        << ") {\n";
444
445    out.indent();
446
447    mElementType->emitResolveReferencesEmbedded(
448        out,
449        depth + 1,
450        (nameIsPointer ? "(*" + name + ")" : name) + "[" + iteratorName + "]",
451        sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
452        false /* nameIsPointer */,
453        parcelObj,
454        parcelObjIsPointer,
455        isReader,
456        mode,
457        myChildName,
458        myChildOffset + " + " +
459                iteratorName + " * sizeof(" + elementType + ")");
460
461    out.unindent();
462
463    out << "}\n\n";
464}
465
466void VectorType::emitJavaReaderWriter(
467        Formatter &out,
468        const std::string &parcelObj,
469        const std::string &argName,
470        bool isReader) const {
471    if (mElementType->isCompoundType()) {
472
473        if (isReader) {
474            out << mElementType->getJavaType()
475                << ".readVectorFromParcel("
476                << parcelObj
477                << ");\n";
478        } else {
479            out << mElementType->getJavaType()
480                << ".writeVectorToParcel("
481                << parcelObj
482                << ", "
483                << argName
484                << ");\n";
485        }
486
487        return;
488    }
489
490    if (mElementType->isArray()) {
491        size_t align, size;
492        getAlignmentAndSize(&align, &size);
493        if (isReader) {
494            out << " new "
495                << getJavaType(false /* forInitializer */)
496                << "();\n";
497        }
498
499        out << "{\n";
500        out.indent();
501
502        out << "android.os.HwBlob _hidl_blob = ";
503
504        if (isReader) {
505            out << parcelObj
506                << ".readBuffer("
507                << size
508                << " /* size */);\n";
509        } else {
510
511            out << "new android.os.HwBlob("
512                << size
513                << " /* size */);\n";
514        }
515
516        emitJavaFieldReaderWriter(
517                out,
518                0 /* depth */,
519                parcelObj,
520                "_hidl_blob",
521                argName,
522                "0 /* offset */",
523                isReader);
524
525        if (!isReader) {
526            out << parcelObj << ".writeBuffer(_hidl_blob);\n";
527        };
528
529        out.unindent();
530        out << "}\n";
531
532        return;
533    }
534
535    emitJavaReaderWriterWithSuffix(
536            out,
537            parcelObj,
538            argName,
539            isReader,
540            mElementType->getJavaSuffix() + "Vector",
541            "" /* extra */);
542}
543
544void VectorType::emitJavaFieldInitializer(
545        Formatter &out, const std::string &fieldName) const {
546    std::string javaType = getJavaType(false /* forInitializer */);
547
548    out << "final "
549        << javaType
550        << " "
551        << fieldName
552        << " = new "
553        << javaType
554        << "();\n";
555}
556
557void VectorType::emitJavaFieldReaderWriter(
558        Formatter &out,
559        size_t depth,
560        const std::string &parcelName,
561        const std::string &blobName,
562        const std::string &fieldName,
563        const std::string &offset,
564        bool isReader) const {
565    VectorType::EmitJavaFieldReaderWriterForElementType(
566            out,
567            depth,
568            mElementType,
569            parcelName,
570            blobName,
571            fieldName,
572            offset,
573            isReader);
574}
575
576// static
577void 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
712bool VectorType::needsEmbeddedReadWrite() const {
713    return true;
714}
715
716bool VectorType::needsResolveReferences() const {
717    return mElementType->needsResolveReferences();
718}
719
720bool VectorType::resultNeedsDeref() const {
721    return !isVectorOfBinders();
722}
723
724bool VectorType::isJavaCompatible() const {
725    if (!mElementType->isJavaCompatible()) {
726        return false;
727    }
728
729    if (mElementType->isArray()) {
730        return static_cast<ArrayType *>(mElementType)->countDimensions() == 1;
731    }
732
733    if (mElementType->isVector()) {
734        return false;
735    }
736
737    if (isVectorOfBinders()) {
738        return false;
739    }
740
741    return true;
742}
743
744bool VectorType::containsPointer() const {
745    return mElementType->containsPointer();
746}
747
748// All hidl_vec<T> have the same size.
749static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
750
751// static
752void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
753    *align = 8;  // hidl_vec<T>
754    *size = assertion.size();
755}
756
757void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
758    VectorType::getAlignmentAndSizeStatic(align, size);
759}
760
761}  // namespace android
762
763