blob: fc0c152343883b8feee8445b5886234786ffbfdd [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "VectorType.h"
#include "ArrayType.h"
#include "CompoundType.h"
#include "HidlTypeAssertion.h"
#include <hidl-util/Formatter.h>
#include <android-base/logging.h>
namespace android {
VectorType::VectorType(Scope* parent) : TemplatedType(parent, "vec") {}
std::string VectorType::templatedTypeName() const {
return "vector";
}
bool VectorType::isCompatibleElementType(const Type* elementType) const {
if (elementType->isScalar()) {
return true;
}
if (elementType->isString()) {
return true;
}
if (elementType->isEnum()) {
return true;
}
if (elementType->isBitField()) {
return true;
}
if (elementType->isCompoundType()) {
if (static_cast<const CompoundType*>(elementType)->containsInterface()) {
return false;
}
return true;
}
if (elementType->isInterface()) {
return true;
}
if (elementType->isHandle()) {
return true;
}
if (elementType->isMemory()) {
return true;
}
if (elementType->isTemplatedType()) {
const Type* inner = static_cast<const TemplatedType*>(elementType)->getElementType();
return this->isCompatibleElementType(inner) && !inner->isInterface();
}
if (elementType->isArray()) {
const Type* inner = static_cast<const ArrayType*>(elementType)->getElementType();
return this->isCompatibleElementType(inner) && !inner->isInterface();
}
return false;
}
bool VectorType::isVector() const {
return true;
}
bool VectorType::isVectorOfBinders() const {
return mElementType->isInterface();
}
bool VectorType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
return mElementType->canCheckEquality(visited);
}
std::vector<const Reference<Type>*> VectorType::getStrongReferences() const {
return {};
}
std::string VectorType::getCppType(StorageMode mode,
bool specifyNamespaces) const {
const std::string base =
std::string(specifyNamespaces ? "::android::hardware::" : "")
+ "hidl_vec<"
+ mElementType->getCppStackType( specifyNamespaces)
+ ">";
switch (mode) {
case StorageMode_Stack:
return base;
case StorageMode_Argument:
return "const " + base + "&";
case StorageMode_Result:
{
if (isVectorOfBinders()) {
return base;
}
return "const " + base + "*";
}
}
}
std::string VectorType::getJavaType(bool /* forInitializer */) const {
// this will break if the type is templated in Java, but there are no types
// like this currently
const std::string elementJavaType = mElementType->getJavaTypeClass();
return "java.util.ArrayList<" + elementJavaType + ">";
}
std::string VectorType::getJavaTypeClass() const {
return "java.util.ArrayList";
}
std::string VectorType::getVtsType() const {
return "TYPE_VECTOR";
}
std::string VectorType::getVtsValueName() const {
return "vector_value";
}
void VectorType::emitReaderWriter(
Formatter &out,
const std::string &name,
const std::string &parcelObj,
bool parcelObjIsPointer,
bool isReader,
ErrorMode mode) const {
if (isVectorOfBinders()) {
emitReaderWriterForVectorOfBinders(
out, name, parcelObj, parcelObjIsPointer, isReader, mode);
return;
}
std::string baseType = mElementType->getCppStackType();
const std::string parentName = "_hidl_" + name + "_parent";
out << "size_t " << parentName << ";\n\n";
const std::string parcelObjDeref =
parcelObj + (parcelObjIsPointer ? "->" : ".");
if (isReader) {
out << "_hidl_err = "
<< parcelObjDeref
<< "readBuffer("
<< "sizeof(*"
<< name
<< "), &"
<< parentName
<< ", "
<< " reinterpret_cast<const void **>("
<< "&" << name
<< "));\n\n";
handleError(out, mode);
} else {
out << "_hidl_err = "
<< parcelObjDeref
<< "writeBuffer(&"
<< name
<< ", sizeof("
<< name
<< "), &"
<< parentName
<< ");\n";
handleError(out, mode);
}
emitReaderWriterEmbedded(
out,
0 /* depth */,
name,
name /* sanitizedName */ ,
isReader /* nameIsPointer */,
parcelObj,
parcelObjIsPointer,
isReader,
mode,
parentName,
"0 /* parentOffset */");
}
void VectorType::emitReaderWriterForVectorOfBinders(
Formatter &out,
const std::string &name,
const std::string &parcelObj,
bool parcelObjIsPointer,
bool isReader,
ErrorMode mode) const {
const std::string parcelObjDeref =
parcelObj + (parcelObjIsPointer ? "->" : ".");
if (isReader) {
out << "{\n";
out.indent();
const std::string sizeName = "_hidl_" + name + "_size";
out << "uint64_t "
<< sizeName
<< ";\n";
out << "_hidl_err = "
<< parcelObjDeref
<< "readUint64(&"
<< sizeName
<< ");\n";
handleError(out, mode);
out << name
<< ".resize("
<< sizeName
<< ");\n\n"
<< "for (size_t _hidl_index = 0; _hidl_index < "
<< sizeName
<< "; ++_hidl_index) {\n";
out.indent();
out << mElementType->getCppStackType(true /* specifyNamespaces */)
<< " _hidl_base;\n";
mElementType->emitReaderWriter(
out,
"_hidl_base",
parcelObj,
parcelObjIsPointer,
isReader,
mode);
out << name
<< "[_hidl_index] = _hidl_base;\n";
out.unindent();
out << "}\n";
out.unindent();
out << "}\n";
} else {
out << "_hidl_err = "
<< parcelObjDeref
<< "writeUint64("
<< name
<< ".size());\n";
handleError(out, mode);
out << "for (size_t _hidl_index = 0; _hidl_index < "
<< name
<< ".size(); ++_hidl_index) {\n";
out.indent();
mElementType->emitReaderWriter(
out,
name + "[_hidl_index]",
parcelObj,
parcelObjIsPointer,
isReader,
mode);
out.unindent();
out << "}\n";
}
}
void VectorType::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) const {
std::string baseType = getCppStackType();
const std::string childName = "_hidl_" + sanitizedName + "_child";
out << "size_t " << childName << ";\n\n";
emitReaderWriterEmbeddedForTypeName(
out,
name,
nameIsPointer,
parcelObj,
parcelObjIsPointer,
isReader,
mode,
parentName,
offsetText,
baseType,
childName,
"::android::hardware");
if (!mElementType->needsEmbeddedReadWrite()) {
return;
}
const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
baseType = mElementType->getCppStackType();
std::string iteratorName = "_hidl_index_" + std::to_string(depth);
out << "for (size_t "
<< iteratorName
<< " = 0; "
<< iteratorName
<< " < "
<< nameDeref
<< "size(); ++"
<< iteratorName
<< ") {\n";
out.indent();
mElementType->emitReaderWriterEmbedded(
out,
depth + 1,
(nameIsPointer ? "(*" + name + ")" : name)
+ "[" + iteratorName + "]",
sanitizedName + (nameIsPointer ? "_deref" : "") + "_indexed",
false /* nameIsPointer */,
parcelObj,
parcelObjIsPointer,
isReader,
mode,
childName,
iteratorName + " * sizeof(" + baseType + ")");
out.unindent();
out << "}\n\n";
}
void VectorType::emitJavaReaderWriter(
Formatter &out,
const std::string &parcelObj,
const std::string &argName,
bool isReader) const {
if (mElementType->isCompoundType()) {
if (isReader) {
out << mElementType->getJavaType()
<< ".readVectorFromParcel("
<< parcelObj
<< ");\n";
} else {
out << mElementType->getJavaType()
<< ".writeVectorToParcel("
<< parcelObj
<< ", "
<< argName
<< ");\n";
}
return;
}
if (mElementType->isArray()) {
size_t align, size;
getAlignmentAndSize(&align, &size);
if (isReader) {
out << " new "
<< getJavaType(false /* forInitializer */)
<< "();\n";
}
out << "{\n";
out.indent();
out << "android.os.HwBlob _hidl_blob = ";
if (isReader) {
out << parcelObj
<< ".readBuffer("
<< size
<< " /* size */);\n";
} else {
out << "new android.os.HwBlob("
<< size
<< " /* size */);\n";
}
emitJavaFieldReaderWriter(
out,
0 /* depth */,
parcelObj,
"_hidl_blob",
argName,
"0 /* offset */",
isReader);
if (!isReader) {
out << parcelObj << ".writeBuffer(_hidl_blob);\n";
};
out.unindent();
out << "}\n";
return;
}
emitJavaReaderWriterWithSuffix(
out,
parcelObj,
argName,
isReader,
mElementType->getJavaSuffix() + "Vector",
"" /* extra */);
}
void VectorType::emitJavaFieldInitializer(
Formatter &out, const std::string &fieldName) const {
const std::string typeName = getJavaType(false /* forInitializer */);
const std::string fieldDeclaration = typeName + " " + fieldName;
emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
}
void VectorType::emitJavaFieldDefaultInitialValue(
Formatter &out, const std::string &declaredFieldName) const {
out << declaredFieldName
<< " = new "
<< getJavaType(false /* forInitializer */)
<< "();\n";
}
void VectorType::emitJavaFieldReaderWriter(
Formatter &out,
size_t depth,
const std::string &parcelName,
const std::string &blobName,
const std::string &fieldName,
const std::string &offset,
bool isReader) const {
const std::string fieldNameWithCast = isReader
? "(" + getJavaTypeCast(fieldName) + ")"
: fieldName;
VectorType::EmitJavaFieldReaderWriterForElementType(
out,
depth,
mElementType.get(),
parcelName,
blobName,
fieldNameWithCast,
offset,
isReader);
}
void VectorType::EmitJavaFieldReaderWriterForElementType(
Formatter &out,
size_t depth,
const Type *elementType,
const std::string &parcelName,
const std::string &blobName,
const std::string &fieldName,
const std::string &offset,
bool isReader) {
size_t elementAlign, elementSize;
elementType->getAlignmentAndSize(&elementAlign, &elementSize);
if (isReader) {
out << "{\n";
out.indent();
out << "int _hidl_vec_size = "
<< blobName
<< ".getInt32("
<< offset
<< " + 8 /* offsetof(hidl_vec<T>, mSize) */);\n";
out << "android.os.HwBlob childBlob = "
<< parcelName
<< ".readEmbeddedBuffer(\n";
out.indent();
out.indent();
out << "_hidl_vec_size * "
<< elementSize << ","
<< blobName
<< ".handle(),\n"
<< offset
<< " + 0 /* offsetof(hidl_vec<T>, mBuffer) */,"
<< "true /* nullable */);\n\n";
out.unindent();
out.unindent();
out << fieldName << ".clear();\n";
std::string iteratorName = "_hidl_index_" + std::to_string(depth);
out << "for (int "
<< iteratorName
<< " = 0; "
<< iteratorName
<< " < _hidl_vec_size; "
<< "++"
<< iteratorName
<< ") {\n";
out.indent();
elementType->emitJavaFieldInitializer(out, "_hidl_vec_element");
elementType->emitJavaFieldReaderWriter(
out,
depth + 1,
parcelName,
"childBlob",
"_hidl_vec_element",
iteratorName + " * " + std::to_string(elementSize),
true /* isReader */);
out << fieldName
<< ".add(_hidl_vec_element);\n";
out.unindent();
out << "}\n";
out.unindent();
out << "}\n";
return;
}
out << "{\n";
out.indent();
out << "int _hidl_vec_size = "
<< fieldName
<< ".size();\n";
out << blobName
<< ".putInt32("
<< offset
<< " + 8 /* offsetof(hidl_vec<T>, mSize) */, _hidl_vec_size);\n";
out << blobName
<< ".putBool("
<< offset
<< " + 12 /* offsetof(hidl_vec<T>, mOwnsBuffer) */, false);\n";
// XXX make HwBlob constructor take a long instead of an int?
out << "android.os.HwBlob childBlob = new android.os.HwBlob((int)(_hidl_vec_size * "
<< elementSize
<< "));\n";
std::string iteratorName = "_hidl_index_" + std::to_string(depth);
out << "for (int "
<< iteratorName
<< " = 0; "
<< iteratorName
<< " < _hidl_vec_size; "
<< "++"
<< iteratorName
<< ") {\n";
out.indent();
elementType->emitJavaFieldReaderWriter(
out,
depth + 1,
parcelName,
"childBlob",
fieldName + ".get(" + iteratorName + ")",
iteratorName + " * " + std::to_string(elementSize),
false /* isReader */);
out.unindent();
out << "}\n";
out << blobName
<< ".putBlob("
<< offset
<< " + 0 /* offsetof(hidl_vec<T>, mBuffer) */, childBlob);\n";
out.unindent();
out << "}\n";
}
bool VectorType::needsEmbeddedReadWrite() const {
return true;
}
bool VectorType::resultNeedsDeref() const {
return !isVectorOfBinders();
}
bool VectorType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
if (!mElementType->isJavaCompatible(visited)) {
return false;
}
if (mElementType->isArray()) {
return static_cast<const ArrayType*>(mElementType.get())->countDimensions() == 1;
}
if (mElementType->isVector()) {
return false;
}
if (mElementType->isMemory()) {
return false;
}
if (isVectorOfBinders()) {
return false;
}
return TemplatedType::deepIsJavaCompatible(visited);
}
bool VectorType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
if (mElementType->containsPointer(visited)) {
return true;
}
return TemplatedType::deepContainsPointer(visited);
}
// All hidl_vec<T> have the same size.
static HidlTypeAssertion assertion("hidl_vec<char>", 16 /* size */);
void VectorType::getAlignmentAndSizeStatic(size_t *align, size_t *size) {
*align = 8; // hidl_vec<T>
*size = assertion.size();
}
void VectorType::getAlignmentAndSize(size_t *align, size_t *size) const {
VectorType::getAlignmentAndSizeStatic(align, size);
}
} // namespace android