• 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 <hidl-util/Formatter.h>
20 #include <android-base/logging.h>
21 
22 #include "ConstantExpression.h"
23 
24 namespace android {
25 
ArrayType(ArrayType * srcArray,ConstantExpression * size)26 ArrayType::ArrayType(ArrayType *srcArray, ConstantExpression *size)
27     : mElementType(srcArray->mElementType),
28       mSizes(srcArray->mSizes) {
29     prependDimension(size);
30 }
31 
ArrayType(Type * elementType,ConstantExpression * size)32 ArrayType::ArrayType(Type *elementType, ConstantExpression *size)
33     : mElementType(elementType) {
34     prependDimension(size);
35 }
36 
prependDimension(ConstantExpression * size)37 void ArrayType::prependDimension(ConstantExpression *size) {
38     mSizes.insert(mSizes.begin(), size);
39 }
40 
appendDimension(ConstantExpression * size)41 void ArrayType::appendDimension(ConstantExpression *size) {
42     mSizes.push_back(size);
43 }
44 
countDimensions() const45 size_t ArrayType::countDimensions() const {
46     return mSizes.size();
47 }
48 
isArray() const49 bool ArrayType::isArray() const {
50     return true;
51 }
52 
canCheckEquality() const53 bool ArrayType::canCheckEquality() const {
54     return mElementType->canCheckEquality();
55 }
56 
getElementType() const57 Type *ArrayType::getElementType() const {
58     return mElementType;
59 }
60 
typeName() const61 std::string ArrayType::typeName() const {
62     if (dimension() == 1) {
63         return "array of " + mElementType->typeName();
64     }
65 
66     return std::to_string(dimension()) + "d array of " + mElementType->typeName();
67 }
68 
getCppType(StorageMode mode,bool specifyNamespaces) const69 std::string ArrayType::getCppType(StorageMode mode,
70                                   bool specifyNamespaces) const {
71     const std::string base = mElementType->getCppStackType(specifyNamespaces);
72 
73     std::string space = specifyNamespaces ? "::android::hardware::" : "";
74     std::string arrayType = space + "hidl_array<" + base;
75 
76     for (size_t i = 0; i < mSizes.size(); ++i) {
77         arrayType += ", ";
78         arrayType += mSizes[i]->cppValue();
79 
80         if (!mSizes[i]->descriptionIsTrivial()) {
81             arrayType += " /* ";
82             arrayType += mSizes[i]->description();
83             arrayType += " */";
84         }
85     }
86 
87     arrayType += ">";
88 
89     switch (mode) {
90         case StorageMode_Stack:
91             return arrayType;
92 
93         case StorageMode_Argument:
94             return "const " + arrayType + "&";
95 
96         case StorageMode_Result:
97             return "const " + arrayType + "*";
98     }
99 
100     CHECK(!"Should not be here");
101 }
102 
getInternalDataCppType() const103 std::string ArrayType::getInternalDataCppType() const {
104     std::string result = mElementType->getCppStackType();
105     for (size_t i = 0; i < mSizes.size(); ++i) {
106         result += "[";
107         result += mSizes[i]->cppValue();
108         result += "]";
109     }
110     return result;
111 }
112 
getJavaType(bool forInitializer) const113 std::string ArrayType::getJavaType(bool forInitializer) const {
114     std::string base =
115         mElementType->getJavaType(forInitializer);
116 
117     for (size_t i = 0; i < mSizes.size(); ++i) {
118         base += "[";
119 
120         if (forInitializer) {
121             base += mSizes[i]->javaValue();
122         }
123 
124         if (!forInitializer || !mSizes[i]->descriptionIsTrivial()) {
125             if (forInitializer)
126                 base += " ";
127             base += "/* " + mSizes[i]->description() + " */";
128         }
129 
130         base += "]";
131     }
132 
133     return base;
134 }
135 
getJavaWrapperType() const136 std::string ArrayType::getJavaWrapperType() const {
137     return mElementType->getJavaWrapperType();
138 }
139 
getVtsType() const140 std::string ArrayType::getVtsType() const {
141     return "TYPE_ARRAY";
142 }
143 
emitReaderWriter(Formatter & out,const std::string & name,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const144 void ArrayType::emitReaderWriter(
145         Formatter &out,
146         const std::string &name,
147         const std::string &parcelObj,
148         bool parcelObjIsPointer,
149         bool isReader,
150         ErrorMode mode) const {
151     std::string baseType = mElementType->getCppStackType();
152 
153     const std::string parentName = "_hidl_" + name + "_parent";
154 
155     out << "size_t " << parentName << ";\n\n";
156 
157     const std::string parcelObjDeref =
158         parcelObj + (parcelObjIsPointer ? "->" : ".");
159 
160     size_t numArrayElements = 1;
161     for (auto size : mSizes) {
162         numArrayElements *= size->castSizeT();
163     }
164     if (isReader) {
165         out << "_hidl_err = "
166             << parcelObjDeref
167             << "readBuffer("
168             << numArrayElements
169             << " * sizeof("
170             << baseType
171             << "), &"
172             << parentName
173             << ", "
174             << " reinterpret_cast<const void **>("
175             << "&" << name
176             << "));\n\n";
177 
178         handleError(out, mode);
179     } else {
180 
181         out << "_hidl_err = "
182             << parcelObjDeref
183             << "writeBuffer("
184             << name
185             << ".data(), "
186             << numArrayElements
187             << " * sizeof("
188             << baseType
189             << "), &"
190             << parentName
191             << ");\n";
192 
193         handleError(out, mode);
194     }
195 
196     emitReaderWriterEmbedded(
197             out,
198             0 /* depth */,
199             name,
200             name /* sanitizedName */,
201             isReader /* nameIsPointer */,
202             parcelObj,
203             parcelObjIsPointer,
204             isReader,
205             mode,
206             parentName,
207             "0 /* parentOffset */");
208 }
209 
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) const210 void ArrayType::emitReaderWriterEmbedded(
211         Formatter &out,
212         size_t depth,
213         const std::string &name,
214         const std::string &sanitizedName,
215         bool nameIsPointer,
216         const std::string &parcelObj,
217         bool parcelObjIsPointer,
218         bool isReader,
219         ErrorMode mode,
220         const std::string &parentName,
221         const std::string &offsetText) const {
222     if (!mElementType->needsEmbeddedReadWrite()) {
223         return;
224     }
225 
226     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
227 
228     std::string baseType = mElementType->getCppStackType();
229 
230     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
231 
232     out << "for (size_t "
233         << iteratorName
234         << " = 0; "
235         << iteratorName
236         << " < "
237         << dimension()
238         << "; ++"
239         << iteratorName
240         << ") {\n";
241 
242     out.indent();
243 
244     mElementType->emitReaderWriterEmbedded(
245             out,
246             depth + 1,
247             nameDeref + "data()[" + iteratorName + "]",
248             sanitizedName + "_indexed",
249             false /* nameIsPointer */,
250             parcelObj,
251             parcelObjIsPointer,
252             isReader,
253             mode,
254             parentName,
255             offsetText
256                 + " + " + iteratorName + " * sizeof("
257                 + baseType
258                 + ")");
259 
260     out.unindent();
261 
262     out << "}\n\n";
263 }
264 
emitResolveReferences(Formatter & out,const std::string & name,bool nameIsPointer,const std::string & parcelObj,bool parcelObjIsPointer,bool isReader,ErrorMode mode) const265 void ArrayType::emitResolveReferences(
266             Formatter &out,
267             const std::string &name,
268             bool nameIsPointer,
269             const std::string &parcelObj,
270             bool parcelObjIsPointer,
271             bool isReader,
272             ErrorMode mode) const {
273     emitResolveReferencesEmbedded(
274         out,
275         0 /* depth */,
276         name,
277         name /* sanitizedName */,
278         nameIsPointer,
279         parcelObj,
280         parcelObjIsPointer,
281         isReader,
282         mode,
283         "_hidl_" + name + "_parent",
284         "0 /* parentOffset */");
285 }
286 
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) const287 void ArrayType::emitResolveReferencesEmbedded(
288             Formatter &out,
289             size_t depth,
290             const std::string &name,
291             const std::string &sanitizedName,
292             bool nameIsPointer,
293             const std::string &parcelObj,
294             bool parcelObjIsPointer,
295             bool isReader,
296             ErrorMode mode,
297             const std::string &parentName,
298             const std::string &offsetText) const {
299     CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
300 
301     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
302 
303     std::string baseType = mElementType->getCppStackType();
304 
305     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
306 
307     out << "for (size_t "
308         << iteratorName
309         << " = 0; "
310         << iteratorName
311         << " < "
312         << dimension()
313         << "; ++"
314         << iteratorName
315         << ") {\n";
316 
317     out.indent();
318 
319     mElementType->emitResolveReferencesEmbedded(
320         out,
321         depth + 1,
322         nameDeref + "data()[" + iteratorName + "]",
323         sanitizedName + "_indexed",
324         false /* nameIsPointer */,
325         parcelObj,
326         parcelObjIsPointer,
327         isReader,
328         mode,
329         parentName,
330         offsetText + " + " + iteratorName + " * sizeof("
331         + baseType
332         + ")");
333 
334     out.unindent();
335 
336     out << "}\n\n";
337 }
338 
emitJavaDump(Formatter & out,const std::string & streamName,const std::string & name) const339 void ArrayType::emitJavaDump(
340         Formatter &out,
341         const std::string &streamName,
342         const std::string &name) const {
343     out << streamName << ".append(java.util.Arrays."
344         << (countDimensions() > 1 ? "deepToString" : "toString")
345         << "("
346         << name << "));\n";
347 }
348 
349 
needsEmbeddedReadWrite() const350 bool ArrayType::needsEmbeddedReadWrite() const {
351     return mElementType->needsEmbeddedReadWrite();
352 }
353 
needsResolveReferences() const354 bool ArrayType::needsResolveReferences() const {
355     return mElementType->needsResolveReferences();
356 }
357 
resultNeedsDeref() const358 bool ArrayType::resultNeedsDeref() const {
359     return true;
360 }
361 
emitJavaReaderWriter(Formatter & out,const std::string & parcelObj,const std::string & argName,bool isReader) const362 void ArrayType::emitJavaReaderWriter(
363         Formatter &out,
364         const std::string &parcelObj,
365         const std::string &argName,
366         bool isReader) const {
367     size_t align, size;
368     getAlignmentAndSize(&align, &size);
369 
370     if (isReader) {
371         out << "new "
372             << getJavaType(true /* forInitializer */)
373             << ";\n";
374     }
375 
376     out << "{\n";
377     out.indent();
378 
379     out << "android.os.HwBlob _hidl_blob = ";
380 
381     if (isReader) {
382         out << parcelObj
383             << ".readBuffer("
384             << size
385             << " /* size */);\n";
386     } else {
387         out << "new android.os.HwBlob("
388             << size
389             << " /* size */);\n";
390     }
391 
392     emitJavaFieldReaderWriter(
393             out,
394             0 /* depth */,
395             parcelObj,
396             "_hidl_blob",
397             argName,
398             "0 /* offset */",
399             isReader);
400 
401     if (!isReader) {
402         out << parcelObj << ".writeBuffer(_hidl_blob);\n";
403     }
404 
405     out.unindent();
406     out << "}\n";
407 }
408 
emitJavaFieldInitializer(Formatter & out,const std::string & fieldName) const409 void ArrayType::emitJavaFieldInitializer(
410         Formatter &out, const std::string &fieldName) const {
411     std::string typeName = getJavaType(false /* forInitializer */);
412     std::string initName = getJavaType(true /* forInitializer */);
413 
414     out << "final "
415         << typeName
416         << " "
417         << fieldName
418         << " = new "
419         << initName
420         << ";\n";
421 }
422 
emitJavaFieldReaderWriter(Formatter & out,size_t depth,const std::string & parcelName,const std::string & blobName,const std::string & fieldName,const std::string & offset,bool isReader) const423 void ArrayType::emitJavaFieldReaderWriter(
424         Formatter &out,
425         size_t depth,
426         const std::string &parcelName,
427         const std::string &blobName,
428         const std::string &fieldName,
429         const std::string &offset,
430         bool isReader) const {
431     out << "{\n";
432     out.indent();
433 
434     std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
435     out << "long " << offsetName << " = " << offset << ";\n";
436 
437     std::string indexString;
438     for (size_t dim = 0; dim < mSizes.size(); ++dim) {
439         std::string iteratorName =
440             "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
441 
442         out << "for (int "
443             << iteratorName
444             << " = 0; "
445             << iteratorName
446             << " < "
447             << mSizes[dim]->javaValue()
448             << "; ++"
449             << iteratorName
450             << ") {\n";
451 
452         out.indent();
453 
454         indexString += "[" + iteratorName + "]";
455     }
456 
457     if (isReader && mElementType->isCompoundType()) {
458         std::string typeName =
459             mElementType->getJavaType(false /* forInitializer */);
460 
461         out << fieldName
462             << indexString
463             << " = new "
464             << typeName
465             << "();\n";
466     }
467 
468     mElementType->emitJavaFieldReaderWriter(
469             out,
470             depth + 1,
471             parcelName,
472             blobName,
473             fieldName + indexString,
474             offsetName,
475             isReader);
476 
477     size_t elementAlign, elementSize;
478     mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
479 
480     out << offsetName << " += " << std::to_string(elementSize) << ";\n";
481 
482     for (size_t dim = 0; dim < mSizes.size(); ++dim) {
483         out.unindent();
484         out << "}\n";
485     }
486 
487     out.unindent();
488     out << "}\n";
489 }
490 
emitVtsTypeDeclarations(Formatter & out) const491 status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
492     out << "type: " << getVtsType() << "\n";
493     out << "vector_size: " << mSizes[0]->value() << "\n";
494     out << "vector_value: {\n";
495     out.indent();
496     // Simple array case.
497     if (mSizes.size() == 1) {
498         status_t err = mElementType->emitVtsTypeDeclarations(out);
499         if (err != OK) {
500             return err;
501         }
502     } else {  // Multi-dimension array case.
503         for (size_t index = 1; index < mSizes.size(); index++) {
504             out << "type: " << getVtsType() << "\n";
505             out << "vector_size: " << mSizes[index]->value() << "\n";
506             out << "vector_value: {\n";
507             out.indent();
508             if (index == mSizes.size() - 1) {
509                 status_t err = mElementType->emitVtsTypeDeclarations(out);
510                 if (err != OK) {
511                     return err;
512                 }
513             }
514         }
515     }
516     for (size_t index = 0; index < mSizes.size(); index++) {
517         out.unindent();
518         out << "}\n";
519     }
520     return OK;
521 }
522 
isJavaCompatible() const523 bool ArrayType::isJavaCompatible() const {
524     return mElementType->isJavaCompatible();
525 }
526 
containsPointer() const527 bool ArrayType::containsPointer() const {
528     return mElementType->containsPointer();
529 }
530 
getAlignmentAndSize(size_t * align,size_t * size) const531 void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
532     mElementType->getAlignmentAndSize(align, size);
533 
534     for (auto sizeInDimension : mSizes) {
535         (*size) *= sizeInDimension->castSizeT();
536     }
537 }
538 
dimension() const539 size_t ArrayType::dimension() const {
540     size_t numArrayElements = 1;
541     for (auto size : mSizes) {
542         numArrayElements *= size->castSizeT();
543     }
544     return numArrayElements;
545 }
546 
547 }  // namespace android
548 
549