• 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 "ArrayType.h"
18 
19 #include <android-base/logging.h>
20 #include <hidl-util/Formatter.h>
21 #include <iostream>
22 
23 #include "ConstantExpression.h"
24 
25 namespace android {
26 
ArrayType(const Reference<Type> & elementType,ConstantExpression * size,Scope * parent)27 ArrayType::ArrayType(const Reference<Type>& elementType, ConstantExpression* size, Scope* parent)
28     : Type(parent), mElementType(elementType), mSizes{size} {
29     CHECK(!elementType.isEmptyReference());
30 }
31 
appendDimension(ConstantExpression * size)32 void ArrayType::appendDimension(ConstantExpression *size) {
33     mSizes.push_back(size);
34 }
35 
countDimensions() const36 size_t ArrayType::countDimensions() const {
37     return mSizes.size();
38 }
39 
isArray() const40 bool ArrayType::isArray() const {
41     return true;
42 }
43 
deepCanCheckEquality(std::unordered_set<const Type * > * visited) const44 bool ArrayType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
45     return mElementType->canCheckEquality(visited);
46 }
47 
getElementType() const48 const Type* ArrayType::getElementType() const {
49     return mElementType.get();
50 }
51 
typeName() const52 std::string ArrayType::typeName() const {
53     if (dimension() == 1) {
54         return "array of " + mElementType->typeName();
55     }
56 
57     return std::to_string(dimension()) + "d array of " + mElementType->typeName();
58 }
59 
getReferences() const60 std::vector<const Reference<Type>*> ArrayType::getReferences() const {
61     return {&mElementType};
62 }
63 
getConstantExpressions() const64 std::vector<const ConstantExpression*> ArrayType::getConstantExpressions() const {
65     std::vector<const ConstantExpression*> ret;
66     ret.insert(ret.end(), mSizes.begin(), mSizes.end());
67     return ret;
68 }
69 
resolveInheritance()70 status_t ArrayType::resolveInheritance() {
71     // Resolve for typedefs
72     while (mElementType->isArray()) {
73         ArrayType* innerArray = static_cast<ArrayType*>(mElementType.get());
74         mSizes.insert(mSizes.end(), innerArray->mSizes.begin(), innerArray->mSizes.end());
75         mElementType = innerArray->mElementType;
76     }
77     return Type::resolveInheritance();
78 }
79 
validate() const80 status_t ArrayType::validate() const {
81     CHECK(!mElementType->isArray());
82 
83     if (mElementType->isInterface()) {
84         std::cerr << "ERROR: Arrays of interface types are not supported"
85                   << " at " << mElementType.location() << "\n";
86 
87         return UNKNOWN_ERROR;
88     }
89     return Type::validate();
90 }
91 
getCppType(StorageMode mode,bool specifyNamespaces) const92 std::string ArrayType::getCppType(StorageMode mode,
93                                   bool specifyNamespaces) const {
94     const std::string base = mElementType->getCppStackType(specifyNamespaces);
95 
96     std::string space = specifyNamespaces ? "::android::hardware::" : "";
97     std::string arrayType = space + "hidl_array<" + base;
98 
99     for (size_t i = 0; i < mSizes.size(); ++i) {
100         arrayType += ", " + mSizes[i]->cppValue();
101     }
102 
103     arrayType += ">";
104 
105     switch (mode) {
106         case StorageMode_Stack:
107             return arrayType;
108 
109         case StorageMode_Argument:
110             return "const " + arrayType + "&";
111 
112         case StorageMode_Result:
113             return "const " + arrayType + "*";
114     }
115 
116     CHECK(!"Should not be here");
117 }
118 
getInternalDataCppType() const119 std::string ArrayType::getInternalDataCppType() const {
120     std::string result = mElementType->getCppStackType();
121     for (size_t i = 0; i < mSizes.size(); ++i) {
122         result += "[";
123         result += mSizes[i]->cppValue();
124         result += "]";
125     }
126     return result;
127 }
128 
getJavaType(bool forInitializer) const129 std::string ArrayType::getJavaType(bool forInitializer) const {
130     std::string base =
131         mElementType->getJavaType(forInitializer);
132 
133     for (size_t i = 0; i < mSizes.size(); ++i) {
134         base += "[";
135 
136         if (forInitializer) {
137             base += mSizes[i]->javaValue();
138         } else {
139             base += "/* " + mSizes[i]->expression() + " */";
140         }
141 
142         base += "]";
143     }
144 
145     return base;
146 }
147 
getVtsType() const148 std::string ArrayType::getVtsType() const {
149     return "TYPE_ARRAY";
150 }
151 
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const152 void ArrayType::emitReaderWriter(
153         Formatter &out,
154         const std::string &name,
155         const std::string &parcelObj,
156         bool parcelObjIsPointer,
157         bool isReader,
158         ErrorMode mode) const {
159     std::string baseType = mElementType->getCppStackType();
160 
161     const std::string parentName = "_hidl_" + name + "_parent";
162 
163     out << "size_t " << parentName << ";\n\n";
164 
165     const std::string parcelObjDeref =
166         parcelObj + (parcelObjIsPointer ? "->" : ".");
167 
168     size_t numArrayElements = 1;
169     for (auto size : mSizes) {
170         numArrayElements *= size->castSizeT();
171     }
172     if (isReader) {
173         out << "_hidl_err = "
174             << parcelObjDeref
175             << "readBuffer("
176             << numArrayElements
177             << " * sizeof("
178             << baseType
179             << "), &"
180             << parentName
181             << ", "
182             << " reinterpret_cast<const void **>("
183             << "&" << name
184             << "));\n\n";
185 
186         handleError(out, mode);
187     } else {
188 
189         out << "_hidl_err = "
190             << parcelObjDeref
191             << "writeBuffer("
192             << name
193             << ".data(), "
194             << numArrayElements
195             << " * sizeof("
196             << baseType
197             << "), &"
198             << parentName
199             << ");\n";
200 
201         handleError(out, mode);
202     }
203 
204     emitReaderWriterEmbedded(
205             out,
206             0 /* depth */,
207             name,
208             name /* sanitizedName */,
209             isReader /* nameIsPointer */,
210             parcelObj,
211             parcelObjIsPointer,
212             isReader,
213             mode,
214             parentName,
215             "0 /* parentOffset */");
216 }
217 
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) const218 void ArrayType::emitReaderWriterEmbedded(
219         Formatter &out,
220         size_t depth,
221         const std::string &name,
222         const std::string &sanitizedName,
223         bool nameIsPointer,
224         const std::string &parcelObj,
225         bool parcelObjIsPointer,
226         bool isReader,
227         ErrorMode mode,
228         const std::string &parentName,
229         const std::string &offsetText) const {
230     if (!mElementType->needsEmbeddedReadWrite()) {
231         return;
232     }
233 
234     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
235 
236     std::string baseType = mElementType->getCppStackType();
237 
238     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
239 
240     out << "for (size_t "
241         << iteratorName
242         << " = 0; "
243         << iteratorName
244         << " < "
245         << dimension()
246         << "; ++"
247         << iteratorName
248         << ") {\n";
249 
250     out.indent();
251 
252     mElementType->emitReaderWriterEmbedded(
253             out,
254             depth + 1,
255             nameDeref + "data()[" + iteratorName + "]",
256             sanitizedName + "_indexed",
257             false /* nameIsPointer */,
258             parcelObj,
259             parcelObjIsPointer,
260             isReader,
261             mode,
262             parentName,
263             offsetText
264                 + " + " + iteratorName + " * sizeof("
265                 + baseType
266                 + ")");
267 
268     out.unindent();
269 
270     out << "}\n\n";
271 }
272 
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const273 void ArrayType::emitResolveReferences(
274             Formatter &out,
275             const std::string &name,
276             bool nameIsPointer,
277             const std::string &parcelObj,
278             bool parcelObjIsPointer,
279             bool isReader,
280             ErrorMode mode) const {
281     emitResolveReferencesEmbedded(
282         out,
283         0 /* depth */,
284         name,
285         name /* sanitizedName */,
286         nameIsPointer,
287         parcelObj,
288         parcelObjIsPointer,
289         isReader,
290         mode,
291         "_hidl_" + name + "_parent",
292         "0 /* parentOffset */");
293 }
294 
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 & parentName,const std::string & offsetText) const295 void ArrayType::emitResolveReferencesEmbedded(
296             Formatter &out,
297             size_t depth,
298             const std::string &name,
299             const std::string &sanitizedName,
300             bool nameIsPointer,
301             const std::string &parcelObj,
302             bool parcelObjIsPointer,
303             bool isReader,
304             ErrorMode mode,
305             const std::string &parentName,
306             const std::string &offsetText) const {
307     CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
308 
309     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
310 
311     std::string baseType = mElementType->getCppStackType();
312 
313     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
314 
315     out << "for (size_t "
316         << iteratorName
317         << " = 0; "
318         << iteratorName
319         << " < "
320         << dimension()
321         << "; ++"
322         << iteratorName
323         << ") {\n";
324 
325     out.indent();
326 
327     mElementType->emitResolveReferencesEmbedded(
328         out,
329         depth + 1,
330         nameDeref + "data()[" + iteratorName + "]",
331         sanitizedName + "_indexed",
332         false /* nameIsPointer */,
333         parcelObj,
334         parcelObjIsPointer,
335         isReader,
336         mode,
337         parentName,
338         offsetText + " + " + iteratorName + " * sizeof("
339         + baseType
340         + ")");
341 
342     out.unindent();
343 
344     out << "}\n\n";
345 }
346 
emitJavaDump(Formatter & out,const std::string & streamName,const std::string & name) const347 void ArrayType::emitJavaDump(
348         Formatter &out,
349         const std::string &streamName,
350         const std::string &name) const {
351     out << streamName << ".append(java.util.Arrays."
352         << (countDimensions() > 1 ? "deepToString" : "toString")
353         << "("
354         << name
355         << "));\n";
356 }
357 
358 
needsEmbeddedReadWrite() const359 bool ArrayType::needsEmbeddedReadWrite() const {
360     return mElementType->needsEmbeddedReadWrite();
361 }
362 
deepNeedsResolveReferences(std::unordered_set<const Type * > * visited) const363 bool ArrayType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
364     if (mElementType->needsResolveReferences(visited)) {
365         return true;
366     }
367     return Type::deepNeedsResolveReferences(visited);
368 }
369 
resultNeedsDeref() const370 bool ArrayType::resultNeedsDeref() const {
371     return true;
372 }
373 
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const374 void ArrayType::emitJavaReaderWriter(
375         Formatter &out,
376         const std::string &parcelObj,
377         const std::string &argName,
378         bool isReader) const {
379     size_t align, size;
380     getAlignmentAndSize(&align, &size);
381 
382     if (isReader) {
383         out << "new "
384             << getJavaType(true /* forInitializer */)
385             << ";\n";
386     }
387 
388     out << "{\n";
389     out.indent();
390 
391     out << "android.os.HwBlob _hidl_blob = ";
392 
393     if (isReader) {
394         out << parcelObj
395             << ".readBuffer("
396             << size
397             << " /* size */);\n";
398     } else {
399         out << "new android.os.HwBlob("
400             << size
401             << " /* size */);\n";
402     }
403 
404     emitJavaFieldReaderWriter(
405             out,
406             0 /* depth */,
407             parcelObj,
408             "_hidl_blob",
409             argName,
410             "0 /* offset */",
411             isReader);
412 
413     if (!isReader) {
414         out << parcelObj << ".writeBuffer(_hidl_blob);\n";
415     }
416 
417     out.unindent();
418     out << "}\n";
419 }
420 
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const421 void ArrayType::emitJavaFieldInitializer(
422         Formatter &out, const std::string &fieldName) const {
423     const std::string typeName = getJavaType(false /* forInitializer */);
424     const std::string fieldDeclaration = typeName + " " + fieldName;
425 
426     emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
427 }
428 
emitJavaFieldDefaultInitialValue(Formatter & out,const std::string & declaredFieldName) const429 void ArrayType::emitJavaFieldDefaultInitialValue(
430         Formatter &out, const std::string &declaredFieldName) const {
431     out << declaredFieldName
432         << " = new "
433         << getJavaType(true /* forInitializer */)
434         << ";\n";
435 }
436 
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const437 void ArrayType::emitJavaFieldReaderWriter(
438         Formatter &out,
439         size_t depth,
440         const std::string &parcelName,
441         const std::string &blobName,
442         const std::string &fieldName,
443         const std::string &offset,
444         bool isReader) const {
445     out << "{\n";
446     out.indent();
447 
448     std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
449     out << "long " << offsetName << " = " << offset << ";\n";
450 
451     const bool isPrimitiveArray = mElementType->isScalar();
452 
453     /* If the element type corresponds to a Java primitive type we can optimize
454        the innermost loop by copying a linear range of memory instead of doing
455        a per-element copy. As a result the outer nested loop does not include
456        the final dimension. */
457     const size_t loopDimensions = mSizes.size() - (isPrimitiveArray ? 1 : 0);
458 
459     std::string indexString;
460     for (size_t dim = 0; dim < loopDimensions; ++dim) {
461         std::string iteratorName =
462             "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
463 
464         out << "for (int "
465             << iteratorName
466             << " = 0; "
467             << iteratorName
468             << " < "
469             << mSizes[dim]->javaValue()
470             << "; ++"
471             << iteratorName
472             << ") {\n";
473 
474         out.indent();
475 
476         indexString += "[" + iteratorName + "]";
477     }
478 
479     const bool isIndexed = (loopDimensions > 0);
480     const std::string fieldNameWithCast = isIndexed
481             ? "(" + getJavaTypeCast(fieldName) + ")" + indexString
482             : getJavaTypeCast(fieldName);
483 
484     if (isReader && mElementType->isCompoundType()) {
485         mElementType->emitJavaFieldDefaultInitialValue(out, fieldNameWithCast);
486     }
487 
488     if (!isPrimitiveArray) {
489         mElementType->emitJavaFieldReaderWriter(
490                 out,
491                 depth + 1,
492                 parcelName,
493                 blobName,
494                 fieldNameWithCast,
495                 offsetName,
496                 isReader);
497 
498         size_t elementAlign, elementSize;
499         mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
500 
501         out << offsetName << " += " << std::to_string(elementSize) << ";\n";
502     } else {
503         if (isReader) {
504             out << blobName
505                 << ".copyTo"
506                 << mElementType->getJavaSuffix()
507                 << "Array("
508                 << offsetName
509                 << ", "
510                 << fieldNameWithCast
511                 << ", "
512                 << mSizes.back()->javaValue()
513                 << " /* size */);\n";
514         } else {
515             std::string elemName = "_hidl_array_item_" + std::to_string(depth);
516 
517             out << mElementType->getJavaType(false /* forInitializer */)
518                 << "[] "
519                 << elemName
520                 << " = "
521                 << fieldNameWithCast
522                 << ";\n\n";
523 
524             out << "if ("
525                 << elemName
526                 << " == null || "
527                 << elemName
528                 << ".length != "
529                 << mSizes.back()->javaValue()
530                 << ") {\n";
531 
532             out.indent();
533 
534             out << "throw new IllegalArgumentException("
535                 << "\"Array element is not of the expected length\");\n";
536 
537             out.unindent();
538             out << "}\n\n";
539 
540             out << blobName
541                 << ".put"
542                 << mElementType->getJavaSuffix()
543                 << "Array("
544                 << offsetName
545                 << ", "
546                 << elemName
547                 << ");\n";
548         }
549 
550         size_t elementAlign, elementSize;
551         mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
552 
553         out << offsetName
554             << " += "
555             << mSizes.back()->javaValue()
556             << " * "
557             << elementSize
558             << ";\n";
559     }
560 
561     for (size_t dim = 0; dim < loopDimensions; ++dim) {
562         out.unindent();
563         out << "}\n";
564     }
565 
566     out.unindent();
567     out << "}\n";
568 }
569 
emitVtsTypeDeclarations(Formatter & out) const570 void ArrayType::emitVtsTypeDeclarations(Formatter& out) const {
571     out << "type: " << getVtsType() << "\n";
572     out << "vector_size: " << mSizes[0]->rawValue() << "\n";
573     out << "vector_value: {\n";
574     out.indent();
575     // Simple array case.
576     if (mSizes.size() == 1) {
577         mElementType->emitVtsTypeDeclarations(out);
578     } else {  // Multi-dimension array case.
579         for (size_t index = 1; index < mSizes.size(); index++) {
580             out << "type: " << getVtsType() << "\n";
581             out << "vector_size: " << mSizes[index]->rawValue() << "\n";
582             out << "vector_value: {\n";
583             out.indent();
584             if (index == mSizes.size() - 1) {
585                 mElementType->emitVtsTypeDeclarations(out);
586             }
587         }
588     }
589     for (size_t index = 0; index < mSizes.size(); index++) {
590         out.unindent();
591         out << "}\n";
592     }
593 }
594 
deepIsJavaCompatible(std::unordered_set<const Type * > * visited) const595 bool ArrayType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
596     if (!mElementType->isJavaCompatible(visited)) {
597         return false;
598     }
599     return Type::deepIsJavaCompatible(visited);
600 }
601 
deepContainsPointer(std::unordered_set<const Type * > * visited) const602 bool ArrayType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
603     if (mElementType->containsPointer(visited)) {
604         return true;
605     }
606     return Type::deepContainsPointer(visited);
607 }
608 
getAlignmentAndSize(size_t * align,size_t * size) const609 void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
610     mElementType->getAlignmentAndSize(align, size);
611 
612     for (auto sizeInDimension : mSizes) {
613         (*size) *= sizeInDimension->castSizeT();
614     }
615 }
616 
dimension() const617 size_t ArrayType::dimension() const {
618     size_t numArrayElements = 1;
619     for (auto size : mSizes) {
620         numArrayElements *= size->castSizeT();
621     }
622     return numArrayElements;
623 }
624 
625 }  // namespace android
626 
627