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