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