Merge "Install non-core HIDL in system_ext"
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 79d5ee7..82ea179 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -33,29 +33,28 @@
 
 CompoundType::CompoundType(Style style, const std::string& localName, const FQName& fullName,
                            const Location& location, Scope* parent)
-    : Scope(localName, fullName, location, parent), mStyle(style), mFields(nullptr) {}
+    : Scope(localName, fullName, location, parent), mStyle(style) {}
 
 CompoundType::Style CompoundType::style() const {
     return mStyle;
 }
 
-void CompoundType::setFields(std::vector<NamedReference<Type>*>* fields) {
-    mFields = fields;
+void CompoundType::addField(NamedReference<Type>* field) {
+    mFields.push_back(field);
 }
 
 std::vector<const NamedReference<Type>*> CompoundType::getFields() const {
-    return mFields ? std::vector<const NamedReference<Type>*>(mFields->begin(), mFields->end())
-                   : std::vector<const NamedReference<Type>*>();
+    return std::vector<const NamedReference<Type>*>(mFields.begin(), mFields.end());
 }
 
 std::vector<const Reference<Type>*> CompoundType::getReferences() const {
     std::vector<const Reference<Type>*> ret;
-    ret.insert(ret.begin(), mFields->begin(), mFields->end());
+    ret.insert(ret.begin(), mFields.begin(), mFields.end());
     return ret;
 }
 
 status_t CompoundType::validate() const {
-    for (const auto* field : *mFields) {
+    for (const auto* field : mFields) {
         const Type& type = field->type();
 
         if ((type.isVector() && static_cast<const VectorType*>(&type)->isVectorOfBinders())) {
@@ -79,7 +78,7 @@
         }
     }
 
-    if (mStyle == STYLE_SAFE_UNION && mFields->size() < 2) {
+    if (mStyle == STYLE_SAFE_UNION && mFields.size() < 2) {
         std::cerr << "ERROR: Safe union must contain at least two types to be useful at "
                   << location() << "\n";
         return UNKNOWN_ERROR;
@@ -97,7 +96,7 @@
 status_t CompoundType::validateUniqueNames() const {
     std::unordered_set<std::string> names;
 
-    for (const auto* field : *mFields) {
+    for (const auto* field : mFields) {
         if (names.find(field->name()) != names.end()) {
             std::cerr << "ERROR: Redefinition of field '" << field->name() << "' at "
                       << field->location() << "\n";
@@ -139,7 +138,7 @@
     if (mStyle == STYLE_UNION) {
         return false;
     }
-    for (const auto* field : *mFields) {
+    for (const auto* field : mFields) {
         if (!field->get()->canCheckEquality(visited)) {
             return false;
         }
@@ -203,7 +202,7 @@
 }
 
 bool CompoundType::containsInterface() const {
-    for (const auto& field : *mFields) {
+    for (const auto& field : mFields) {
         if (field->type().isCompoundType()) {
             const Type& t = field->type();
             const CompoundType* ct = static_cast<const CompoundType*>(&t);
@@ -263,60 +262,45 @@
             << "::hidl_discriminator) _hidl_d_primitive) ";
 
         out.block([&] {
-            for (const auto& field : *mFields) {
-                out << "case "
-                    << fullName()
-                    << "::hidl_discriminator::"
-                    << field->name()
-                    << ": ";
+               for (const auto& field : mFields) {
+                   out << "case " << fullName() << "::hidl_discriminator::" << field->name()
+                       << ": ";
 
-                const std::string tempFieldName = "_hidl_temp_" + field->name();
-                out.block([&] {
-                    if (isReader) {
-                        out << field->type().getCppResultType()
-                            << " "
-                            << tempFieldName
-                            << ";\n";
+                   const std::string tempFieldName = "_hidl_temp_" + field->name();
+                   out.block([&] {
+                          if (isReader) {
+                              out << field->type().getCppResultType() << " " << tempFieldName
+                                  << ";\n";
 
-                        field->type().emitReaderWriter(out, tempFieldName, parcelObj,
-                                                       parcelObjIsPointer, isReader, mode);
+                              field->type().emitReaderWriter(out, tempFieldName, parcelObj,
+                                                             parcelObjIsPointer, isReader, mode);
 
-                        const std::string derefOperator = field->type().resultNeedsDeref()
-                                                          ? "*" : "";
-                        out << name
-                            << "."
-                            << field->name()
-                            << "(std::move("
-                            << derefOperator
-                            << tempFieldName
-                            << "));\n";
-                    } else {
-                        const std::string fieldValue = name + "." + field->name() + "()";
-                        out << field->type().getCppArgumentType()
-                            << " "
-                            << tempFieldName
-                            << " = "
-                            << fieldValue
-                            << ";\n";
+                              const std::string derefOperator =
+                                      field->type().resultNeedsDeref() ? "*" : "";
+                              out << name << "." << field->name() << "(std::move(" << derefOperator
+                                  << tempFieldName << "));\n";
+                          } else {
+                              const std::string fieldValue = name + "." + field->name() + "()";
+                              out << field->type().getCppArgumentType() << " " << tempFieldName
+                                  << " = " << fieldValue << ";\n";
 
-                        field->type().emitReaderWriter(out, tempFieldName, parcelObj,
-                                                       parcelObjIsPointer, isReader, mode);
-                    }
-                    out << "break;\n";
-                }).endl();
-            }
+                              field->type().emitReaderWriter(out, tempFieldName, parcelObj,
+                                                             parcelObjIsPointer, isReader, mode);
+                          }
+                          out << "break;\n";
+                      }).endl();
+               }
 
-            out << "default: ";
-            out.block([&] {
-                   emitSafeUnionUnknownDiscriminatorError(out, "_hidl_d_primitive",
-                                                          !isReader /*fatal*/);
-                   if (isReader) {
-                       out << "_hidl_err = BAD_VALUE;\n";
-                       handleError(out, mode);
-                   }
-               })
-                .endl();
-        }).endl();
+               out << "default: ";
+               out.block([&] {
+                      emitSafeUnionUnknownDiscriminatorError(out, "_hidl_d_primitive",
+                                                             !isReader /*fatal*/);
+                      if (isReader) {
+                          out << "_hidl_err = BAD_VALUE;\n";
+                          handleError(out, mode);
+                      }
+                  }).endl();
+           }).endl();
     }).endl();
 }
 
@@ -339,7 +323,7 @@
             return;
         }
 
-        for (const auto& field : *mFields) {
+        for (const auto& field : mFields) {
             const std::string tempFieldName = "_hidl_temp_" + field->name();
             const std::string fieldValue = name + "." + field->name();
 
@@ -524,8 +508,8 @@
         << " ";
 
     out.block([&] {
-        for (size_t idx = 0; idx < mFields->size(); idx++) {
-            const auto& field = mFields->at(idx);
+        for (size_t idx = 0; idx < mFields.size(); idx++) {
+            const auto& field = mFields.at(idx);
 
             field->emitDocComment(out);
             out << field->name()
@@ -545,7 +529,7 @@
         << definedName() << "& operator=(" << definedName() << "&&);\n"          // Move assignment
         << definedName() << "& operator=(const " << definedName() << "&);\n\n";  // Copy assignment
 
-    for (const auto& field : *mFields) {
+    for (const auto& field : mFields) {
         // Setter (copy)
         out << "void "
             << field->name()
@@ -598,8 +582,7 @@
     out << "union hidl_union final {\n";
     out.indent();
 
-    for (const auto& field : *mFields) {
-
+    for (const auto& field : mFields) {
         size_t fieldAlign, fieldSize;
         field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
 
@@ -656,7 +639,7 @@
     out << typeName() << " ";
 
     std::set<FQName> namesDeclaredInScope;
-    for (const NamedReference<Type>* ref : *mFields) {
+    for (const NamedReference<Type>* ref : mFields) {
         if (ref->definedInline()) {
             const Type* type = ref->get();
             CHECK(type->isCompoundType()) << " only compound types can be defined inline";
@@ -676,13 +659,13 @@
     out.indent([&] {
         size_t preDeclaredTypesIdx = 0;
         size_t fieldIdx = 0;
-        while (preDeclaredTypesIdx < preDeclaredTypes.size() && fieldIdx < mFields->size()) {
+        while (preDeclaredTypesIdx < preDeclaredTypes.size() && fieldIdx < mFields.size()) {
             out << "\n";
             if (preDeclaredTypes.at(preDeclaredTypesIdx)->location() <
-                mFields->at(fieldIdx)->location()) {
+                mFields.at(fieldIdx)->location()) {
                 preDeclaredTypes.at(preDeclaredTypesIdx++)->emitHidlDefinition(out);
             } else {
-                emitFieldHidlDefinition(out, *mFields->at(fieldIdx++));
+                emitFieldHidlDefinition(out, *mFields.at(fieldIdx++));
             }
         }
 
@@ -691,9 +674,9 @@
             preDeclaredTypes.at(preDeclaredTypesIdx++)->emitHidlDefinition(out);
         }
 
-        while (fieldIdx < mFields->size()) {
+        while (fieldIdx < mFields.size()) {
             out << "\n";
-            emitFieldHidlDefinition(out, *mFields->at(fieldIdx++));
+            emitFieldHidlDefinition(out, *mFields.at(fieldIdx++));
         }
     });
     out << "}";
@@ -717,7 +700,7 @@
     Scope::emitTypeDeclarations(out);
 
     if (containsPointer()) {
-        for (const auto &field : *mFields) {
+        for (const auto& field : mFields) {
             field->emitDocComment(out);
             out << field->type().getCppStackType()
                 << " "
@@ -733,7 +716,7 @@
 
     for (int pass = 0; pass < 2; ++pass) {
         size_t offset = 0;
-        for (const auto &field : *mFields) {
+        for (const auto& field : mFields) {
             size_t fieldAlign, fieldSize;
             field->type().getAlignmentAndSize(&fieldAlign, &fieldSize);
 
@@ -794,10 +777,8 @@
 void CompoundType::emitPackageTypeDeclarations(Formatter& out) const {
     Scope::emitPackageTypeDeclarations(out);
 
-    out << "static inline std::string toString("
-        << getCppArgumentType()
-        << (mFields->empty() ? "" : " o")
-        << ");\n";
+    out << "static inline std::string toString(" << getCppArgumentType()
+        << (mFields.empty() ? "" : " o") << ");\n";
 
     if (canCheckEquality()) {
         out << "static inline bool operator==("
@@ -815,10 +796,8 @@
 void CompoundType::emitPackageTypeHeaderDefinitions(Formatter& out) const {
     Scope::emitPackageTypeHeaderDefinitions(out);
 
-    out << "static inline std::string toString("
-        << getCppArgumentType()
-        << (mFields->empty() ? "" : " o")
-        << ") ";
+    out << "static inline std::string toString(" << getCppArgumentType()
+        << (mFields.empty() ? "" : " o") << ") ";
 
     out.block([&] {
         // include toString for scalar types
@@ -831,7 +810,7 @@
             out.indent();
         }
 
-        for (const NamedReference<Type>* field : *mFields) {
+        for (const NamedReference<Type>* field : mFields) {
             if (mStyle == STYLE_SAFE_UNION) {
                 out << "case "
                     << fullName()
@@ -850,7 +829,7 @@
                 }).endl();
             } else {
                 out << "os += \"";
-                if (field != *(mFields->begin())) {
+                if (field != *(mFields.begin())) {
                     out << ", ";
                 }
                 out << "." << field->name() << " = \";\n";
@@ -873,9 +852,9 @@
     }).endl().endl();
 
     if (canCheckEquality()) {
-        out << "static inline bool operator==("
-            << getCppArgumentType() << " " << (mFields->empty() ? "/* lhs */" : "lhs") << ", "
-            << getCppArgumentType() << " " << (mFields->empty() ? "/* rhs */" : "rhs") << ") ";
+        out << "static inline bool operator==(" << getCppArgumentType() << " "
+            << (mFields.empty() ? "/* lhs */" : "lhs") << ", " << getCppArgumentType() << " "
+            << (mFields.empty() ? "/* rhs */" : "rhs") << ") ";
         out.block([&] {
             if (mStyle == STYLE_SAFE_UNION) {
                 out.sIf("lhs.getDiscriminator() != rhs.getDiscriminator()", [&] {
@@ -886,7 +865,7 @@
                 out.indent();
             }
 
-            for (const auto& field : *mFields) {
+            for (const auto& field : mFields) {
                 if (mStyle == STYLE_SAFE_UNION) {
                     out << "case "
                         << fullName()
@@ -1045,41 +1024,35 @@
             << ".hidl_d) ";
 
         out.block([&] {
-            for (const auto& field : *mFields) {
-                const std::string parameterFieldName = (parameterName + ".hidl_u." +
-                                                        field->name());
+               for (const auto& field : mFields) {
+                   const std::string parameterFieldName =
+                           (parameterName + ".hidl_u." + field->name());
 
-                const std::string argumentName = usesMoveSemantics
-                                                 ? ("std::move(" + parameterFieldName + ")")
-                                                 : parameterFieldName;
+                   const std::string argumentName =
+                           usesMoveSemantics ? ("std::move(" + parameterFieldName + ")")
+                                             : parameterFieldName;
 
-                out << "case hidl_discriminator::"
-                    << field->name()
-                    << ": ";
+                   out << "case hidl_discriminator::" << field->name() << ": ";
 
-                if (isCopyConstructor) {
-                    out.block([&] {
-                        emitSafeUnionFieldConstructor(out, field, argumentName);
-                        out << "break;\n";
-                    }).endl();
-                } else {
-                    out.block([&] {
-                        out << field->name()
-                            << "("
-                            << argumentName
-                            << ");\n"
-                            << "break;\n";
-                    }).endl();
-                }
-            }
+                   if (isCopyConstructor) {
+                       out.block([&] {
+                              emitSafeUnionFieldConstructor(out, field, argumentName);
+                              out << "break;\n";
+                          }).endl();
+                   } else {
+                       out.block([&] {
+                              out << field->name() << "(" << argumentName << ");\n"
+                                  << "break;\n";
+                          }).endl();
+                   }
+               }
 
-            out << "default: ";
-            out.block([&] {
-                   emitSafeUnionUnknownDiscriminatorError(out, parameterName + ".hidl_d",
-                                                          true /*fatal*/);
-               })
-                .endl();
-        }).endl();
+               out << "default: ";
+               out.block([&] {
+                      emitSafeUnionUnknownDiscriminatorError(out, parameterName + ".hidl_d",
+                                                             true /*fatal*/);
+                  }).endl();
+           }).endl();
 
         if (isCopyConstructor) {
             out << "\nhidl_d = "
@@ -1101,19 +1074,32 @@
             << fullName()
             << ", hidl_d) == 0, \"wrong offset\");\n";
 
+        const CompoundLayout layout = getCompoundAlignmentAndSize();
+
         if (!containsPointer()) {
-            CompoundLayout layout = getCompoundAlignmentAndSize();
-            out << "static_assert(offsetof("
-                << fullName()
-                << ", hidl_u) == "
-                << layout.innerStruct.offset
-                << ", \"wrong offset\");\n";
+            out << "static_assert(offsetof(" << fullName()
+                << ", hidl_u) == " << layout.innerStruct.offset << ", \"wrong offset\");\n";
         }
+
         out.endl();
 
-        CHECK(!mFields->empty());
-        out << "hidl_d = hidl_discriminator::" << mFields->at(0)->name() << ";\n";
-        emitSafeUnionFieldConstructor(out, mFields->at(0), "");
+        out << "::std::memset(&hidl_u, 0, sizeof(hidl_u));\n";
+
+        // union itself is zero'd when set
+        // padding after descriminator
+        size_t dpad = layout.innerStruct.offset - layout.discriminator.size;
+        emitPaddingZero(out, layout.discriminator.size /*offset*/, dpad /*size*/);
+
+        size_t innerStructEnd = layout.innerStruct.offset + layout.innerStruct.size;
+        // final padding of the struct
+        size_t fpad = layout.overall.size - innerStructEnd;
+        emitPaddingZero(out, innerStructEnd /*offset*/, fpad /*size*/);
+
+        out.endl();
+
+        CHECK(!mFields.empty());
+        out << "hidl_d = hidl_discriminator::" << mFields.at(0)->name() << ";\n";
+        emitSafeUnionFieldConstructor(out, mFields.at(0), "");
     }).endl().endl();
 
     // Destructor
@@ -1124,13 +1110,15 @@
     }).endl().endl();
 
     // Move constructor
-    out << fullName() << "::" << definedName() << "(" << definedName() << "&& other) ";
+    out << fullName() << "::" << definedName() << "(" << definedName()
+        << "&& other) : " << fullName() << "() ";
 
     emitSafeUnionCopyAndAssignDefinition(
             out, "other", true /* isCopyConstructor */, true /* usesMoveSemantics */);
 
     // Copy constructor
-    out << fullName() << "::" << definedName() << "(const " << definedName() << "& other) ";
+    out << fullName() << "::" << definedName() << "(const " << definedName()
+        << "& other) : " << fullName() << "() ";
 
     emitSafeUnionCopyAndAssignDefinition(
         out, "other", true /* isCopyConstructor */, false /* usesMoveSemantics */);
@@ -1159,28 +1147,26 @@
     out.block([&] {
         out << "switch (hidl_d) ";
         out.block([&] {
+               for (const auto& field : mFields) {
+                   out << "case hidl_discriminator::" << field->name() << ": ";
 
-            for (const auto& field : *mFields) {
-                out << "case hidl_discriminator::"
-                    << field->name()
-                    << ": ";
+                   out.block([&] {
+                          out << "::android::hardware::details::destructElement(&(hidl_u."
+                              << field->name() << "));\n"
+                              << "break;\n";
+                      }).endl();
+               }
 
-                out.block([&] {
-                    out << "::android::hardware::details::destructElement(&(hidl_u."
-                        << field->name()
-                        << "));\n"
-                        << "break;\n";
-                }).endl();
-            }
-
-            out << "default: ";
-            out.block(
-                   [&] { emitSafeUnionUnknownDiscriminatorError(out, "hidl_d", true /*fatal*/); })
+               out << "default: ";
+               out.block([&] {
+                      emitSafeUnionUnknownDiscriminatorError(out, "hidl_d", true /*fatal*/);
+                  }).endl();
+           })
+                .endl()
                 .endl();
-        }).endl().endl();
     }).endl().endl();
 
-    for (const NamedReference<Type>* field : *mFields) {
+    for (const NamedReference<Type>* field : mFields) {
         // Setter (copy)
         out << "void "
             << fullName()
@@ -1281,58 +1267,54 @@
     if (mStyle == STYLE_SAFE_UNION) {
         out << "public " << definedName() << "() ";
         out.block([&] {
-            CHECK(!mFields->empty());
-            mFields->at(0)->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
-        }).endl().endl();
+               CHECK(!mFields.empty());
+               mFields.at(0)->type().emitJavaFieldDefaultInitialValue(out, "hidl_o");
+           })
+                .endl()
+                .endl();
 
         const std::string discriminatorStorageType = (
                 getUnionDiscriminatorType()->getJavaType(false));
 
         out << "public static final class hidl_discriminator ";
         out.block([&] {
-            for (size_t idx = 0; idx < mFields->size(); idx++) {
-                const auto& field = mFields->at(idx);
+               for (size_t idx = 0; idx < mFields.size(); idx++) {
+                   const auto& field = mFields.at(idx);
 
-                field->emitDocComment(out);
-                out << "public static final "
-                    << discriminatorStorageType
-                    << " "
-                    << field->name()
-                    << " = "
-                    << idx
-                    << ";  // "
-                    << field->type().getJavaType(true /* forInitializer */)
-                    << "\n";
-            }
+                   field->emitDocComment(out);
+                   out << "public static final " << discriminatorStorageType << " " << field->name()
+                       << " = " << idx << ";  // "
+                       << field->type().getJavaType(true /* forInitializer */) << "\n";
+               }
 
-            out << "\n"
-                << "public static final String getName("
-                << discriminatorStorageType
-                << " value) ";
+               out << "\n"
+                   << "public static final String getName(" << discriminatorStorageType
+                   << " value) ";
 
-            out.block([&] {
-                out << "switch (value) ";
-                out.block([&] {
-                    for (size_t idx = 0; idx < mFields->size(); idx++) {
-                        const auto& field = mFields->at(idx);
+               out.block([&] {
+                      out << "switch (value) ";
+                      out.block([&] {
+                             for (size_t idx = 0; idx < mFields.size(); idx++) {
+                                 const auto& field = mFields.at(idx);
 
-                        out << "case "
-                            << idx
-                            << ": { return \""
-                            << field->name()
-                            << "\"; }\n";
-                    }
-                    out << "default: { return \"Unknown\"; }\n";
-                }).endl();
-            }).endl().endl();
+                                 out << "case " << idx << ": { return \"" << field->name()
+                                     << "\"; }\n";
+                             }
+                             out << "default: { return \"Unknown\"; }\n";
+                         }).endl();
+                  })
+                       .endl()
+                       .endl();
 
-            out << "private hidl_discriminator() {}\n";
-        }).endl().endl();
+               out << "private hidl_discriminator() {}\n";
+           })
+                .endl()
+                .endl();
 
         out << "private " << discriminatorStorageType << " hidl_d = 0;\n";
         out << "private Object hidl_o = null;\n";
 
-        for (const auto& field : *mFields) {
+        for (const auto& field : mFields) {
             // Setter
             out << "public void "
                 << field->name()
@@ -1397,7 +1379,7 @@
             << " getDiscriminator() { return hidl_d; }\n\n";
 
     } else {
-        for (const auto& field : *mFields) {
+        for (const auto& field : mFields) {
             field->emitDocComment(out);
 
             out << "public ";
@@ -1432,7 +1414,7 @@
                     out << "return false;\n";
                 }).endl();
             } else {
-                for (const auto &field : *mFields) {
+                for (const auto& field : mFields) {
                     std::string condition = (field->type().isScalar() || field->type().isEnum())
                         ? "this." + field->name() + " != other." + field->name()
                         : ("!android.os.HidlSupport.deepEquals(this." + field->name()
@@ -1453,7 +1435,7 @@
                     out << "android.os.HidlSupport.deepHashCode(this.hidl_o),\n"
                         << "java.util.Objects.hashCode(this.hidl_d)";
                 } else {
-                    out.join(mFields->begin(), mFields->end(), ", \n", [&] (const auto &field) {
+                    out.join(mFields.begin(), mFields.end(), ", \n", [&](const auto& field) {
                         out << "android.os.HidlSupport.deepHashCode(this." << field->name() << ")";
                     });
                 }
@@ -1476,7 +1458,7 @@
             out.indent();
         }
 
-        for (const auto &field : *mFields) {
+        for (const auto& field : mFields) {
             if (mStyle == STYLE_SAFE_UNION) {
                 out << "case hidl_discriminator."
                     << field->name()
@@ -1494,7 +1476,7 @@
             }
             else {
                 out << "builder.append(\"";
-                if (field != *(mFields->begin())) {
+                if (field != *(mFields.begin())) {
                     out << ", ";
                 }
                 out << "." << field->name() << " = \");\n";
@@ -1531,7 +1513,7 @@
             out.indent();
         }
 
-        for (const auto& field : *mFields) {
+        for (const auto& field : mFields) {
             if (mStyle == STYLE_SAFE_UNION) {
                 out << "case hidl_discriminator."
                     << field->name()
@@ -1616,8 +1598,7 @@
         }
 
         size_t offset = layout.innerStruct.offset;
-        for (const auto& field : *mFields) {
-
+        for (const auto& field : mFields) {
             if (mStyle == STYLE_SAFE_UNION) {
                 out << "case hidl_discriminator."
                     << field->name()
@@ -1669,7 +1650,7 @@
             out.indent();
         }
 
-        for (const auto& field : *mFields) {
+        for (const auto& field : mFields) {
             if (mStyle == STYLE_SAFE_UNION) {
                 out << "case hidl_discriminator."
                     << field->name()
@@ -1750,7 +1731,7 @@
         }
 
         size_t offset = layout.innerStruct.offset;
-        for (const auto& field : *mFields) {
+        for (const auto& field : mFields) {
             if (mStyle == STYLE_SAFE_UNION) {
                 out << "case hidl_discriminator."
                     << field->name()
@@ -1827,7 +1808,7 @@
         out.indent();
     }
 
-    for (const auto &field : *mFields) {
+    for (const auto& field : mFields) {
         if (!field->type().needsEmbeddedReadWrite()) {
             continue;
         }
@@ -1884,7 +1865,7 @@
         return false;
     }
 
-    for (const auto &field : *mFields) {
+    for (const auto& field : mFields) {
         if (field->type().needsEmbeddedReadWrite()) {
             return true;
         }
@@ -1931,7 +1912,7 @@
     }
 
     // Emit declaration for each field.
-    for (const auto &field : *mFields) {
+    for (const auto& field : mFields) {
         switch (mStyle) {
             case STYLE_STRUCT:
             {
@@ -1971,7 +1952,7 @@
         return false;
     }
 
-    for (const auto* field : *mFields) {
+    for (const auto* field : mFields) {
         if (!field->get()->isJavaCompatible(visited)) {
             return false;
         }
@@ -1981,7 +1962,7 @@
 }
 
 bool CompoundType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
-    for (const auto* field : *mFields) {
+    for (const auto* field : mFields) {
         if (field->get()->containsPointer(visited)) {
             return true;
         }
@@ -2011,8 +1992,7 @@
         innerStruct.offset = discriminator.size;
     }
 
-    for (const auto &field : *mFields) {
-
+    for (const auto& field : mFields) {
         // Each field is aligned according to its alignment requirement.
         // The surrounding structure's alignment is the maximum of its
         // fields' aligments.
@@ -2035,20 +2015,35 @@
     innerStruct.offset += Layout::getPad(innerStruct.offset,
                                          innerStruct.align);
 
-    overall.size = innerStruct.offset + innerStruct.size;
-
     // An empty struct/union still occupies a byte of space in C++.
-    if (overall.size == 0) {
-        overall.size = 1;
+    if (innerStruct.size == 0) {
+        innerStruct.size = 1;
     }
 
+    overall.size = innerStruct.offset + innerStruct.size;
+
     // Pad the overall structure's size
     overall.align = std::max(innerStruct.align, discriminator.align);
     overall.size += Layout::getPad(overall.size, overall.align);
 
+    if (mStyle != STYLE_SAFE_UNION) {
+        CHECK(overall.offset == innerStruct.offset) << overall.offset << " " << innerStruct.offset;
+        CHECK(overall.align == innerStruct.align) << overall.align << " " << innerStruct.align;
+        CHECK(overall.size == innerStruct.size) << overall.size << " " << innerStruct.size;
+    }
+
     return compoundLayout;
 }
 
+void CompoundType::emitPaddingZero(Formatter& out, size_t offset, size_t size) const {
+    if (size > 0) {
+        out << "::std::memset(reinterpret_cast<uint8_t*>(this) + " << offset << ", 0, " << size
+            << ");\n";
+    } else {
+        out << "// no padding to zero starting at offset " << offset << "\n";
+    }
+}
+
 std::unique_ptr<ScalarType> CompoundType::getUnionDiscriminatorType() const {
     static const std::vector<std::pair<int, ScalarType::Kind> > scalars {
         {8, ScalarType::Kind::KIND_UINT8},
@@ -2056,7 +2051,7 @@
         {32, ScalarType::Kind::KIND_UINT32},
     };
 
-    size_t numFields = mFields->size();
+    size_t numFields = mFields.size();
     auto kind = ScalarType::Kind::KIND_UINT64;
 
     for (const auto& scalar : scalars) {
diff --git a/CompoundType.h b/CompoundType.h
index 55968a4..566427c 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -39,7 +39,7 @@
     Style style() const;
 
     std::vector<const NamedReference<Type>*> getFields() const;
-    void setFields(std::vector<NamedReference<Type>*>* fields);
+    void addField(NamedReference<Type>* field);
 
     bool isCompoundType() const override;
 
@@ -137,13 +137,17 @@
     };
 
     struct CompoundLayout {
+        // Layout of this entire object including metadata.
+        // For struct/union, this is the same as innerStruct.
         Layout overall;
+        // Layout of user-specified data
         Layout innerStruct;
+        // Layout of discriminator for safe union (otherwise zero)
         Layout discriminator;
     };
 
     Style mStyle;
-    std::vector<NamedReference<Type>*>* mFields;
+    std::vector<NamedReference<Type>*> mFields;
 
     // only emits the struct body. doesn't emit the last ";\n" from the definition
     void emitInlineHidlDefinition(Formatter& out) const;
@@ -170,6 +174,7 @@
                                               bool usesMoveSemantics) const;
 
     CompoundLayout getCompoundAlignmentAndSize() const;
+    void emitPaddingZero(Formatter& out, size_t offset, size_t size) const;
 
     void emitSafeUnionReaderWriterForInterfaces(
             Formatter &out,
diff --git a/DocComment.cpp b/DocComment.cpp
index 2a1c981..02b7ab7 100644
--- a/DocComment.cpp
+++ b/DocComment.cpp
@@ -73,13 +73,13 @@
             break;
     }
 
-    out.setLinePrefix(" *");
+    out.pushLinePrefix(" *");
 
     for (const std::string& line : mLines) {
         out << (line.empty() ? "" : " ") << line << "\n";
     }
 
-    out.unsetLinePrefix();
+    out.popLinePrefix();
     out << " */\n";
 }
 
diff --git a/FmqType.cpp b/FmqType.cpp
index fa49928..37d771e 100644
--- a/FmqType.cpp
+++ b/FmqType.cpp
@@ -28,6 +28,10 @@
                  const std::string& definedName)
     : TemplatedType(parent, definedName), mNamespace(nsp), mName(name) {}
 
+bool FmqType::isFmq() const {
+    return true;
+}
+
 std::string FmqType::templatedTypeName() const {
     return mName;
 }
diff --git a/FmqType.h b/FmqType.h
index 92a7273..7d76546 100644
--- a/FmqType.h
+++ b/FmqType.h
@@ -28,8 +28,9 @@
     FmqType(const std::string& nsp, const std::string& name, Scope* parent,
             const std::string& definedName);
 
-    std::string fullName() const;
+    bool isFmq() const override;
 
+    std::string fullName() const;
     std::string templatedTypeName() const override;
 
     std::string getCppType(
diff --git a/Interface.cpp b/Interface.cpp
index 5510fec..0029f43 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -386,23 +386,23 @@
             {IMPL_INTERFACE,
                 [](auto &out) {
                     // getDebugInfo returns N/A for local objects.
-                    out << "_hidl_cb({ -1 /* pid */, 0 /* ptr */, \n"
-                        << sArch
-                        << "});\n"
-                        << "return ::android::hardware::Void();\n";
+                    out << "::android::hidl::base::V1_0::DebugInfo info = {};\n";
+                    out << "info.pid = -1;\n";
+                    out << "info.ptr = 0;\n";
+                    out << "info.arch = \n" << sArch << ";\n";
+                    out << "_hidl_cb(info);\n";
+                    out << "return ::android::hardware::Void();\n";
                 }
             },
             {IMPL_STUB_IMPL,
                 [](auto &out) {
-                    out << "_hidl_cb(";
-                    out.block([&] {
-                        out << "::android::hardware::details::getPidIfSharable(),\n"
-                            << "::android::hardware::details::debuggable()"
-                            << "? reinterpret_cast<uint64_t>(this) : 0 /* ptr */,\n"
-                            << sArch << "\n";
-                    });
-                    out << ");\n"
-                        << "return ::android::hardware::Void();\n";
+                    out << "::android::hidl::base::V1_0::DebugInfo info = {};\n";
+                    out << "info.pid = ::android::hardware::details::getPidIfSharable();\n";
+                    out << "info.ptr = ::android::hardware::details::debuggable()"
+                        << "? reinterpret_cast<uint64_t>(this) : 0;\n";
+                    out << "info.arch = \n" << sArch << ";\n";
+                    out << "_hidl_cb(info);\n";
+                    out << "return ::android::hardware::Void();\n";
                 }
             }
         }, /* cppImpl */
diff --git a/Type.cpp b/Type.cpp
index 80bce2a..5873cc0 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -94,6 +94,10 @@
     return false;
 }
 
+bool Type::isFmq() const {
+    return false;
+}
+
 Type* Type::resolve() {
     return const_cast<Type*>(static_cast<const Type*>(this)->resolve());
 }
diff --git a/Type.h b/Type.h
index 0ed120b..6ddd11d 100644
--- a/Type.h
+++ b/Type.h
@@ -56,6 +56,7 @@
     virtual bool isTemplatedType() const;
     virtual bool isTypeDef() const;
     virtual bool isVector() const;
+    virtual bool isFmq() const;
 
     // Resolves the type by unwrapping typedefs
     Type* resolve();
diff --git a/build/hidl_interface.go b/build/hidl_interface.go
index fa0896b..e94186b 100644
--- a/build/hidl_interface.go
+++ b/build/hidl_interface.go
@@ -605,16 +605,12 @@
 			Generated_headers:  []string{name.headersName()},
 			Shared_libs: concat(cppDependencies, []string{
 				"libhidlbase",
-				"libhidltransport",
-				"libhwbinder",
 				"liblog",
 				"libutils",
 				"libcutils",
 			}),
 			Export_shared_lib_headers: concat(cppDependencies, []string{
 				"libhidlbase",
-				"libhidltransport",
-				"libhwbinder",
 				"libutils",
 			}),
 			Export_generated_headers: []string{name.headersName()},
@@ -706,8 +702,6 @@
 			"libbase",
 			"libcutils",
 			"libhidlbase",
-			"libhidltransport",
-			"libhwbinder",
 			"liblog",
 			"libutils",
 		},
@@ -716,7 +710,6 @@
 		}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
 		Export_shared_lib_headers: []string{
 			"libhidlbase",
-			"libhidltransport",
 		},
 		Export_static_lib_headers: concat([]string{
 			"libhidladapter",
@@ -741,8 +734,6 @@
 			"libbase",
 			"libcutils",
 			"libhidlbase",
-			"libhidltransport",
-			"libhwbinder",
 			"liblog",
 			"libutils",
 		},
@@ -886,11 +877,13 @@
 }
 
 var doubleLoadablePackageNames = []string{
+	"android.frameworks.bufferhub@1.0",
 	"android.hardware.cas@1.0",
 	"android.hardware.cas.native@1.0",
 	"android.hardware.configstore@",
 	"android.hardware.drm@1.0",
 	"android.hardware.drm@1.1",
+	"android.hardware.drm@1.2",
 	"android.hardware.graphics.allocator@",
 	"android.hardware.graphics.bufferqueue@",
 	"android.hardware.media@",
@@ -911,7 +904,7 @@
 	return false
 }
 
-// packages in libhidltransport
+// packages in libhidlbase
 var coreDependencyPackageNames = []string{
 	"android.hidl.base@",
 	"android.hidl.manager@",
diff --git a/c2hal/Note.cpp b/c2hal/Note.cpp
index 292bb79..bbb841f 100644
--- a/c2hal/Note.cpp
+++ b/c2hal/Note.cpp
@@ -34,7 +34,7 @@
 }
 
 void Note::generateSource(Formatter &out) const {
-    out.setLinePrefix("//");
+    out.pushLinePrefix("//");
     out << "NOTE:\n";
 
     out.indent();
@@ -45,7 +45,7 @@
     }
     out.unindent();
 
-    out.unsetLinePrefix();
+    out.popLinePrefix();
     out << "\n";
 }
 
diff --git a/c2hal/test/Android.bp b/c2hal/test/Android.bp
index 104d405..722d1a8 100644
--- a/c2hal/test/Android.bp
+++ b/c2hal/test/Android.bp
@@ -73,8 +73,6 @@
     export_generated_headers: ["c2hal_test_genc++_headers"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
         "libcutils",
diff --git a/generateCppImpl.cpp b/generateCppImpl.cpp
index 278334d..bad6151 100644
--- a/generateCppImpl.cpp
+++ b/generateCppImpl.cpp
@@ -144,7 +144,7 @@
         generateStubImplMethod(out, baseName, method);
     });
 
-    out.setLinePrefix("//");
+    out.pushLinePrefix("//");
     out << iface->definedName() << "* ";
     generateFetchSymbol(out, iface->definedName());
     out << "(const char* /* name */) {\n";
@@ -152,7 +152,7 @@
     out << "return new " << baseName << "();\n";
     out.unindent();
     out << "}\n\n";
-    out.unsetLinePrefix();
+    out.popLinePrefix();
 
     out << "}  // namespace implementation\n";
     enterLeaveNamespace(out, false /* leave */);
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 6ff5cba..2975d12 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -296,7 +296,7 @@
 %type<type> named_struct_or_union_declaration named_enum_declaration
 %type<type> compound_declaration annotated_compound_declaration
 
-%type<field> field_declaration commentable_field_declaration
+%type<docCommentable> field_declaration commentable_field_declaration
 %type<fields> field_declarations struct_or_union_body
 %type<constantExpression> const_expr
 %type<enumValue> enum_value commentable_enum_value
@@ -336,6 +336,7 @@
     android::Annotation *annotation;
     std::vector<android::Annotation *> *annotations;
     android::DocComment* docComment;
+    android::DocCommentable* docCommentable;
 }
 
 %%
@@ -925,7 +926,6 @@
       {
           CHECK((*scope)->isCompoundType());
           CompoundType *container = static_cast<CompoundType *>(*scope);
-          container->setFields($4);
 
           leaveScope(ast, scope);
           ast->addScopedType(container, *scope);
@@ -938,15 +938,10 @@
     ;
 
 field_declarations
-    : /* empty */ { $$ = new std::vector<NamedReference<Type>*>; }
+    : /* empty */ { $$ = nullptr; }
     | field_declarations commentable_field_declaration
       {
-          $$ = $1;
-
-          // Compound declaration or error
-          if ($2 != nullptr) {
-              $$->push_back($2);
-          }
+          $$ = nullptr;
       }
     ;
 
@@ -965,14 +960,18 @@
           CHECK((*scope)->isCompoundType());
 
           std::string errorMsg;
-          auto style = static_cast<CompoundType *>(*scope)->style();
+          CompoundType* compoundType = static_cast<CompoundType *>(*scope);
+          auto style = compoundType->style();
 
           if (!isValidCompoundTypeField(style, $2, &errorMsg)) {
               std::cerr << "ERROR: " << errorMsg << " at "
                         << @2 << "\n";
               YYERROR;
           }
-          $$ = new NamedReference<Type>($2, *$1, convertYYLoc(@2, ast));
+
+          NamedReference<Type>* field = new NamedReference<Type>($2, *$1, convertYYLoc(@2, ast));
+          compoundType->addField(field);
+          $$ = field;
       }
     | annotated_compound_declaration ';'
       {
@@ -988,8 +987,8 @@
                         << @2 << "\n";
               YYERROR;
           }
-          // Returns fields only
-          $$ = nullptr;
+
+          $$ = $1;
       }
     ;
 
@@ -1149,4 +1148,3 @@
         const std::string &errstr) {
     std::cerr << "ERROR: " << errstr << " at " << where << "\n";
 }
-
diff --git a/hidl2aidl/AidlHelper.cpp b/hidl2aidl/AidlHelper.cpp
index ff809e4..5f84450 100644
--- a/hidl2aidl/AidlHelper.cpp
+++ b/hidl2aidl/AidlHelper.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <hidl-util/FQName.h>
 #include <hidl-util/Formatter.h>
@@ -32,6 +33,18 @@
 
 namespace android {
 
+Formatter* AidlHelper::notesFormatter = nullptr;
+
+Formatter& AidlHelper::notes() {
+    CHECK(notesFormatter != nullptr);
+    return *notesFormatter;
+}
+
+void AidlHelper::setNotes(Formatter* formatter) {
+    CHECK(formatter != nullptr);
+    notesFormatter = formatter;
+}
+
 std::string AidlHelper::getAidlName(const FQName& fqName) {
     std::vector<std::string> names;
     for (const std::string& name : fqName.names()) {
diff --git a/hidl2aidl/AidlHelper.h b/hidl2aidl/AidlHelper.h
index f4457d3..a6301e4 100644
--- a/hidl2aidl/AidlHelper.h
+++ b/hidl2aidl/AidlHelper.h
@@ -48,7 +48,7 @@
     static Formatter getFileWithHeader(const NamedType& namedType, const Coordinator& coordinator);
 
     /* Methods for Type */
-    static std::string getAidlType(const Type& type);
+    static std::string getAidlType(const Type& type, const FQName& relativeTo);
 
     /* Methods for NamedType */
     static void emitAidl(const NamedType& namedType, const Coordinator& coordinator);
@@ -60,6 +60,13 @@
     static void emitAidl(const Interface& interface, const Coordinator& coordinator);
     // Returns all methods that would exist in an AIDL equivalent interface
     static std::vector<const Method*> getUserDefinedMethods(const Interface& interface);
+
+    static Formatter& notes();
+    static void setNotes(Formatter* formatter);
+
+  private:
+    // This is the formatter to use for additional conversion output
+    static Formatter* notesFormatter;
 };
 
 }  // namespace android
diff --git a/hidl2aidl/AidlInterface.cpp b/hidl2aidl/AidlInterface.cpp
index 66f32ca..e6d6438 100644
--- a/hidl2aidl/AidlInterface.cpp
+++ b/hidl2aidl/AidlInterface.cpp
@@ -16,6 +16,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
+#include <android-base/strings.h>
 #include <hidl-util/FQName.h>
 #include <hidl-util/Formatter.h>
 #include <hidl-util/StringHelper.h>
@@ -24,7 +25,10 @@
 
 #include "AidlHelper.h"
 #include "Coordinator.h"
+#include "DocComment.h"
+#include "FormattingConstants.h"
 #include "Interface.h"
+#include "Location.h"
 #include "Method.h"
 #include "NamedType.h"
 #include "Reference.h"
@@ -32,11 +36,29 @@
 
 namespace android {
 
-static void emitAidlMethodParams(Formatter& out, const std::vector<NamedReference<Type>*> args,
-                                 const std::string& prefix) {
-    out.join(args.begin(), args.end(), ", ", [&](const NamedReference<Type>* arg) {
-        out << prefix << AidlHelper::getAidlType(*arg->get()) << " " << arg->name();
-    });
+static void emitAidlMethodParams(WrappedOutput* wrappedOutput,
+                                 const std::vector<NamedReference<Type>*> args,
+                                 const std::string& prefix, const std::string& attachToLast,
+                                 const Interface& iface) {
+    if (args.size() == 0) {
+        *wrappedOutput << attachToLast;
+        return;
+    }
+
+    for (size_t i = 0; i < args.size(); i++) {
+        const NamedReference<Type>* arg = args[i];
+        std::string out =
+                prefix + AidlHelper::getAidlType(*arg->get(), iface.fqName()) + " " + arg->name();
+        wrappedOutput->group([&] {
+            if (i != 0) wrappedOutput->printUnlessWrapped(" ");
+            *wrappedOutput << out;
+            if (i == args.size() - 1) {
+                if (!attachToLast.empty()) *wrappedOutput << attachToLast;
+            } else {
+                *wrappedOutput << ",";
+            }
+        });
+    }
 }
 
 std::vector<const Method*> AidlHelper::getUserDefinedMethods(const Interface& interface) {
@@ -96,6 +118,16 @@
     }
 }
 
+struct ResultTransformation {
+    enum class TransformType {
+        MOVED,    // Moved to the front of the method name
+        REMOVED,  // Removed the result
+    };
+
+    std::string resultName;
+    TransformType type;
+};
+
 void AidlHelper::emitAidl(const Interface& interface, const Coordinator& coordinator) {
     for (const NamedType* type : interface.getSubTypes()) {
         emitAidl(*type, coordinator);
@@ -135,14 +167,16 @@
 
         out.join(methodMap.begin(), methodMap.end(), "\n", [&](const auto& pair) {
             const Method* method = pair.second.method;
-            method->emitDocComment(out);
 
             std::vector<NamedReference<Type>*> results;
+            std::vector<ResultTransformation> transformations;
             for (NamedReference<Type>* res : method->results()) {
                 if (StringHelper::EndsWith(StringHelper::Uppercase(res->name()), "STATUS") ||
                     StringHelper::EndsWith(StringHelper::Uppercase(res->name()), "ERROR")) {
-                    out << "// Ignoring result " << res->get()->getJavaType() << " " << res->name()
-                        << " since AIDL has built in status types.\n";
+                    out << "// Ignoring result " << getAidlType(*res->get(), interface.fqName())
+                        << " " << res->name() << " since AIDL has built in status types.\n";
+                    transformations.emplace_back(ResultTransformation{
+                            res->name(), ResultTransformation::TransformType::REMOVED});
                 } else {
                     results.push_back(res);
                 }
@@ -155,26 +189,73 @@
 
             std::string returnType = "void";
             if (results.size() == 1) {
-                returnType = getAidlType(*results[0]->get());
+                returnType = getAidlType(*results[0]->get(), interface.fqName());
 
-                out << "// Adding return type to method instead of out param "
-                    << results[0]->get()->getJavaType() << " " << results[0]->name()
-                    << " since there is only one return value.\n";
+                out << "// Adding return type to method instead of out param " << returnType << " "
+                    << results[0]->name() << " since there is only one return value.\n";
+                transformations.emplace_back(ResultTransformation{
+                        results[0]->name(), ResultTransformation::TransformType::MOVED});
                 results.clear();
             }
 
-            if (method->isOneway()) out << "oneway ";
-            out << returnType << " " << pair.second.name << "(";
-            emitAidlMethodParams(out, method->args(), "in ");
+            if (method->getDocComment() != nullptr) {
+                std::vector<std::string> modifiedDocComment;
+                for (const std::string& line : method->getDocComment()->lines()) {
+                    std::vector<std::string> tokens = base::Split(line, " ");
+                    if (tokens.size() <= 1 || tokens[0] != "@return") {
+                        // unimportant line
+                        modifiedDocComment.emplace_back(line);
+                        continue;
+                    }
 
-            // Join these
-            if (!results.empty()) {
-                // TODO: Emit warning if a primitive is given as a out param.
-                if (!method->args().empty()) out << ", ";
-                emitAidlMethodParams(out, results, "out ");
+                    const std::string& res = tokens[1];
+                    bool transformed = false;
+                    for (const ResultTransformation& transform : transformations) {
+                        if (transform.resultName != res) continue;
+
+                        // Some transform was done to it
+                        if (transform.type == ResultTransformation::TransformType::MOVED) {
+                            // remove the name
+                            tokens.erase(++tokens.begin());
+                            transformed = true;
+                        } else {
+                            CHECK(transform.type == ResultTransformation::TransformType::REMOVED);
+                            tokens.insert(tokens.begin(), "The following return was removed\n");
+                            transformed = true;
+                        }
+                    }
+
+                    if (!transformed) {
+                        tokens.erase(tokens.begin());
+                        tokens.insert(tokens.begin(), "@param out");
+                    }
+
+                    modifiedDocComment.emplace_back(base::Join(tokens, " "));
+                }
+
+                DocComment(base::Join(modifiedDocComment, "\n"), HIDL_LOCATION_HERE).emit(out);
             }
 
-            out << ");\n";
+            WrappedOutput wrappedOutput(MAX_LINE_LENGTH);
+
+            if (method->isOneway()) wrappedOutput << "oneway ";
+            wrappedOutput << returnType << " " << pair.second.name << "(";
+
+            if (results.empty()) {
+                emitAidlMethodParams(&wrappedOutput, method->args(), /* prefix */ "in ",
+                                     /* attachToLast */ ");\n", interface);
+            } else {
+                emitAidlMethodParams(&wrappedOutput, method->args(), /* prefix */ "in ",
+                                     /* attachToLast */ ",", interface);
+                wrappedOutput.printUnlessWrapped(" ");
+
+                // TODO: Emit warning if a primitive is given as a out param.
+                if (!method->args().empty()) out << ", ";
+                emitAidlMethodParams(&wrappedOutput, results, /* prefix */ "out ",
+                                     /* attachToLast */ ");\n", interface);
+            }
+
+            out << wrappedOutput;
         });
     });
 }
diff --git a/hidl2aidl/AidlNamedType.cpp b/hidl2aidl/AidlNamedType.cpp
index 6bf35ca..63a0373 100644
--- a/hidl2aidl/AidlNamedType.cpp
+++ b/hidl2aidl/AidlNamedType.cpp
@@ -23,14 +23,24 @@
 
 namespace android {
 
+static void emitConversionNotes(Formatter& out, const NamedType& namedType) {
+    out << "// This is the HIDL definition of " << namedType.fqName().string() << "\n";
+    out.pushLinePrefix("// ");
+    namedType.emitHidlDefinition(out);
+    out.popLinePrefix();
+    out << "\n";
+}
+
 static void emitTypeDefAidlDefinition(Formatter& out, const TypeDef& typeDef) {
     out << "// Cannot convert typedef " << typeDef.referencedType()->definedName() << " "
         << typeDef.fqName().string() << " since AIDL does not support typedefs.\n";
+    emitConversionNotes(out, typeDef);
 }
 
 static void emitEnumAidlDefinition(Formatter& out, const EnumType& enumType) {
     out << "// Cannot convert enum " << enumType.fqName().string()
         << " since AIDL does not support enums.\n";
+    emitConversionNotes(out, enumType);
 }
 
 static void emitCompoundTypeAidlDefinition(Formatter& out, const CompoundType& compoundType,
@@ -45,12 +55,14 @@
         out.block([&] {
             for (const NamedReference<Type>* field : compoundType.getFields()) {
                 field->emitDocComment(out);
-                out << AidlHelper::getAidlType(*field->get()) << " " << field->name() << ";\n";
+                out << AidlHelper::getAidlType(*field->get(), compoundType.fqName()) << " "
+                    << field->name() << ";\n";
             }
         });
     } else {
         out << "{}\n";
-        out << "// FIXME: Add union/safe_union implementations";
+        out << "// Cannot convert unions/safe_unions since AIDL does not support them.\n";
+        emitConversionNotes(out, compoundType);
     }
     out << "\n\n";
 }
diff --git a/hidl2aidl/AidlType.cpp b/hidl2aidl/AidlType.cpp
index b982736..6a31e25 100644
--- a/hidl2aidl/AidlType.cpp
+++ b/hidl2aidl/AidlType.cpp
@@ -14,25 +14,43 @@
  * limitations under the License.
  */
 
+#include <hidl-util/FQName.h>
 #include <string>
 
 #include "AidlHelper.h"
+#include "FmqType.h"
 #include "NamedType.h"
 #include "Type.h"
 #include "VectorType.h"
 
 namespace android {
 
-std::string AidlHelper::getAidlType(const Type& type) {
+static std::string getPlaceholderType(const std::string& type) {
+    return "IBinder /* FIXME: " + type + " */";
+}
+
+std::string AidlHelper::getAidlType(const Type& type, const FQName& relativeTo) {
     if (type.isVector()) {
         const VectorType& vec = static_cast<const VectorType&>(type);
         const Type* elementType = vec.getElementType();
 
         // Aidl doesn't support List<*> for C++ and NDK backends
-        return AidlHelper::getAidlType(*elementType) + "[]";
+        return getAidlType(*elementType, relativeTo) + "[]";
     } else if (type.isNamedType()) {
         const NamedType& namedType = static_cast<const NamedType&>(type);
-        return AidlHelper::getAidlFQName(namedType.fqName());
+        if (getAidlPackage(relativeTo) == getAidlPackage(namedType.fqName())) {
+            return getAidlName(namedType.fqName());
+        } else {
+            return getAidlFQName(namedType.fqName());
+        }
+    } else if (type.isMemory()) {
+        return getPlaceholderType("memory");
+    } else if (type.isFmq()) {
+        const FmqType& fmq = static_cast<const FmqType&>(type);
+        return getPlaceholderType(fmq.templatedTypeName() + "<" +
+                                  getAidlType(*fmq.getElementType(), relativeTo) + ">");
+    } else if (type.isPointer()) {
+        return getPlaceholderType("pointer");
     } else {
         return type.getJavaType();
     }
diff --git a/hidl2aidl/main.cpp b/hidl2aidl/main.cpp
index bc9c440..2509a00 100644
--- a/hidl2aidl/main.cpp
+++ b/hidl2aidl/main.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <hidl-util/FQName.h>
 #include <hidl-util/Formatter.h>
 
@@ -25,6 +26,7 @@
 #include "AST.h"
 #include "AidlHelper.h"
 #include "Coordinator.h"
+#include "DocComment.h"
 
 using namespace android;
 
@@ -107,6 +109,27 @@
     return result;
 }
 
+static AST* parse(const Coordinator& coordinator, const FQName& target) {
+    AST* ast = coordinator.parse(target);
+    if (ast == nullptr) {
+        std::cerr << "ERROR: Could not parse " << target.name() << ". Aborting." << std::endl;
+        exit(1);
+    }
+
+    if (!ast->getUnhandledComments().empty()) {
+        AidlHelper::notes()
+                << "Unhandled comments from " << target.string()
+                << " follow. Consider using hidl-lint to locate these and fixup as many "
+                << "as possible.\n";
+        for (const DocComment* docComment : ast->getUnhandledComments()) {
+            docComment->emit(AidlHelper::notes());
+        }
+        AidlHelper::notes() << "\n";
+    }
+
+    return ast;
+}
+
 int main(int argc, char** argv) {
     const char* me = argv[0];
     if (argc == 1) {
@@ -208,16 +231,20 @@
             }
         }
 
+        // Set up AIDL conversion log
+        std::string aidlPackage = AidlHelper::getAidlPackage(fqName);
+        std::string aidlName = AidlHelper::getAidlName(fqName);
+        Formatter err = coordinator.getFormatter(
+                fqName, Coordinator::Location::DIRECT,
+                base::Join(base::Split(aidlPackage, "."), "/") + "/" +
+                        (aidlName.empty() ? "" : (aidlName + "-")) + "conversion.log");
+        AidlHelper::setNotes(&err);
+
         std::vector<const NamedType*> namedTypesInPackage;
         for (const FQName& target : targets) {
             if (target.name() != "types") continue;
 
-            AST* ast = coordinator.parse(target);
-            if (ast == nullptr) {
-                std::cerr << "ERROR: Could not parse " << target.name() << ". Aborting."
-                          << std::endl;
-                exit(1);
-            }
+            AST* ast = parse(coordinator, target);
 
             CHECK(!ast->isInterface());
 
@@ -240,12 +267,7 @@
         for (const FQName& target : targets) {
             if (target.name() == "types") continue;
 
-            AST* ast = coordinator.parse(target);
-            if (ast == nullptr) {
-                std::cerr << "ERROR: Could not parse " << target.name() << ". Aborting."
-                          << std::endl;
-                exit(1);
-            }
+            AST* ast = parse(coordinator, target);
 
             const Interface* iface = ast->getInterface();
             CHECK(iface);
diff --git a/hidl2aidl/test/1.0/IBar.hal b/hidl2aidl/test/1.0/IBar.hal
index 118ab56..b58f4d1 100644
--- a/hidl2aidl/test/1.0/IBar.hal
+++ b/hidl2aidl/test/1.0/IBar.hal
@@ -24,4 +24,6 @@
     };
 
     extraMethod(Inner inner);
+
+    fmqMethod(fmq_sync<bool> sync, fmq_unsync<int32_t> unsync) generates (pointer t);
 };
diff --git a/hidl2aidl/test/1.1/IFoo.hal b/hidl2aidl/test/1.1/IFoo.hal
index 0f36fc5..a04cced 100644
--- a/hidl2aidl/test/1.1/IFoo.hal
+++ b/hidl2aidl/test/1.1/IFoo.hal
@@ -27,6 +27,31 @@
     // Should take precedence over @1.0::someBar
     someBar_1_1(string a);
 
+    versionTest_(string a);
+    versionTest_two_(string a) generates (bool bl);
+
     useStruct() generates (BigStruct type);
     useImportedStruct(Outer outer);
+
+    /**
+     * @param mem memory
+     */
+    useMemory(memory mem);
+    shouldImportCorrectTypes() generates (vec<OnlyIn11> lst);
+
+    /**
+     * @return output output
+     */
+    oneOutput() generates (string output);
+
+    /**
+     * @return out1 out
+     * @return out2 out
+     */
+     multipleOutputs() generates (BigStruct out1, BigStruct out2);
+
+    /**
+     * @return status removed
+     */
+    removedOutput() generates (string status);
 };
diff --git a/hidl2aidl/test/2.0/IFoo.hal b/hidl2aidl/test/2.0/IFoo.hal
index d3e6ad4..8c2bbad 100644
--- a/hidl2aidl/test/2.0/IFoo.hal
+++ b/hidl2aidl/test/2.0/IFoo.hal
@@ -16,7 +16,11 @@
 
 package hidl2aidl@2.0;
 
+import @1.0::IFoo;
+
 /* This should go into a package called hidl2aidl2 */
 interface IFoo {
     oneway someFoo(int8_t a);
+
+    shouldImportExternalTypes(@1.0::IFoo foo);
 };
diff --git a/hidl2aidl/test/Android.bp b/hidl2aidl/test/Android.bp
index f722f8b..c841947 100644
--- a/hidl2aidl/test/Android.bp
+++ b/hidl2aidl/test/Android.bp
@@ -20,6 +20,7 @@
     cmd: "$(location hidl2aidl) -o $(genDir)/ " +
         "-rhidl2aidl:system/tools/hidl/hidl2aidl/test " +
         "hidl2aidl@1.0 hidl2aidl@2.0",
+    required: ["android.hidl.base@1.0"],
     srcs: [
         "1.0/IBar.hal",
         "1.0/IFoo.hal",
@@ -38,6 +39,7 @@
         "hidl2aidl/Outer.aidl",
         "hidl2aidl/OuterInner.aidl",
         "hidl2aidl/OverrideMe.aidl",
+        // "hidl2aidl/conversion.log",
         "hidl2aidl2/IFoo.aidl",
     ],
 }
diff --git a/host_utils/Formatter.cpp b/host_utils/Formatter.cpp
index 24d690c..c801cf7 100644
--- a/host_utils/Formatter.cpp
+++ b/host_utils/Formatter.cpp
@@ -19,6 +19,7 @@
 #include <assert.h>
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <string>
 #include <vector>
 
@@ -65,12 +66,12 @@
     return (*this) << "}";
 }
 
-void Formatter::setLinePrefix(const std::string &prefix) {
-    mLinePrefix = prefix;
+void Formatter::pushLinePrefix(const std::string& prefix) {
+    mLinePrefix.push_back(prefix);
 }
 
-void Formatter::unsetLinePrefix() {
-    mLinePrefix = "";
+void Formatter::popLinePrefix() {
+    mLinePrefix.pop_back();
 }
 
 Formatter &Formatter::endl() {
@@ -120,14 +121,16 @@
 Formatter& Formatter::operator<<(const std::string& out) {
     const size_t len = out.length();
     size_t start = 0;
+
+    const std::string& prefix = base::Join(mLinePrefix, "");
     while (start < len) {
         size_t pos = out.find('\n', start);
 
         if (pos == std::string::npos) {
             if (mCurrentPosition == 0) {
                 fprintf(mFile, "%*s", (int)(getIndentation()), "");
-                fprintf(mFile, "%s", mLinePrefix.c_str());
-                mCurrentPosition = getIndentation() + mLinePrefix.size();
+                fprintf(mFile, "%s", prefix.c_str());
+                mCurrentPosition = getIndentation() + prefix.size();
             }
 
             std::string sub = out.substr(start);
@@ -136,10 +139,10 @@
             break;
         }
 
-        if (mCurrentPosition == 0 && (pos > start || !mLinePrefix.empty())) {
+        if (mCurrentPosition == 0 && (pos > start || !prefix.empty())) {
             fprintf(mFile, "%*s", (int)(getIndentation()), "");
-            fprintf(mFile, "%s", mLinePrefix.c_str());
-            mCurrentPosition = getIndentation() + mLinePrefix.size();
+            fprintf(mFile, "%s", prefix.c_str());
+            mCurrentPosition = getIndentation() + prefix.size();
         }
 
         if (pos == start) {
@@ -157,7 +160,12 @@
 }
 
 void Formatter::printBlock(const WrappedOutput::Block& block, size_t lineLength) {
-    size_t lineStart = mCurrentPosition ?: (getIndentation() + mLinePrefix.size());
+    size_t prefixSize = 0;
+    for (const std::string& prefix : mLinePrefix) {
+        prefixSize += prefix.size();
+    }
+
+    size_t lineStart = mCurrentPosition ?: (getIndentation() + prefixSize);
     size_t blockSize = block.computeSize(false);
     if (blockSize + lineStart < lineLength) {
         block.print(*this, false);
@@ -166,7 +174,7 @@
 
     // Everything will not fit on this line. Try to fit it on the next line.
     blockSize = block.computeSize(true);
-    if ((blockSize + getIndentation() + mSpacesPerIndent + mLinePrefix.size()) < lineLength) {
+    if ((blockSize + getIndentation() + mSpacesPerIndent + prefixSize) < lineLength) {
         *this << "\n";
         indent();
 
diff --git a/host_utils/include/hidl-util/Formatter.h b/host_utils/include/hidl-util/Formatter.h
index 3c0e116..0364bd9 100644
--- a/host_utils/include/hidl-util/Formatter.h
+++ b/host_utils/include/hidl-util/Formatter.h
@@ -171,9 +171,10 @@
     // you want to start a // comment block, for example.
     // The prefix will be put before the indentation.
     // Will be effective the next time cursor is at the start of line.
-    void setLinePrefix(const std::string& prefix);
-    // Remove the line prefix.
-    void unsetLinePrefix();
+    // Adding two prefixes will output them in the order they were added
+    void pushLinePrefix(const std::string& prefix);
+    // Remove the last line prefix.
+    void popLinePrefix();
 
     bool isValid() const;
     size_t getIndentation() const;
@@ -187,7 +188,7 @@
     size_t mSpacesPerIndent;
     size_t mCurrentPosition;
 
-    std::string mLinePrefix;
+    std::vector<std::string> mLinePrefix;
 
     void printBlock(const WrappedOutput::Block& block, size_t lineLength);
     void output(const std::string &text) const;
diff --git a/lint/lints/methodDocComment.cpp b/lint/lints/methodDocComment.cpp
index 7f3ff7b..5a90e91 100644
--- a/lint/lints/methodDocComment.cpp
+++ b/lint/lints/methodDocComment.cpp
@@ -34,7 +34,7 @@
 // returns true if the line contained a prefix and false otherwise
 static bool getFirstWordAfterPrefix(const std::string& str, const std::string& prefix,
                                     std::string* out) {
-    std::string line = base::Trim(str);
+    std::string line = str;
     if (base::StartsWith(line, prefix)) {
         line = StringHelper::LTrim(line, prefix);
 
diff --git a/lint/lints/oneway.cpp b/lint/lints/oneway.cpp
index 0b372de..fca0e95 100644
--- a/lint/lints/oneway.cpp
+++ b/lint/lints/oneway.cpp
@@ -38,17 +38,13 @@
 // This function returns what kind of methods the interface contains
 static InterfaceMethodType getInterfaceOnewayType(const Interface& iface,
                                                   bool includeParentMethods) {
-    // Don't consider IBase since it is always mixed.
-    if (iface.isIBase()) {
-        return NONE;
-    }
-
     InterfaceMethodType onewayType = NONE;
 
     const std::vector<Method*>& methods = iface.userDefinedMethods();
     if (methods.empty()) {
-        CHECK(iface.superType() != nullptr);
-        return includeParentMethods ? getInterfaceOnewayType(*iface.superType(), true) : NONE;
+        return (iface.superType() != nullptr && includeParentMethods)
+                       ? getInterfaceOnewayType(*iface.superType(), true)
+                       : NONE;
     }
 
     for (auto method : methods) {
diff --git a/main.cpp b/main.cpp
index 6fd572d..038a2a9 100644
--- a/main.cpp
+++ b/main.cpp
@@ -465,7 +465,7 @@
 
 bool isSystemProcessSupportedPackage(const FQName& fqName) {
     // Technically, so is hidl IBase + IServiceManager, but
-    // these are part of libhidltransport.
+    // these are part of libhidlbase.
     return fqName.inPackage("android.hardware.graphics.common") ||
            fqName.inPackage("android.hardware.graphics.mapper") ||
            fqName.string() == "android.hardware.renderscript@1.0" ||
@@ -727,7 +727,6 @@
             << "shared_libs: [\n";
         out.indent([&] {
             out << "\"libhidlbase\",\n"
-                << "\"libhidltransport\",\n"
                 << "\"libutils\",\n"
                 << "\"" << makeLibraryName(packageFQName) << "\",\n";
 
diff --git a/test/cpp_impl_test/Android.bp b/test/cpp_impl_test/Android.bp
index 0d53fa5..803ab02 100644
--- a/test/cpp_impl_test/Android.bp
+++ b/test/cpp_impl_test/Android.bp
@@ -38,7 +38,6 @@
     generated_headers: ["hidl_cpp_impl_test_gen-headers"],
     shared_libs: [
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "android.hardware.tests.foo@1.0",
     ],
diff --git a/test/error_test/line_number_doc_comments/1.0/IFoo.hal b/test/error_test/line_number_doc_comments/1.0/IFoo.hal
new file mode 100644
index 0000000..2be328e
--- /dev/null
+++ b/test/error_test/line_number_doc_comments/1.0/IFoo.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+package test.line_number_doc_comments@1.0;
+
+/**
+ * This is a doc comment
+ */
+/*
+ * Different type of comment
+ */
+// Unhandled comment
+interface IFoo {
+    struct A {};
+
+    enum B : uint32_t {
+        C = 2, // bad (A is not an enum)
+        /* more unhandled stuff */
+        /** some more */
+    };
+
+    // The error is on the next line. Should say 35 in the output.
+    foo()
+};
diff --git a/test/error_test/line_number_doc_comments/1.0/required_error b/test/error_test/line_number_doc_comments/1.0/required_error
new file mode 100644
index 0000000..772b903
--- /dev/null
+++ b/test/error_test/line_number_doc_comments/1.0/required_error
@@ -0,0 +1 @@
+IFoo.hal:35.
\ No newline at end of file
diff --git a/test/format_test/1.0/IFoo.hal b/test/format_test/1.0/IFoo.hal
index 90c792a..56b5993 100644
--- a/test/format_test/1.0/IFoo.hal
+++ b/test/format_test/1.0/IFoo.hal
@@ -30,6 +30,9 @@
             int32_t c;
         } c;
 
+        /**
+         * This doc comment should show up
+         */
         struct Foo {};
 
         Foo b;
diff --git a/test/hidl_test/Android.bp b/test/hidl_test/Android.bp
index 63cce42..fcecd6d 100644
--- a/test/hidl_test/Android.bp
+++ b/test/hidl_test/Android.bp
@@ -10,8 +10,6 @@
         "libcutils",
         "libhidlbase",
         "libhidlmemory",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/test/hidl_test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
index ac28d22..9f0ec39 100644
--- a/test/hidl_test/hidl_test_client.cpp
+++ b/test/hidl_test/hidl_test_client.cpp
@@ -1689,6 +1689,9 @@
         //do nothing, this is expected
     }
 
+    // further calls fail
+    EXPECT_FAIL(dyingBaz->ping());
+
     std::unique_lock<std::mutex> lock(recipient->mutex);
     recipient->condition.wait_for(lock, std::chrono::milliseconds(100), [&recipient]() {
             return recipient->fired;
@@ -1849,31 +1852,44 @@
 
 TEST_F(HidlTest, InvalidTransactionTest) {
     using ::android::hardware::tests::bar::V1_0::BnHwBar;
-    using ::android::hardware::tests::bar::V1_0::BpHwBar;
     using ::android::hardware::IBinder;
     using ::android::hardware::Parcel;
-    using ::android::status_t;
-    using ::android::OK;
+
+    sp<IBinder> binder = ::android::hardware::toBinder(bar);
 
     Parcel request, reply;
-    sp<IBinder> binder;
-    status_t status = request.writeInterfaceToken(::android::hardware::tests::bar::V1_0::IBar::descriptor);
+    EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBar::descriptor));
+    EXPECT_EQ(::android::UNKNOWN_TRANSACTION, binder->transact(1234, request, &reply));
 
-    EXPECT_EQ(status, OK);
+    EXPECT_OK(bar->ping());  // still works
+}
 
-    if (mode == BINDERIZED) {
-        EXPECT_TRUE(bar->isRemote());
-        binder = ::android::hardware::toBinder<IBar>(bar);
-    } else {
-        // For a local test, just wrap the implementation with a BnHwBar
-        binder = new BnHwBar(bar);
-    }
+TEST_F(HidlTest, EmptyTransactionTest) {
+    using ::android::hardware::IBinder;
+    using ::android::hardware::Parcel;
+    using ::android::hardware::tests::bar::V1_0::BnHwBar;
 
-    status = binder->transact(1234, request, &reply);
+    sp<IBinder> binder = ::android::hardware::toBinder(bar);
 
-    EXPECT_EQ(status, ::android::UNKNOWN_TRANSACTION);
-    // Try another call, to make sure nothing is messed up
-    EXPECT_OK(bar->thisIsNew());
+    Parcel request, reply;
+    EXPECT_EQ(::android::BAD_TYPE, binder->transact(2 /*someBoolMethod*/, request, &reply));
+
+    EXPECT_OK(bar->ping());  // still works
+}
+
+TEST_F(HidlTest, WrongDescriptorTest) {
+    using ::android::hardware::IBinder;
+    using ::android::hardware::Parcel;
+    using ::android::hardware::tests::bar::V1_0::BnHwBar;
+
+    sp<IBinder> binder = ::android::hardware::toBinder(bar);
+
+    Parcel request, reply;
+    // wrong descriptor
+    EXPECT_EQ(::android::OK, request.writeInterfaceToken("not a real descriptor"));
+    EXPECT_EQ(::android::BAD_TYPE, binder->transact(2 /*someBoolMethod*/, request, &reply));
+
+    EXPECT_OK(bar->ping());  // still works
 }
 
 TEST_F(HidlTest, TwowayMethodOnewayEnabledTest) {
@@ -2066,6 +2082,49 @@
     }));
 }
 
+template <typename T>
+void testZeroInit(const std::string& header) {
+    uint8_t buf[sizeof(T)];
+    memset(buf, 0xFF, sizeof(buf));
+
+    T* t = new (buf) T;
+
+    for (size_t i = 0; i < sizeof(T); i++) {
+        EXPECT_EQ(0, buf[i]) << header << " at offset: " << i;
+    }
+
+    t->~T();
+    t = nullptr;
+
+    memset(buf, 0xFF, sizeof(buf));
+    t = new (buf) T(T());  // copy constructor
+
+    for (size_t i = 0; i < sizeof(T); i++) {
+        EXPECT_EQ(0, buf[i]) << header << " at offset: " << i;
+    }
+
+    t->~T();
+    t = nullptr;
+
+    memset(buf, 0xFF, sizeof(buf));
+    const T aT = T();
+    t = new (buf) T(std::move(aT));  // move constructor
+
+    for (size_t i = 0; i < sizeof(T); i++) {
+        EXPECT_EQ(0, buf[i]) << header << " at offset: " << i;
+    }
+
+    t->~T();
+    t = nullptr;
+}
+
+TEST_F(HidlTest, SafeUnionUninit) {
+    testZeroInit<SmallSafeUnion>("SmallSafeUnion");
+    testZeroInit<LargeSafeUnion>("LargeSafeUnion");
+    testZeroInit<InterfaceTypeSafeUnion>("InterfaceTypeSafeUnion");
+    testZeroInit<HandleTypeSafeUnion>("HandleTypeSafeUnion");
+}
+
 TEST_F(HidlTest, SafeUnionMoveConstructorTest) {
     sp<IOtherInterface> otherInterface = new OtherInterface();
     ASSERT_EQ(1, otherInterface->getStrongCount());
diff --git a/test/java_test/Android.bp b/test/java_test/Android.bp
index 4f18adf..87654aa 100644
--- a/test/java_test/Android.bp
+++ b/test/java_test/Android.bp
@@ -11,8 +11,6 @@
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libutils",
     ],
diff --git a/test/lazy_test/Android.bp b/test/lazy_test/Android.bp
index 8764b30..04acf6f 100644
--- a/test/lazy_test/Android.bp
+++ b/test/lazy_test/Android.bp
@@ -7,9 +7,7 @@
         "libbase",
         "liblog",
         "libhidlbase",
-        "libhidltransport",
         "libhidlmemory",
-        "libhwbinder",
         "libutils",
     ],
 }
diff --git a/test/lazy_test/main.cpp b/test/lazy_test/main.cpp
index 7126e85..48512e0 100644
--- a/test/lazy_test/main.cpp
+++ b/test/lazy_test/main.cpp
@@ -23,6 +23,7 @@
 
 #include <unistd.h>
 
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <gtest/gtest.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
@@ -30,8 +31,11 @@
 #include <hwbinder/IPCThreadState.h>
 
 using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
 using ::android::hardware::IPCThreadState;
 using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::manager::V1_2::IServiceManager;
 
 static std::string gDescriptor;
 static std::string gInstance;
@@ -41,12 +45,52 @@
                                                                true /*retry*/, false /*getStub*/);
 }
 
+class HidlLazyTest : public ::testing::Test {
+  protected:
+    sp<IServiceManager> manager;
+
+    void SetUp() override {
+        manager = IServiceManager::getService();
+        ASSERT_NE(manager, nullptr);
+
+        ASSERT_FALSE(isServiceRunning()) << "Service '" << gDescriptor << "/" << gInstance
+                                         << "' is already running. Please ensure this "
+                                         << "service is implemented as a lazy HAL, then kill all "
+                                         << "clients of this service and try again.";
+    }
+
+    static constexpr size_t SHUTDOWN_WAIT_TIME = 10;
+    void TearDown() override {
+        std::cout << "Waiting " << SHUTDOWN_WAIT_TIME << " seconds before checking that the "
+                  << "service has shut down." << std::endl;
+        IPCThreadState::self()->flushCommands();
+        sleep(SHUTDOWN_WAIT_TIME);
+        ASSERT_FALSE(isServiceRunning()) << "Service failed to shutdown.";
+    }
+
+    bool isServiceRunning() {
+        bool isRunning = false;
+        EXPECT_TRUE(
+                manager->listByInterface(gDescriptor,
+                                         [&isRunning](const hidl_vec<hidl_string>& instanceNames) {
+                                             for (const hidl_string& name : instanceNames) {
+                                                 if (name == gInstance) {
+                                                     isRunning = true;
+                                                     break;
+                                                 }
+                                             }
+                                         })
+                        .isOk());
+        return isRunning;
+    }
+};
+
 static constexpr size_t NUM_IMMEDIATE_GET_UNGETS = 100;
-TEST(LazyHidl, GetUnget) {
+TEST_F(HidlLazyTest, GetUnget) {
     for (size_t i = 0; i < NUM_IMMEDIATE_GET_UNGETS; i++) {
         IPCThreadState::self()->flushCommands();
         sp<IBase> hal = getHal();
-        ASSERT_NE(nullptr, hal.get());
+        ASSERT_NE(hal.get(), nullptr);
         EXPECT_TRUE(hal->ping().isOk());
     }
 }
@@ -69,7 +113,7 @@
         std::cout << "Thread waiting " << sleepTime << " while not holding HAL." << std::endl;
         sleep(sleepTime);
         sp<IBase> hal = getHal();
-        ASSERT_NE(nullptr, hal.get());
+        ASSERT_NE(hal.get(), nullptr);
         ASSERT_TRUE(hal->ping().isOk());
     }
 }
@@ -77,7 +121,7 @@
 static constexpr size_t NUM_TIMES_GET_UNGET = 5;
 static constexpr size_t MAX_WAITING_DURATION = 10;
 static constexpr size_t NUM_CONCURRENT_THREADS = 5;
-TEST(LazyHidl, GetWithWaitConcurrent) {
+TEST_F(HidlLazyTest, GetWithWaitConcurrent) {
     std::vector<std::vector<size_t>> threadWaitTimes(NUM_CONCURRENT_THREADS);
 
     for (size_t i = 0; i < threadWaitTimes.size(); i++) {
@@ -108,4 +152,4 @@
     gInstance = argv[2];
 
     return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}