Snap for 8730993 from baf3a81927ebaed887aca76d1a730b3c2376ad21 to mainline-tzdata3-release

Change-Id: Idaebb96152ca207a2c74e48b88ec9ca145a4c826
diff --git a/Android.bp b/Android.bp
index 7e09272..67a9edd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,7 +110,6 @@
         host: {
             srcs: [
                 "RuntimeInfo-host.cpp",
-                "VintfObjectRecovery.cpp",
             ],
         },
         android: {
@@ -118,11 +117,6 @@
                 "RuntimeInfo-target.cpp",
             ],
         },
-        recovery: {
-            srcs: [
-                "VintfObjectRecovery.cpp",
-            ],
-        },
     }
 }
 
diff --git a/AssembleVintf.cpp b/AssembleVintf.cpp
index 7b01c8d..81ac234 100644
--- a/AssembleVintf.cpp
+++ b/AssembleVintf.cpp
@@ -31,7 +31,6 @@
 #include <vintf/KernelConfigParser.h>
 #include <vintf/parse_string.h>
 #include <vintf/parse_xml.h>
-#include "constants-private.h"
 #include "utils.h"
 
 #define BUFFER_SIZE sysconf(_SC_PAGESIZE)
@@ -346,19 +345,7 @@
             std::cerr << error << "\n";
             return false;
         }
-        return true;
-    }
 
-    bool checkDeviceManifestNoKernelLevel(const HalManifest& manifest) {
-        if (manifest.level() != Level::UNSPECIFIED &&
-            manifest.level() >= details::kEnforceDeviceManifestNoKernelLevel &&
-            // Use manifest.kernel()->level() directly because inferredKernelLevel()
-            // reads manifest.level().
-            manifest.kernel().has_value() && manifest.kernel()->level() != Level::UNSPECIFIED) {
-            std::cerr << "Error: Device manifest with level " << manifest.level()
-                      << " must not set kernel level " << manifest.kernel()->level() << std::endl;
-            return false;
-        }
         return true;
     }
 
@@ -400,10 +387,6 @@
             if (!setDeviceManifestKernel(halManifest)) {
                 return false;
             }
-
-            if (!checkDeviceManifestNoKernelLevel(*halManifest)) {
-                return false;
-            }
         }
 
         if (halManifest->mType == SchemaType::FRAMEWORK) {
@@ -585,9 +568,7 @@
                               << std::endl;
                 }
             }
-            // No <kernel> tags to assemble at this point
-            const auto kernelLevel = Level::UNSPECIFIED;
-            builtMatrix = CompatibilityMatrix::combine(deviceLevel, kernelLevel, matrices, &error);
+            builtMatrix = CompatibilityMatrix::combine(deviceLevel, matrices, &error);
             matrix = builtMatrix.get();
 
             if (matrix == nullptr) {
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 582914f..f8d7d05 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -334,8 +334,7 @@
 }
 
 std::unique_ptr<CompatibilityMatrix> CompatibilityMatrix::combine(
-    Level deviceLevel, Level kernelLevel, std::vector<CompatibilityMatrix>* matrices,
-    std::string* error) {
+    Level deviceLevel, std::vector<CompatibilityMatrix>* matrices, std::string* error) {
     // Check type.
     for (const auto& e : *matrices) {
         if (e.type() != SchemaType::FRAMEWORK) {
@@ -364,12 +363,12 @@
 
     std::vector<std::string> parsedFiles;
     for (auto& e : *matrices) {
-        bool success = false;
         if (e.level() < deviceLevel) {
-            if (kernelLevel == Level::UNSPECIFIED) continue;
-            if (e.level() < kernelLevel) continue;
-            success = baseMatrix->addAllKernels(&e, error);
-        } else if (e.level() == deviceLevel) {
+            continue;
+        }
+
+        bool success = false;
+        if (e.level() == deviceLevel) {
             success = baseMatrix->addAll(&e, error);
         } else {
             success = baseMatrix->addAllAsOptional(&e, error);
diff --git a/HalManifest.cpp b/HalManifest.cpp
index eff62c4..3a9386a 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -184,7 +184,7 @@
                 names.insert(toFQNameString(e.package(), e.version()));
                 break;
             case HalFormat::AIDL:
-                names.insert(e.package() + "@" + aidlVersionToString(e.version()));
+                names.insert(e.package());
                 break;
         }
         return true;
diff --git a/ManifestInstance.cpp b/ManifestInstance.cpp
index a77e0f9..8b9a20f 100644
--- a/ManifestInstance.cpp
+++ b/ManifestInstance.cpp
@@ -79,14 +79,6 @@
     return mTransportArch.arch;
 }
 
-const std::optional<std::string> ManifestInstance::ip() const {
-    return mTransportArch.ip;
-}
-
-const std::optional<uint64_t> ManifestInstance::port() const {
-    return mTransportArch.port;
-}
-
 HalFormat ManifestInstance::format() const {
     return mHalFormat;
 }
diff --git a/OWNERS b/OWNERS
index 6ce06b4..d225637 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,3 @@
-# Bug component: 192869
 smoreland@google.com
 elsk@google.com
 malchev@google.com
diff --git a/RuntimeInfo-target.cpp b/RuntimeInfo-target.cpp
index 3ef5aaa..4e94ebb 100644
--- a/RuntimeInfo-target.cpp
+++ b/RuntimeInfo-target.cpp
@@ -42,7 +42,6 @@
 #define BUFFER_SIZE sysconf(_SC_PAGESIZE)
 
 static constexpr char kMainline[] = "-mainline-";
-static constexpr char kMainlineSuffix[] = "-mainline";
 
 namespace android {
 namespace vintf {
@@ -126,8 +125,7 @@
     mRuntimeInfo->mOsVersion = buf.version;
     mRuntimeInfo->mHardwareId = buf.machine;
 
-    mRuntimeInfo->mIsMainline = mRuntimeInfo->mOsRelease.find(kMainline) != std::string::npos ||
-                                android::base::EndsWith(mRuntimeInfo->mOsRelease, kMainlineSuffix);
+    mRuntimeInfo->mIsMainline = mRuntimeInfo->mOsRelease.find(kMainline) != std::string::npos;
 
     status_t err = RuntimeInfo::parseGkiKernelRelease(flags, mRuntimeInfo->mOsRelease,
                                                       &mRuntimeInfo->mKernel.mVersion,
diff --git a/TEST_MAPPING b/TEST_MAPPING
index a1607bd..9ec415d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -9,16 +9,5 @@
     {
       "name": "lshal_test"
     }
-  ],
-  "hwasan-postsubmit": [
-    {
-      "name": "libvintf_test"
-    },
-    {
-      "name": "vintf_object_test"
-    },
-    {
-      "name": "lshal_test"
-    }
   ]
 }
diff --git a/TransportArch.cpp b/TransportArch.cpp
index 83aeb94..19c1dcd 100644
--- a/TransportArch.cpp
+++ b/TransportArch.cpp
@@ -34,30 +34,20 @@
     switch (transport) {
         case Transport::EMPTY: // fallthrough
         case Transport::HWBINDER:
-            if (arch == Arch::ARCH_EMPTY && !ip.has_value() && !port.has_value()) {
+            if (arch == Arch::ARCH_EMPTY) {
                 return true;
             }
             if (error) {
-                *error += "Transport " + to_string(transport) +
-                          " requires empty ip and port attributes as well as empty arch attribute";
+                *error += "Transport " + to_string(transport) + " requires empty arch attribute";
             }
             return false;
 
         case Transport::PASSTHROUGH:
-            if (arch != Arch::ARCH_EMPTY && !ip.has_value() && !port.has_value()) {
+            if (arch != Arch::ARCH_EMPTY) {
                 return true;
             }
             if (error) {
-                *error += "Passthrough HALs requires arch attribute and no ip or port attributes";
-            }
-            return false;
-        case Transport::INET:
-            if (arch == Arch::ARCH_EMPTY && ip.has_value() && port.has_value()) {
-                return true;
-            }
-            if (error) {
-                *error += "Transport " + to_string(transport) +
-                          " requires ip and port attributes as well as empty arch attribute";
+                *error += "Passthrough HALs requires arch attribute";
             }
             return false;
     }
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 8d9df31..0a2b49c 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -30,7 +30,6 @@
 #include <hidl/metadata.h>
 
 #include "CompatibilityMatrix.h"
-#include "VintfObjectUtils.h"
 #include "constants-private.h"
 #include "parse_string.h"
 #include "parse_xml.h"
@@ -51,6 +50,29 @@
 static constexpr bool kIsTarget = false;
 #endif
 
+template <typename T, typename F>
+static std::shared_ptr<const T> Get(const char* id, LockedSharedPtr<T>* ptr,
+                                    const F& fetchAllInformation) {
+    std::unique_lock<std::mutex> _lock(ptr->mutex);
+    if (!ptr->fetchedOnce) {
+        LOG(INFO) << id << ": Reading VINTF information.";
+        ptr->object = std::make_unique<T>();
+        std::string error;
+        status_t status = fetchAllInformation(ptr->object.get(), &error);
+        if (status == OK) {
+            ptr->fetchedOnce = true;
+            LOG(INFO) << id << ": Successfully processed VINTF information";
+        } else {
+            // Doubled because a malformed error std::string might cause us to
+            // lose the status.
+            LOG(ERROR) << id << ": status from fetching VINTF information: " << status;
+            LOG(ERROR) << id << ": " << status << " VINTF parse error: " << error;
+            ptr->object = nullptr;  // frees the old object
+        }
+    }
+    return ptr->object;
+}
+
 static std::unique_ptr<FileSystem> createDefaultFileSystem() {
     std::unique_ptr<FileSystem> fileSystem;
     if (kIsTarget) {
@@ -114,17 +136,11 @@
     // To avoid deadlock, get device manifest before any locks.
     auto deviceManifest = getDeviceHalManifest();
 
-    std::string error;
-    auto kernelLevel = getKernelLevel(&error);
-    if (kernelLevel == Level::UNSPECIFIED) {
-        LOG(WARNING) << "getKernelLevel: " << error;
-    }
-
     std::unique_lock<std::mutex> _lock(mFrameworkCompatibilityMatrixMutex);
 
-    auto combined = Get(__func__, &mCombinedFrameworkMatrix,
-                        std::bind(&VintfObject::getCombinedFrameworkMatrix, this, deviceManifest,
-                                  kernelLevel, _1, _2));
+    auto combined =
+        Get(__func__, &mCombinedFrameworkMatrix,
+            std::bind(&VintfObject::getCombinedFrameworkMatrix, this, deviceManifest, _1, _2));
     if (combined != nullptr) {
         return combined;
     }
@@ -135,8 +151,8 @@
 }
 
 status_t VintfObject::getCombinedFrameworkMatrix(
-    const std::shared_ptr<const HalManifest>& deviceManifest, Level kernelLevel,
-    CompatibilityMatrix* out, std::string* error) {
+    const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out,
+    std::string* error) {
     std::vector<CompatibilityMatrix> matrixFragments;
     auto matrixFragmentsStatus = getAllFrameworkMatrixLevels(&matrixFragments, error);
     if (matrixFragmentsStatus != OK) {
@@ -184,7 +200,7 @@
         return NAME_NOT_FOUND;
     }
 
-    auto combined = CompatibilityMatrix::combine(deviceLevel, kernelLevel, &matrixFragments, error);
+    auto combined = CompatibilityMatrix::combine(deviceLevel, &matrixFragments, error);
     if (combined == nullptr) {
         return BAD_VALUE;
     }
@@ -193,18 +209,12 @@
 }
 
 // Load and combine all of the manifests in a directory
-// If forceSchemaType, all fragment manifests are coerced into manifest->type().
 status_t VintfObject::addDirectoryManifests(const std::string& directory, HalManifest* manifest,
-                                            bool forceSchemaType, std::string* error) {
+                                            std::string* error) {
     std::vector<std::string> fileNames;
     status_t err = getFileSystem()->listFiles(directory, &fileNames, error);
     // if the directory isn't there, that's okay
-    if (err == NAME_NOT_FOUND) {
-      if (error) {
-        error->clear();
-      }
-      return OK;
-    }
+    if (err == NAME_NOT_FOUND) return OK;
     if (err != OK) return err;
 
     for (const std::string& file : fileNames) {
@@ -214,10 +224,6 @@
         err = fetchOneHalManifest(directory + file, &fragmentManifest, error);
         if (err != OK) return err;
 
-        if (forceSchemaType) {
-            fragmentManifest.setType(manifest->type());
-        }
-
         if (!manifest->addAll(&fragmentManifest, error)) {
             if (error) {
                 error->insert(0, "Cannot add manifest fragment " + directory + file + ": ");
@@ -246,8 +252,7 @@
 
     if (vendorStatus == OK) {
         *out = std::move(vendorManifest);
-        status_t fragmentStatus = addDirectoryManifests(kVendorManifestFragmentDir, out,
-                                                        false /* forceSchemaType*/, error);
+        status_t fragmentStatus = addDirectoryManifests(kVendorManifestFragmentDir, out, error);
         if (fragmentStatus != OK) {
             return fragmentStatus;
         }
@@ -268,15 +273,13 @@
                 return UNKNOWN_ERROR;
             }
         }
-        return addDirectoryManifests(kOdmManifestFragmentDir, out, false /* forceSchemaType */,
-                                     error);
+        return addDirectoryManifests(kOdmManifestFragmentDir, out, error);
     }
 
     // vendorStatus != OK, "out" is not changed.
     if (odmStatus == OK) {
         *out = std::move(odmManifest);
-        return addDirectoryManifests(kOdmManifestFragmentDir, out, false /* forceSchemaType */,
-                                     error);
+        return addDirectoryManifests(kOdmManifestFragmentDir, out, error);
     }
 
     // Use legacy /vendor/manifest.xml
@@ -383,8 +386,7 @@
 status_t VintfObject::fetchUnfilteredFrameworkHalManifest(HalManifest* out, std::string* error) {
     auto systemEtcStatus = fetchOneHalManifest(kSystemManifest, out, error);
     if (systemEtcStatus == OK) {
-        auto dirStatus = addDirectoryManifests(kSystemManifestFragmentDir, out,
-                                               false /* forceSchemaType */, error);
+        auto dirStatus = addDirectoryManifests(kSystemManifestFragmentDir, out, error);
         if (dirStatus != OK) {
             return dirStatus;
         }
@@ -408,8 +410,7 @@
                 }
             }
 
-            auto fragmentStatus =
-                addDirectoryManifests(frags, out, false /* forceSchemaType */, error);
+            auto fragmentStatus = addDirectoryManifests(frags, out, error);
             if (fragmentStatus != OK) {
                 return fragmentStatus;
             }
@@ -489,9 +490,6 @@
         std::vector<std::string> fileNames;
         status_t listStatus = getFileSystem()->listFiles(dir, &fileNames, error);
         if (listStatus == NAME_NOT_FOUND) {
-            if (error) {
-              error->clear();
-            }
             continue;
         }
         if (listStatus != OK) {
@@ -862,11 +860,6 @@
         if (error) *error = "Device manifest does not specify Shipping FCM Version.";
         return BAD_VALUE;
     }
-    std::string kernelLevelError;
-    Level kernelLevel = getKernelLevel(&kernelLevelError);
-    if (kernelLevel == Level::UNSPECIFIED) {
-        LOG(WARNING) << kernelLevelError;
-    }
 
     std::vector<CompatibilityMatrix> targetMatrices;
     // Partition matrixFragments into two groups, where the second group
@@ -882,8 +875,7 @@
         return NAME_NOT_FOUND;
     }
     // so that they can be combined into one matrix for deprecation checking.
-    auto targetMatrix =
-        CompatibilityMatrix::combine(deviceLevel, kernelLevel, &targetMatrices, error);
+    auto targetMatrix = CompatibilityMatrix::combine(deviceLevel, &targetMatrices, error);
     if (targetMatrix == nullptr) {
         return BAD_VALUE;
     }
@@ -1231,30 +1223,26 @@
 }
 
 // make_unique does not work because VintfObject constructor is private.
-VintfObject::Builder::Builder()
-    : VintfObjectBuilder(std::unique_ptr<VintfObject>(new VintfObject())) {}
+VintfObject::Builder::Builder() : mObject(std::unique_ptr<VintfObject>(new VintfObject())) {}
 
-namespace details {
-
-VintfObjectBuilder::~VintfObjectBuilder() {}
-
-VintfObjectBuilder& VintfObjectBuilder::setFileSystem(std::unique_ptr<FileSystem>&& e) {
+VintfObject::Builder& VintfObject::Builder::setFileSystem(std::unique_ptr<FileSystem>&& e) {
     mObject->mFileSystem = std::move(e);
     return *this;
 }
 
-VintfObjectBuilder& VintfObjectBuilder::setRuntimeInfoFactory(
+VintfObject::Builder& VintfObject::Builder::setRuntimeInfoFactory(
     std::unique_ptr<ObjectFactory<RuntimeInfo>>&& e) {
     mObject->mRuntimeInfoFactory = std::move(e);
     return *this;
 }
 
-VintfObjectBuilder& VintfObjectBuilder::setPropertyFetcher(std::unique_ptr<PropertyFetcher>&& e) {
+VintfObject::Builder& VintfObject::Builder::setPropertyFetcher(
+    std::unique_ptr<PropertyFetcher>&& e) {
     mObject->mPropertyFetcher = std::move(e);
     return *this;
 }
 
-std::unique_ptr<VintfObject> VintfObjectBuilder::buildInternal() {
+std::unique_ptr<VintfObject> VintfObject::Builder::build() {
     if (!mObject->mFileSystem) mObject->mFileSystem = createDefaultFileSystem();
     if (!mObject->mRuntimeInfoFactory)
         mObject->mRuntimeInfoFactory = std::make_unique<ObjectFactory<RuntimeInfo>>();
@@ -1262,7 +1250,5 @@
     return std::move(mObject);
 }
 
-}  // namespace details
-
 }  // namespace vintf
 }  // namespace android
diff --git a/VintfObjectRecovery.cpp b/VintfObjectRecovery.cpp
deleted file mode 100644
index cc44e1e..0000000
--- a/VintfObjectRecovery.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 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 <vintf/VintfObjectRecovery.h>
-
-#include "VintfObjectUtils.h"
-#include "constants-private.h"
-
-using std::placeholders::_1;
-using std::placeholders::_2;
-
-namespace android::vintf {
-
-using details::Get;
-using details::kSystemManifest;
-using details::kSystemManifestFragmentDir;
-
-std::shared_ptr<VintfObjectRecovery> VintfObjectRecovery::GetInstance() {
-    static details::LockedSharedPtr<VintfObjectRecovery> sInstance{};
-    std::unique_lock<std::mutex> lock(sInstance.mutex);
-    if (sInstance.object == nullptr) {
-        std::unique_ptr<VintfObjectRecovery> uptr =
-            VintfObjectRecovery::Builder().build<VintfObjectRecovery>();
-        sInstance.object = std::shared_ptr<VintfObjectRecovery>(uptr.release());
-    }
-    return sInstance.object;
-}
-
-std::shared_ptr<const HalManifest> VintfObjectRecovery::getRecoveryHalManifest() {
-    return Get(__func__, &mRecoveryManifest,
-               std::bind(&VintfObjectRecovery::fetchRecoveryHalManifest, this, _1, _2));
-}
-
-// All manifests are installed under /system/etc/vintf.
-// There may be mixed framework and device manifests under that directory. Treat them all
-// as device manifest fragments.
-// Priority:
-// 1. /system/etc/vintf/manifest.xml
-//    + /system/etc/vintf/manifest/*.xml if they exist
-status_t VintfObjectRecovery::fetchRecoveryHalManifest(HalManifest* out, std::string* error) {
-    HalManifest manifest;
-    status_t systemEtcStatus = fetchOneHalManifest(kSystemManifest, &manifest, error);
-    if (systemEtcStatus != OK && systemEtcStatus != NAME_NOT_FOUND) {
-        return systemEtcStatus;
-    }
-    // Merge |manifest| to |out| only if the main manifest is found.
-    if (systemEtcStatus == OK) {
-        *out = std::move(manifest);
-    }
-    out->setType(SchemaType::DEVICE);
-    status_t fragmentStatus =
-        addDirectoryManifests(kSystemManifestFragmentDir, out, true /* forceSchemaType */, error);
-    if (fragmentStatus != OK) {
-        return fragmentStatus;
-    }
-    return OK;
-}
-
-VintfObjectRecovery::Builder::Builder()
-    : VintfObjectBuilder(std::unique_ptr<VintfObject>(new VintfObjectRecovery())) {}
-
-}  // namespace android::vintf
diff --git a/VintfObjectUtils.h b/VintfObjectUtils.h
deleted file mode 100644
index ac55200..0000000
--- a/VintfObjectUtils.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-// Special utils for VintfObject(s).
-
-#pragma once
-
-// This is okay because it is a header private to libvintf. Do not do this in exported headers!
-#include <android-base/logging.h>
-
-#include <vintf/VintfObject.h>
-
-namespace android {
-namespace vintf {
-namespace details {
-
-template <typename T, typename F>
-std::shared_ptr<const T> Get(const char* id, LockedSharedPtr<T>* ptr,
-                             const F& fetchAllInformation) {
-    std::unique_lock<std::mutex> _lock(ptr->mutex);
-    if (!ptr->fetchedOnce) {
-        LOG(INFO) << id << ": Reading VINTF information.";
-        ptr->object = std::make_unique<T>();
-        std::string error;
-        status_t status = fetchAllInformation(ptr->object.get(), &error);
-        if (status == OK) {
-            ptr->fetchedOnce = true;
-            LOG(INFO) << id << ": Successfully processed VINTF information";
-        } else {
-            // Doubled because a malformed error std::string might cause us to
-            // lose the status.
-            LOG(ERROR) << id << ": status from fetching VINTF information: " << status;
-            LOG(ERROR) << id << ": " << status << " VINTF parse error: " << error;
-            ptr->object = nullptr;  // frees the old object
-        }
-    }
-    return ptr->object;
-}
-
-}  // namespace details
-}  // namespace vintf
-}  // namespace android
diff --git a/analyze_matrix/hals_for_release.py b/analyze_matrix/hals_for_release.py
index f830c7b..fa94bb4 100755
--- a/analyze_matrix/hals_for_release.py
+++ b/analyze_matrix/hals_for_release.py
@@ -32,21 +32,16 @@
 import argparse
 import collections
 import enum
-import json
 import logging
 import os
 import subprocess
-from collections.abc import Sequence
-from typing import Any
-from typing import Optional
-
 import sys
 
 logging.basicConfig(format="%(levelname)s: %(message)s")
 logger = logging.getLogger(__name__)
 
 
-def ParseArgs() -> argparse.Namespace:
+def ParseArgs():
   """
   Parse arguments.
   :return: arguments.
@@ -74,7 +69,6 @@
                       help="Only print HALs where package contains the given substring. "
                            "E.g. wifi, usb, health. Recommend to use with --unchanged.")
   parser.add_argument("--verbose", "-v", action="store_true", help="Verbose mode")
-  parser.add_argument("--json", "-j", action="store_true", help="Print JSON")
   args = parser.parse_args()
 
   if args.verbose:
@@ -108,8 +102,7 @@
   return args
 
 
-def Analyze(analyze_matrix: str, file: str, args: Sequence[str],
-    ignore_errors=False) -> str:
+def Analyze(analyze_matrix, file, args, ignore_errors=False):
   """
   Run analyze_matrix with
   :param analyze_matrix: path of analyze_matrix
@@ -129,7 +122,7 @@
   return proc.stdout.decode().strip()
 
 
-def GetLevel(analyze_matrix: str, file: str) -> Optional[int]:
+def GetLevel(analyze_matrix, file):
   """
   :param analyze_matrix: Path of analyze_matrix
   :param file: a file, possibly a compatibility matrix
@@ -148,7 +141,7 @@
     return None
 
 
-def GetLevelName(analyze_matrix: str, file: str) -> str:
+def GetLevelName(analyze_matrix, file):
   """
   :param analyze_matrix: Path of analyze_matrix
   :param file: a file, possibly a compatibility matrix
@@ -159,17 +152,7 @@
   return Analyze(analyze_matrix, file, ["--level-name"], ignore_errors=True)
 
 
-class MatrixData(object):
-  def __init__(self, level: str, level_name: str, instances: Sequence[str]):
-    self.level = level
-    self.level_name = level_name
-    self.instances = instances
-
-  def GetInstancesKeyedOnPackage(self) -> dict[str, list[str]]:
-    return KeyOnPackage(self.instances)
-
-
-def ReadMatrices(args: argparse.Namespace) -> dict[int, MatrixData]:
+def ReadMatrices(args):
   """
   :param args: parsed arguments from ParseArgs
   :return: A dictionary. Key is an integer indicating the matrix level.
@@ -188,7 +171,7 @@
     if level in matrices:
       logger.warning("Found duplicated matrix for level %s, ignoring: %s", level, file)
       continue
-    matrices[level] = MatrixData(level, level_name, instances)
+    matrices[level] = (level_name, instances)
 
   return matrices
 
@@ -198,7 +181,7 @@
   AIDL = 2
 
 
-def GetHalFormat(instance: str) -> HalFormat:
+def GetHalFormat(instance):
   """
   Guess the HAL format of instance.
   :param instance: two formats:
@@ -214,7 +197,7 @@
   return HalFormat.HIDL if "::" in instance else HalFormat.AIDL
 
 
-def SplitInstance(instance: str) -> tuple[str, str, str]:
+def SplitInstance(instance):
   """
   Split instance into parts.
   :param instance:
@@ -239,7 +222,7 @@
     return instance[:dotPos], instance[dotPos + 1:spacePos], instance[spacePos + 1:]
 
 
-def GetPackage(instance: str) -> str:
+def GetPackage(instance):
   """
   Guess the package of instance.
   :param instance: two formats:
@@ -255,7 +238,7 @@
   return SplitInstance(instance)[0]
 
 
-def KeyOnPackage(instances: Sequence[str]) -> dict[str, list[str]]:
+def KeyOnPackage(instances):
   """
   :param instances: A list of instances.
   :return: A dictionary, where key is the package (see GetPackage), and
@@ -269,154 +252,67 @@
   return d
 
 
-class Report(object):
+def GetReport(tuple1, tuple2, args):
   """
-  Base class for generating a report.
+  :param tuple1: (level, (level_name, Set of instances from the first matrix))
+  :param tuple2: (level, (level_name, Set of instances from the second matrix))
+  :return: A human-readable report of their difference.
   """
-  def __init__(self, matrixData1: MatrixData, matrixData2: MatrixData, args: argparse.Namespace):
-    """
-    Initialize the report with two matrices.
-    :param matrixData1: Data of the old matrix
-    :param matrixData2: Data of the new matrix
-    :param args: command-line arguments
-    """
-    self.args = args
-    self.matrixData1 = matrixData1
-    self.matrixData2 = matrixData2
-    self.instances_by_package1 = matrixData1.GetInstancesKeyedOnPackage()
-    self.instances_by_package2 = matrixData2.GetInstancesKeyedOnPackage()
-    self.all_packages = set(self.instances_by_package1.keys()) | set(
-      self.instances_by_package2.keys())
+  level1, (level_name1, instances1) = tuple1
+  level2, (level_name2, instances2) = tuple2
 
-  def GetReport(self) -> Any:
-    """
-    Generate the report
-    :return: An object representing the report. Type is implementation defined.
-    """
-    packages_report: dict[str, Any] = dict()
-    for package in self.all_packages:
-      package_instances1 = set(self.instances_by_package1.get(package, []))
-      package_instances2 = set(self.instances_by_package2.get(package, []))
-      deprecated = sorted(package_instances1 - package_instances2)
-      unchanged = sorted(package_instances1 & package_instances2)
-      introduced = sorted(package_instances2 - package_instances1)
-      package_report = self.DescribePackage(deprecated=deprecated,
-                                            unchanged=unchanged,
-                                            introduced=introduced)
-      if package_report:
-        packages_report[package] = package_report
-    return self.CombineReport(packages_report)
+  instances_by_package1 = KeyOnPackage(instances1)
+  instances_by_package2 = KeyOnPackage(instances2)
+  all_packages = set(instances_by_package1.keys()) | set(instances_by_package2.keys())
 
-  def DescribePackage(self, deprecated: Sequence[str], unchanged: Sequence[str],
-      introduced: Sequence[str]) -> Any:
-    """
-    Describe a package in a implementation-defined format, with the given
-    set of changes.
-    :param deprecated: set of deprecated HALs
-    :param unchanged:  set of unchanged HALs
-    :param introduced: set of new HALs
-    :return: An object that will later be passed into the values of the
-      packages_report argument of CombineReport
-    """
-    raise NotImplementedError
+  if args.packages:
+    package_matches = lambda package: any(pattern in package for pattern in args.packages)
+    all_packages = filter(package_matches, all_packages)
 
-  def CombineReport(self, packages_report: dict[str, Any]) -> Any:
-    """
-    Combine a set of reports for a package in an implementation-defined way.
-    :param packages_report: A dictionary, where key is the package
-      name, and value is the object generated by DescribePackage
-    :return: the report object
-    """
-    raise NotImplementedError
+  packages_report = dict()
+  for package in all_packages:
+    package_instances1 = set(instances_by_package1.get(package, []))
+    package_instances2 = set(instances_by_package2.get(package, []))
 
-
-class HumanReadableReport(Report):
-  def DescribePackage(self, deprecated: Sequence[str], unchanged: Sequence[str],
-      introduced: Sequence[str]) -> Any:
     package_report = []
-    desc = lambda fmt, instance: fmt.format(GetHalFormat(instance).name,
-                                            *SplitInstance(instance))
-    if self.args.deprecated:
+    deprecated = sorted(package_instances1 - package_instances2)
+    unchanged = sorted(package_instances1 & package_instances2)
+    introduced = sorted(package_instances2 - package_instances1)
+
+    desc = lambda fmt, instance: fmt.format(GetHalFormat(instance).name, *SplitInstance(instance))
+
+    if args.deprecated:
       package_report += [desc("- {0} {2} can no longer be used", instance)
                          for instance in deprecated]
-    if self.args.unchanged:
-      package_report += [desc("  {0} {2} is {3}", instance) for instance in
-                         unchanged]
-    if self.args.introduced:
-      package_report += [desc("+ {0} {2} is {3}", instance) for instance in
-                         introduced]
+    if args.unchanged:
+      package_report += [desc("  {0} {2} is {3}", instance) for instance in unchanged]
+    if args.introduced:
+      package_report += [desc("+ {0} {2} is {3}", instance) for instance in introduced]
 
-    return package_report
+    if package_report:
+      packages_report[package] = package_report
 
-  def CombineReport(self, packages_report: dict[str, Any]) -> str:
-    report = ["============",
-              "Level %s (%s) (against Level %s (%s))" % (
-              self.matrixData2.level, self.matrixData2.level_name,
-              self.matrixData1.level, self.matrixData1.level_name),
-              "============"]
-    for package, lines in sorted(packages_report.items()):
-      report.append(package)
-      report += [("    " + e) for e in lines]
+  report = ["============",
+            "Level %s (%s) (against Level %s (%s))" % (level2, level_name2, level1, level_name1),
+            "============"]
+  for package, lines in sorted(packages_report.items()):
+    report.append(package)
+    report += [("    " + e) for e in lines]
 
-    return "\n".join(report)
-
-
-class JsonReport(Report):
-  def DescribePackage(self, deprecated: Sequence[str], unchanged: Sequence[str],
-      introduced: Sequence[str]) -> Any:
-    package_report = collections.defaultdict(list)
-    if self.args.deprecated and deprecated:
-      package_report["deprecated"] += deprecated
-    if self.args.unchanged and unchanged:
-      package_report["unchanged"] += unchanged
-    if self.args.introduced and introduced:
-      package_report["introduced"] += introduced
-
-    return package_report
-
-  def CombineReport(self, packages_report: dict[str, Any]) -> dict[str, Any]:
-    final = collections.defaultdict(list)
-    for package_report in packages_report.values():
-      for key, lst in package_report.items():
-        final[key] += lst
-    final["__meta__"] = {
-        "old": {"level": self.matrixData1.level,
-                "level_name": self.matrixData1.level_name},
-        "new": {"level": self.matrixData2.level,
-                "level_name": self.matrixData2.level_name},
-    }
-    return final
-
-
-def PrintReport(matrices: dict[int, MatrixData], args: argparse.Namespace):
-  """
-  :param matrixData1: data of first matrix
-  :param matrixData2: data of second matrix
-  :return: A report of their difference.
-  """
-  sorted_matrices = sorted(matrices.items())
-  if not sorted_matrices:
-    logger.warning("Nothing to show, because no matrices found in '%s'.", args.input)
-
-  if args.json:
-    reports = []
-    for (level1, matrixData1), (level2, matrixData2) in zip(sorted_matrices, sorted_matrices[1:]):
-      reports.append(JsonReport(matrixData1, matrixData2, args).GetReport())
-    print(json.dumps(reports))
-    return
-
-  for (level1, matrixData1), (level2, matrixData2) in zip(sorted_matrices, sorted_matrices[1:]):
-    report = HumanReadableReport(matrixData1, matrixData2, args)
-    print(report.GetReport())
+  return "\n".join(report)
 
 
 def main():
-  sys.stderr.write("Generated with %s\n" % " ".join(sys.argv))
+  print("Generated with %s" % " ".join(sys.argv))
   args = ParseArgs()
   if args is None:
     return 1
   matrices = ReadMatrices(args)
-  PrintReport(matrices, args)
+  sorted_matrices = sorted(matrices.items())
+  if not sorted_matrices:
+    logger.warning("Nothing to show, because no matrices found in '%s'.", args.input)
+  for tuple1, tuple2 in zip(sorted_matrices, sorted_matrices[1:]):
+    print(GetReport(tuple1, tuple2, args))
   return 0
 
 
diff --git a/check_vintf.cpp b/check_vintf.cpp
index 163ba47..2e322a6 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -118,7 +118,7 @@
         if (flags & RuntimeInfo::FetchFlag::CONFIG_GZ) {
             std::string content;
             if (!android::base::ReadFileToString(kernelConfigFile, &content)) {
-                LOG(ERROR) << "ERROR: Cannot read " << kernelConfigFile;
+                LOG(ERROR) << "Cannot read " << kernelConfigFile;
                 return UNKNOWN_ERROR;
             }
             KernelConfigParser parser;
@@ -156,13 +156,13 @@
     std::string error;
     status_t err = fileSystem->fetch(path, &xml, &error);
     if (err != OK) {
-        LOG(ERROR) << "ERROR: Cannot read '" << path << "' (" << strerror(-err) << "): " << error;
+        LOG(ERROR) << "Cannot read '" << path << "' (" << strerror(-err) << "): " << error;
         return nullptr;
     }
     auto ret = std::make_unique<T>();
     ret->setFileName(path);
     if (!fromXml(ret.get(), xml, &error)) {
-        LOG(ERROR) << "ERROR: Cannot parse '" << path << "': " << error;
+        LOG(ERROR) << "Cannot parse '" << path << "': " << error;
         return nullptr;
     }
     return ret;
@@ -178,7 +178,7 @@
 
     std::string error;
     if (!manifest->checkCompatibility(*matrix, &error)) {
-        LOG(ERROR) << "ERROR: Incompatible: " << error;
+        LOG(ERROR) << "Incompatible: " << error;
         std::cout << "false" << std::endl;
         return 1;
     }
@@ -220,7 +220,7 @@
     }
     if (optind < argc) {
         // see non option
-        LOG(ERROR) << "ERROR: unrecognized option `" << argv[optind] << "'";
+        LOG(ERROR) << "unrecognized option `" << argv[optind] << "'";
         return {{HELP, ""}};
     }
     return ret;
@@ -278,7 +278,7 @@
         LOG(INFO) << "Successfully parsed content of " << s << ": " << content;
         return true;
     }
-    LOG(ERROR) << "ERROR: Cannot parse content of " << s << ": " << content;
+    LOG(ERROR) << "Cannot parse content of " << s << ": " << content;
     return false;
 }
 
@@ -286,13 +286,13 @@
 std::shared_ptr<StaticRuntimeInfo> getRuntimeInfo(const T& args) {
     auto ret = std::make_shared<StaticRuntimeInfo>();
     if (std::distance(args.begin(), args.end()) > 1) {
-        LOG(ERROR) << "ERROR: Can't have multiple --kernel options";
+        LOG(ERROR) << "Can't have multiple --kernel options";
         return nullptr;
     }
     const auto& arg = *args.begin();
     auto colonPos = arg.rfind(":");
     if (colonPos == std::string::npos) {
-        LOG(ERROR) << "ERROR: Invalid --kernel";
+        LOG(ERROR) << "Invalid --kernel";
         return nullptr;
     }
 
@@ -358,11 +358,6 @@
             LOG(WARNING) << "Unable to print HALs from new FCMs: no device HAL manifest.";
             return;
         }
-        std::string kernelLevelError;
-        auto kernelLevel = vintfObject->getKernelLevel(&kernelLevelError);
-        if (kernelLevel == Level::UNSPECIFIED) {
-            LOG(WARNING) << "getKernelLevel: " << kernelLevel;
-        }
         std::vector<CompatibilityMatrix> matrixFragments;
         std::string error;
         auto status = vintfObject->getAllFrameworkMatrixLevels(&matrixFragments, &error);
@@ -377,8 +372,8 @@
                                             matrix.level() > deviceManifest->level();
                                  });
         matrixFragments.erase(it, matrixFragments.end());
-        auto combined = CompatibilityMatrix::combine(deviceManifest->level(), kernelLevel,
-                                                     &matrixFragments, &error);
+        auto combined =
+            CompatibilityMatrix::combine(deviceManifest->level(), &matrixFragments, &error);
         if (combined == nullptr) {
             LOG(WARNING) << "Unable to print HALs from new FCMs: unable to combine matrix "
                             "fragments <= level "
@@ -401,8 +396,8 @@
 // If |result| is already an error, don't do anything. Otherwise, set it to
 // an error with |errorCode|. Return reference to Error object for appending
 // additional error messages.
-android::base::Error<>& SetErrorCode(std::optional<android::base::Error<>>* retError,
-                                     int errorCode = 0) {
+android::base::Error& SetErrorCode(std::optional<android::base::Error>* retError,
+                                   int errorCode = 0) {
     if (!retError->has_value()) {
         retError->emplace(errorCode);
     } else {
@@ -416,8 +411,8 @@
 
 // If |other| is an error, add it to |retError|.
 template <typename T>
-void AddResult(std::optional<android::base::Error<>>* retError,
-               const android::base::Result<T>& other, const char* additionalMessage = "") {
+void AddResult(std::optional<android::base::Error>* retError, const android::base::Result<T>& other,
+               const char* additionalMessage = "") {
     if (other.ok()) return;
     SetErrorCode(retError, other.error().code()) << other.error() << additionalMessage;
 }
@@ -442,7 +437,7 @@
             .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
             .build();
 
-    std::optional<android::base::Error<>> retError = std::nullopt;
+    std::optional<android::base::Error> retError = std::nullopt;
 
     std::string compatibleError;
     int compatibleResult = vintfObject->checkCompatibility(&compatibleError, flags);
@@ -504,27 +499,27 @@
             LOG(INFO) << "Checking system manifest.";
             auto manifest = vintfObject->getFrameworkHalManifest();
             if (!manifest) {
-                LOG(ERROR) << "ERROR: Cannot fetch system manifest.";
+                LOG(ERROR) << "Cannot fetch system manifest.";
                 exitCode = EX_SOFTWARE;
             }
             LOG(INFO) << "Checking system matrix.";
             auto matrix = vintfObject->getFrameworkCompatibilityMatrix();
             if (!matrix) {
-                LOG(ERROR) << "ERROR: Cannot fetch system matrix.";
+                LOG(ERROR) << "Cannot fetch system matrix.";
                 exitCode = EX_SOFTWARE;
             }
             auto res = vintfObject->checkMissingHalsInMatrices(HidlInterfaceMetadata::all(),
                                                                AidlInterfaceMetadata::all(),
                                                                ShouldCheckMissingHalsInFcm);
             if (!res.ok()) {
-                LOG(ERROR) << "ERROR: " << res.error() << gCheckMissingHalsSuggestion;
+                LOG(ERROR) << res.error() << gCheckMissingHalsSuggestion;
                 exitCode = EX_SOFTWARE;
             }
 
             res = vintfObject->checkMatrixHalsHasDefinition(HidlInterfaceMetadata::all(),
                                                             AidlInterfaceMetadata::all());
             if (!res.ok()) {
-                LOG(ERROR) << "ERROR: " << res.error();
+                LOG(ERROR) << res.error();
                 exitCode = EX_SOFTWARE;
             }
             continue;
@@ -534,40 +529,30 @@
             LOG(INFO) << "Checking vendor manifest.";
             auto manifest = vintfObject->getDeviceHalManifest();
             if (!manifest) {
-                LOG(ERROR) << "ERROR: Cannot fetch vendor manifest.";
+                LOG(ERROR) << "Cannot fetch vendor manifest.";
                 exitCode = EX_SOFTWARE;
             }
             LOG(INFO) << "Checking vendor matrix.";
             auto matrix = vintfObject->getDeviceCompatibilityMatrix();
             if (!matrix) {
-                LOG(ERROR) << "ERROR: Cannot fetch vendor matrix.";
+                LOG(ERROR) << "Cannot fetch vendor matrix.";
                 exitCode = EX_SOFTWARE;
             }
             continue;
         }
 
-        LOG(ERROR) << "ERROR: --check-one does not work with --dirmap " << prefix;
+        LOG(ERROR) << "--check-one does not work with --dirmap " << prefix;
         exitCode = EX_SOFTWARE;
     }
     return exitCode;
 }
 
-void Logger(android::base::LogId, android::base::LogSeverity severity, const char* /*tag*/,
-            const char* /*file*/, unsigned int /*line*/, const char* message) {
-    if (severity >= android::base::WARNING) {
-        fflush(stdout);
-        fprintf(stderr, "%s\n", message);
-    } else {
-        fprintf(stdout, "%s\n", message);
-    }
-}
-
 }  // namespace details
 }  // namespace vintf
 }  // namespace android
 
 int main(int argc, char** argv) {
-    android::base::SetLogger(android::vintf::details::Logger);
+    android::base::SetLogger(android::base::StderrLogger);
 
     using namespace android::vintf;
     using namespace android::vintf::details;
@@ -605,7 +590,7 @@
     auto rootdirs = iterateValues(args, ROOTDIR);
     if (!rootdirs.empty()) {
         if (std::distance(rootdirs.begin(), rootdirs.end()) > 1) {
-            LOG(ERROR) << "ERROR: Can't have multiple --rootdir options";
+            LOG(ERROR) << "Can't have multiple --rootdir options";
             return usage(argv[0]);
         }
         args.emplace(DIR_MAP, "/:" + *rootdirs.begin());
@@ -621,7 +606,7 @@
     }
 
     if (dirmap.empty()) {
-        LOG(ERROR) << "ERROR: Missing --rootdir or --dirmap option.";
+        LOG(ERROR) << "Missing --rootdir or --dirmap option.";
         return usage(argv[0]);
     }
 
@@ -632,10 +617,10 @@
         return EX_OK;
     }
     if (compat.error().code() == 0) {
-        LOG(ERROR) << "ERROR: files are incompatible: " << compat.error();
+        LOG(ERROR) << "files are incompatible: " << compat.error();
         std::cout << "INCOMPATIBLE" << std::endl;
         return EX_DATAERR;
     }
-    LOG(ERROR) << "ERROR: " << strerror(compat.error().code()) << ": " << compat.error();
+    LOG(ERROR) << strerror(compat.error().code()) << ": " << compat.error();
     return EX_SOFTWARE;
 }
diff --git a/constants-private.h b/constants-private.h
index 39e6bf0..2b50f55 100644
--- a/constants-private.h
+++ b/constants-private.h
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <vintf/Level.h>
 #include <vintf/Version.h>
 #include <vintf/VersionRange.h>
 #include <vintf/constants.h>
@@ -72,9 +71,6 @@
 #undef SYSTEM_EXT_VINTF_DIR
 #undef ODM_LEGACY_VINTF_DIR
 
-// Device manifest with level T must not set kernel level.
-constexpr Level kEnforceDeviceManifestNoKernelLevel = Level::T;
-
 }  // namespace details
 }  // namespace vintf
 }  // namespace android
diff --git a/include/vintf/Arch.h b/include/vintf/Arch.h
index 4f4ae6a..3e69a42 100644
--- a/include/vintf/Arch.h
+++ b/include/vintf/Arch.h
@@ -32,7 +32,7 @@
     ARCH_32_64
 };
 
-static constexpr std::array<const char*, 4> gArchStrings = {
+static const std::array<std::string, 4> gArchStrings = {
     {
         "",
         "32",
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index a4a4558..9ad0e83 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -117,10 +117,7 @@
 
     // Combine a set of framework compatibility matrices. For each CompatibilityMatrix in matrices
     // (in the order of level(), where UNSPECIFIED (empty) is treated as deviceLevel)
-    // - If level() < deviceLevel:
-    //    - If kernelLevel is UNSPECIFIED, ignore
-    //    - If kernelLevel is not UNSPECIFIED and level() < kernelLevel, ignore
-    //    - If kernelLevel is not UNSPECIFIED and level() >= kernelLevel, add kernel()
+    // - If level() < deviceLevel, ignore
     // - If level() == UNSPECIFIED or level() == deviceLevel,
     //   - Add as hard requirements. See combineSameFcmVersion
     // - If level() > deviceLevel,
@@ -129,7 +126,7 @@
     //     with lower level()
     //   - <sepolicy>, <avb><vbmeta-version> is ignored
     // Return the combined matrix, nullptr if any error (e.g. conflict of information).
-    static std::unique_ptr<CompatibilityMatrix> combine(Level deviceLevel, Level kernelLevel,
+    static std::unique_ptr<CompatibilityMatrix> combine(Level deviceLevel,
                                                         std::vector<CompatibilityMatrix>* matrices,
                                                         std::string* error);
 
diff --git a/include/vintf/HalFormat.h b/include/vintf/HalFormat.h
index 3774098..fc86133 100644
--- a/include/vintf/HalFormat.h
+++ b/include/vintf/HalFormat.h
@@ -32,7 +32,7 @@
 };
 
 // clang-format off
-static constexpr std::array<const char*, 3> gHalFormatStrings = {
+static const std::array<std::string, 3> gHalFormatStrings = {
     "hidl",
     "native",
     "aidl"
diff --git a/include/vintf/KernelConfigType.h b/include/vintf/KernelConfigType.h
index ffb203e..de22c21 100644
--- a/include/vintf/KernelConfigType.h
+++ b/include/vintf/KernelConfigType.h
@@ -31,7 +31,7 @@
     TRISTATE
 };
 
-static constexpr std::array<const char*, 4> gKernelConfigTypeStrings = {
+static const std::array<std::string, 4> gKernelConfigTypeStrings = {
     {
         "string",
         "int",
diff --git a/include/vintf/ManifestHal.h b/include/vintf/ManifestHal.h
index 0b4a4af..7dfe5cb 100644
--- a/include/vintf/ManifestHal.h
+++ b/include/vintf/ManifestHal.h
@@ -64,8 +64,6 @@
     }
 
     inline Arch arch() const { return transportArch.arch; }
-    inline std::optional<std::string> ip() const { return transportArch.ip; }
-    inline std::optional<uint64_t> port() const { return transportArch.port; }
 
     inline const std::string& getName() const { return name; }
 
diff --git a/include/vintf/ManifestInstance.h b/include/vintf/ManifestInstance.h
index c89ccc3..c6a885b 100644
--- a/include/vintf/ManifestInstance.h
+++ b/include/vintf/ManifestInstance.h
@@ -50,8 +50,6 @@
     Arch arch() const;
     HalFormat format() const;
     const std::optional<std::string>& updatableViaApex() const;
-    const std::optional<std::string> ip() const;
-    const std::optional<uint64_t> port() const;
 
     bool operator==(const ManifestInstance& other) const;
     bool operator<(const ManifestInstance& other) const;
diff --git a/include/vintf/SchemaType.h b/include/vintf/SchemaType.h
index 8a68150..4254957 100644
--- a/include/vintf/SchemaType.h
+++ b/include/vintf/SchemaType.h
@@ -29,7 +29,7 @@
     FRAMEWORK,
 };
 
-static constexpr std::array<const char*, 2> gSchemaTypeStrings = {
+static const std::array<std::string, 2> gSchemaTypeStrings = {
     {
         "device",
         "framework",
diff --git a/include/vintf/Transport.h b/include/vintf/Transport.h
index e1a5c80..5823e60 100644
--- a/include/vintf/Transport.h
+++ b/include/vintf/Transport.h
@@ -29,15 +29,16 @@
     EMPTY = 0,
     PASSTHROUGH,
     HWBINDER,
-    INET,
 };
 
-static constexpr std::array<const char*, 4> gTransportStrings = {{
-    "",
-    "passthrough",
-    "hwbinder",
-    "inet",
-}};
+static const std::array<std::string, 3> gTransportStrings = {
+    {
+        "",
+        "passthrough",
+        "hwbinder",
+    }
+};
+
 
 } // namespace vintf
 } // namespace android
diff --git a/include/vintf/TransportArch.h b/include/vintf/TransportArch.h
index cb3030c..8e892e8 100644
--- a/include/vintf/TransportArch.h
+++ b/include/vintf/TransportArch.h
@@ -18,8 +18,6 @@
 #ifndef ANDROID_VINTF_TRANSPORT_ARCH_H
 #define ANDROID_VINTF_TRANSPORT_ARCH_H
 
-#include <optional>
-
 #include "Arch.h"
 #include "Transport.h"
 
@@ -29,8 +27,6 @@
 struct TransportArch {
     Transport transport = Transport::EMPTY;
     Arch arch = Arch::ARCH_EMPTY;
-    std::optional<std::string> ip;
-    std::optional<uint64_t> port;
 
     TransportArch() = default;
     TransportArch(Transport t, Arch a) : transport(t), arch(a) {}
@@ -55,8 +51,6 @@
     // <transport arch="64">passthrough</transport>
     // <transport arch="32+64">passthrough</transport>
     // <transport>hwbinder</transport>
-    // "ip" and "port" can be any string and uint64_t value respectively
-    // <transport ip="1.2.3.4" port="1234">inet</transport>
     // Element doesn't exist
     bool isValid(std::string* error = nullptr) const;
 };
diff --git a/include/vintf/Tristate.h b/include/vintf/Tristate.h
index 5417b23..f600b4c 100644
--- a/include/vintf/Tristate.h
+++ b/include/vintf/Tristate.h
@@ -30,7 +30,7 @@
     MODULE
 };
 
-static constexpr std::array<const char*, 3> gTristateStrings = {
+static const std::array<std::string, 3> gTristateStrings = {
     {
         "n",
         "y",
diff --git a/include/vintf/VersionRange.h b/include/vintf/VersionRange.h
index a17eaf6..50029ae 100644
--- a/include/vintf/VersionRange.h
+++ b/include/vintf/VersionRange.h
@@ -54,7 +54,7 @@
     //     ver == 2.2: false
     //     ver == 2.3: true
     //     ver == 2.7: true
-    //     ver == 2.8: true
+    //     ver == 2.8: false
     inline bool supportedBy(const Version &ver) const {
         return majorVer == ver.majorVer && minMinor <= ver.minorVer;
     }
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 050de80..ff0fae8 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -28,23 +28,22 @@
 #include <android-base/result.h>
 #include <hidl/metadata.h>
 
-#include <vintf/CheckFlags.h>
-#include <vintf/CompatibilityMatrix.h>
-#include <vintf/FileSystem.h>
-#include <vintf/HalManifest.h>
-#include <vintf/Level.h>
-#include <vintf/ObjectFactory.h>
-#include <vintf/PropertyFetcher.h>
-#include <vintf/RuntimeInfo.h>
+#include "CheckFlags.h"
+#include "CompatibilityMatrix.h"
+#include "FileSystem.h"
+#include "HalManifest.h"
+#include "Level.h"
+#include "ObjectFactory.h"
+#include "PropertyFetcher.h"
+#include "RuntimeInfo.h"
 
 namespace android {
 namespace vintf {
 
-class VintfObject;
-
 namespace details {
 class CheckVintfUtils;
 class FmOnlyVintfObject;
+class VintfObjectAfterUpdate;
 
 template <typename T>
 struct LockedSharedPtr {
@@ -58,40 +57,10 @@
     std::mutex mutex;
     RuntimeInfo::FetchFlags fetchedFlags = RuntimeInfo::FetchFlag::NONE;
 };
-
-/**
- * DO NOT USE outside of libvintf. This is an implementation detail. Use VintfObject::Builder
- * instead.
- *
- * A builder of VintfObject. If a dependency is not specified, the default behavior is used.
- * - FileSystem fetch from "/" for target and fetch no files for host
- * - ObjectFactory<RuntimeInfo> fetches default RuntimeInfo for target and nothing for host
- * - PropertyFetcher fetches properties for target and nothing for host
- */
-class VintfObjectBuilder {
-   public:
-    VintfObjectBuilder(std::unique_ptr<VintfObject>&& object) : mObject(std::move(object)) {}
-    ~VintfObjectBuilder();
-    VintfObjectBuilder& setFileSystem(std::unique_ptr<FileSystem>&&);
-    VintfObjectBuilder& setRuntimeInfoFactory(std::unique_ptr<ObjectFactory<RuntimeInfo>>&&);
-    VintfObjectBuilder& setPropertyFetcher(std::unique_ptr<PropertyFetcher>&&);
-
-    template <typename VintfObjectType = VintfObject>
-    std::unique_ptr<VintfObjectType> build() {
-        return std::unique_ptr<VintfObjectType>(
-            static_cast<VintfObjectType*>(buildInternal().release()));
-    }
-
-   private:
-    std::unique_ptr<VintfObject> buildInternal();
-    std::unique_ptr<VintfObject> mObject;
-};
-
 }  // namespace details
 
 namespace testing {
 class VintfObjectTestBase;
-class VintfObjectRecoveryTest;
 class VintfObjectRuntimeInfoTest;
 class VintfObjectCompatibleTest;
 }  // namespace testing
@@ -287,12 +256,11 @@
 
     // Expose functions for testing and recovery
     friend class testing::VintfObjectTestBase;
-    friend class testing::VintfObjectRecoveryTest;
     friend class testing::VintfObjectRuntimeInfoTest;
     friend class testing::VintfObjectCompatibleTest;
 
     // Expose functions to simulate dependency injection.
-    friend class details::VintfObjectBuilder;
+    friend class details::VintfObjectAfterUpdate;
     friend class details::CheckVintfUtils;
     friend class details::FmOnlyVintfObject;
 
@@ -343,16 +311,15 @@
     static std::shared_ptr<const RuntimeInfo> GetRuntimeInfo(
         RuntimeInfo::FetchFlags flags = RuntimeInfo::FetchFlag::ALL);
 
-   protected:
+   private:
     status_t getCombinedFrameworkMatrix(const std::shared_ptr<const HalManifest>& deviceManifest,
-                                        Level kernelLevel, CompatibilityMatrix* out,
-                                        std::string* error = nullptr);
+                                        CompatibilityMatrix* out, std::string* error = nullptr);
     status_t getAllFrameworkMatrixLevels(std::vector<CompatibilityMatrix>* out,
                                          std::string* error = nullptr);
     status_t getOneMatrix(const std::string& path, CompatibilityMatrix* out,
                           std::string* error = nullptr);
     status_t addDirectoryManifests(const std::string& directory, HalManifest* manifests,
-                                   bool ignoreSchemaType, std::string* error);
+                                   std::string* error = nullptr);
     status_t fetchDeviceHalManifest(HalManifest* out, std::string* error = nullptr);
     status_t fetchDeviceMatrix(CompatibilityMatrix* out, std::string* error = nullptr);
     status_t fetchOdmHalManifest(HalManifest* out, std::string* error = nullptr);
@@ -388,14 +355,26 @@
         const ListInstances& listInstances);
 
    public:
-    /** Builder of VintfObject. See VintfObjectBuilder for details. */
-    class Builder : public details::VintfObjectBuilder {
+    /**
+     * Builder of VintfObject. If a dependency is not specified, the default behavior is used.
+     * - FileSystem fetch from "/" for target and fetch no files for host
+     * - ObjectFactory<RuntimeInfo> fetches default RuntimeInfo for target and nothing for host
+     * - PropertyFetcher fetches properties for target and nothing for host
+     */
+    class Builder {
        public:
         Builder();
+        Builder& setFileSystem(std::unique_ptr<FileSystem>&&);
+        Builder& setRuntimeInfoFactory(std::unique_ptr<ObjectFactory<RuntimeInfo>>&&);
+        Builder& setPropertyFetcher(std::unique_ptr<PropertyFetcher>&&);
+        std::unique_ptr<VintfObject> build();
+
+       private:
+        std::unique_ptr<VintfObject> mObject;
     };
 
-   protected:
-    /* Empty VintfObject without any dependencies. Used by Builder and subclasses. */
+   private:
+    /* Empty VintfObject without any dependencies. Used by Builder. */
     VintfObject() = default;
 };
 
diff --git a/include/vintf/VintfObjectRecovery.h b/include/vintf/VintfObjectRecovery.h
deleted file mode 100644
index 64be749..0000000
--- a/include/vintf/VintfObjectRecovery.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-#pragma once
-
-#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
-#error VintfObjectRecovery is only supported in recovery and host.
-#endif
-
-#include <vintf/VintfObject.h>
-
-namespace android::vintf {
-
-/**
- * A special variant of VintfObject for the recovery ramdisk.
- *
- * In recovery ramdisk, there is no Treble split. All VINTF data is stored in /system/etc/vintf.
- *
- * All getDevice* / getFramework* functions return nullptr. Instead, getRecovery* should be
- * used instead.
- */
-class VintfObjectRecovery : public VintfObject {
-   public:
-    /*
-     * Get global instance. Results are cached.
-     */
-    static std::shared_ptr<VintfObjectRecovery> GetInstance();
-
-    /*
-     * Return the API that access the HAL manifests built from component pieces on the
-     * recovery partition.
-     *
-     * Returned manifest has SchemaType::DEVICE.
-     *
-     * No SKU manifest support.
-     */
-    std::shared_ptr<const HalManifest> getRecoveryHalManifest();
-
-    // Not supported. Call getRecoveryHalManifest instead.
-    std::shared_ptr<const HalManifest> getDeviceHalManifest() override { return nullptr; }
-    std::shared_ptr<const HalManifest> getFrameworkHalManifest() override { return nullptr; }
-
-    // Not supported. No compatibility check in recovery because there is no Treble split.
-    std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix() override {
-        return nullptr;
-    }
-    std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix() override {
-        return nullptr;
-    }
-
-    /** Builder of VintfObjectRecovery. See VintfObjectBuilder for details. */
-    class Builder : public details::VintfObjectBuilder {
-       public:
-        Builder();
-    };
-
-   private:
-    VintfObjectRecovery() = default;
-    status_t fetchRecoveryHalManifest(HalManifest* out, std::string* error);
-    details::LockedSharedPtr<HalManifest> mRecoveryManifest;
-};
-
-}  // namespace android::vintf
diff --git a/include/vintf/XmlSchemaFormat.h b/include/vintf/XmlSchemaFormat.h
index e75771e..32a42b6 100644
--- a/include/vintf/XmlSchemaFormat.h
+++ b/include/vintf/XmlSchemaFormat.h
@@ -28,7 +28,7 @@
     XSD,
 };
 
-static constexpr std::array<const char*, 2> gXmlSchemaFormatStrings = {{
+static const std::array<std::string, 2> gXmlSchemaFormatStrings = {{
     "dtd", "xsd",
 }};
 
diff --git a/include/vintf/constants.h b/include/vintf/constants.h
index 6bad7ce..6c56451 100644
--- a/include/vintf/constants.h
+++ b/include/vintf/constants.h
@@ -23,11 +23,7 @@
 namespace vintf {
 
 /* libvintf meta-version */
-constexpr Version kMetaVersion{5, 0};
-
-// Some legacy metaversion constants
-// The metaversion where inet transport is added to AIDL HALs
-constexpr Version kMetaVersionAidlInet{5, 0};
+constexpr Version kMetaVersion{4, 0};
 
 // Default version for an AIDL HAL if no version is specified.
 constexpr size_t kDefaultAidlMinorVersion = 1;
diff --git a/include/vintf/parse_string.h b/include/vintf/parse_string.h
index 315659b..e8aba2e 100644
--- a/include/vintf/parse_string.h
+++ b/include/vintf/parse_string.h
@@ -77,6 +77,10 @@
 #pragma clang diagnostic pop
 
 bool parse(const std::string &s, KernelVersion *ver);
+// if return true, ta->isValid() must be true.
+bool parse(const std::string &s, TransportArch *ta);
+// if return true, hal->isValid() must be true.
+bool parse(const std::string &s, ManifestHal *hal);
 bool parse(const std::string& s, FqInstance* fqInstance);
 
 bool parseKernelConfigInt(const std::string &s, int64_t *i);
diff --git a/libaidlvintf_test_helper/Android.bp b/libaidlvintf_test_helper/Android.bp
index ff39497..599051b 100644
--- a/libaidlvintf_test_helper/Android.bp
+++ b/libaidlvintf_test_helper/Android.bp
@@ -15,6 +15,7 @@
         "libselinux",
         "libtinyxml2",
         "libvintf",
+        "libutils",
     ],
 }
 
diff --git a/libaidlvintf_test_helper/include/aidl/Gtest.h b/libaidlvintf_test_helper/include/aidl/Gtest.h
index bde89a3..d88877e 100644
--- a/libaidlvintf_test_helper/include/aidl/Gtest.h
+++ b/libaidlvintf_test_helper/include/aidl/Gtest.h
@@ -13,8 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#pragma once
-
 #include <gtest/gtest.h>
 
 namespace android {
diff --git a/parse_string.cpp b/parse_string.cpp
index 83d72c7..e2954cf 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -329,10 +329,54 @@
     return os << to_string(ta.transport) << to_string(ta.arch);
 }
 
+bool parse(const std::string &s, TransportArch *ta) {
+    bool transportSet = false;
+    bool archSet = false;
+    for (size_t i = 0; i < gTransportStrings.size(); ++i) {
+        if (s.find(gTransportStrings.at(i)) != std::string::npos) {
+            ta->transport = static_cast<Transport>(i);
+            transportSet = true;
+            break;
+        }
+    }
+    if (!transportSet) {
+        return false;
+    }
+    for (size_t i = 0; i < gArchStrings.size(); ++i) {
+        if (s.find(gArchStrings.at(i)) != std::string::npos) {
+            ta->arch = static_cast<Arch>(i);
+            archSet = true;
+            break;
+        }
+    }
+    if (!archSet) {
+        return false;
+    }
+    return ta->isValid();
+}
+
 std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
     return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
 }
 
+bool parse(const std::string &s, ManifestHal *hal) {
+    std::vector<std::string> v = SplitString(s, '/');
+    if (v.size() != 4) {
+        return false;
+    }
+    if (!parse(v[0], &hal->format)) {
+        return false;
+    }
+    hal->name = v[1];
+    if (!parse(v[2], &hal->transportArch)) {
+        return false;
+    }
+    if (!parse(v[3], &hal->versions)) {
+        return false;
+    }
+    return hal->isValid();
+}
+
 std::ostream &operator<<(std::ostream &os, const ManifestHal &hal) {
     return os << hal.format << "/"
               << hal.name << "/"
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 90184b2..6e0538c 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -143,76 +143,42 @@
     return true;
 }
 
-static bool parse(const std::string& s, std::optional<uint64_t>* out) {
-    uint64_t val;
-    if (base::ParseUint(s, &val)) {
-        *out = val;
-        return true;
-    }
-    return false;
-}
-
 // ---------------------- XmlNodeConverter definitions
 
-// When serializing an object to an XML document, these parameters don't change until
-// the object is fully serialized.
-// These parameters are also passed to converters of child nodes so they see the same
-// serialization parameters.
-struct MutateNodeParam {
-    DocType* d;
-    SerializeFlags::Type flags = SerializeFlags::EVERYTHING;
-};
-
-// When deserializing an XML document to an object, these parameters don't change until
-// the XML document is fully deserialized.
-// * Except metaVersion, which is immediately modified when parsing top-level <manifest>
-//   or <compatibility-matrix>, and unchanged thereafter;
-//   see HalManifestConverter::BuildObject and CompatibilityMatrixConverter::BuildObject)
-// These parameters are also passed to converters of child nodes so they see the same
-// deserialization parameters.
-struct BuildObjectParam {
-    std::string* error;
-    Version metaVersion;
-};
-
 template <typename Object>
 struct XmlNodeConverter {
     XmlNodeConverter() {}
     virtual ~XmlNodeConverter() {}
 
-   protected:
-    virtual void mutateNode(const Object& object, NodeType* root, const MutateNodeParam&) const = 0;
-    virtual bool buildObject(Object* object, NodeType* root, const BuildObjectParam&) const = 0;
-
-   public:
-    // Methods for other (usually parent) converters
-    // Name of the XML element.
+    // sub-types should implement these.
+    virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
+    virtual void mutateNode(const Object& o, NodeType* n, DocType* d, SerializeFlags::Type) const {
+        mutateNode(o, n, d);
+    }
+    virtual bool buildObject(Object* o, NodeType* n, std::string* error) const = 0;
     virtual std::string elementName() const = 0;
-    // Serialize |o| into an XML element.
-    inline NodeType* operator()(const Object& o, const MutateNodeParam& param) const {
-        NodeType* root = createNode(this->elementName(), param.d);
-        this->mutateNode(o, root, param);
+
+    // convenience methods for user
+    inline NodeType* operator()(const Object& o, DocType* d,
+                                SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const {
+        NodeType *root = createNode(this->elementName(), d);
+        this->mutateNode(o, root, d, flags);
         return root;
     }
-    // Deserialize XML element |root| into |object|.
-    inline bool operator()(Object* object, NodeType* root, const BuildObjectParam& param) const {
-        if (nameOf(root) != this->elementName()) {
-            return false;
-        }
-        return this->buildObject(object, root, param);
-    }
-
-    // Public methods for android::vintf::fromXml / android::vintf::toXml.
-    // Serialize |o| into an XML string.
-    inline std::string toXml(const Object& o, SerializeFlags::Type flags) const {
-        DocType* doc = createDocument();
-        appendChild(doc, (*this)(o, MutateNodeParam{doc, flags}));
+    inline std::string operator()(const Object& o, SerializeFlags::Type flags) const {
+        DocType *doc = createDocument();
+        appendChild(doc, (*this)(o, doc, flags));
         std::string s = printDocument(doc);
         deleteDocument(doc);
         return s;
     }
-    // Deserialize XML string |xml| into |o|.
-    inline bool fromXml(Object* o, const std::string& xml, std::string* error) const {
+    inline bool operator()(Object* object, NodeType* root, std::string* error) const {
+        if (nameOf(root) != this->elementName()) {
+            return false;
+        }
+        return this->buildObject(object, root, error);
+    }
+    inline bool operator()(Object* o, const std::string& xml, std::string* error) const {
         std::string errorBuffer;
         if (error == nullptr) error = &errorBuffer;
 
@@ -221,16 +187,12 @@
             *error = "Not a valid XML";
             return false;
         }
-        // For top-level <manifest> and <compatibility-matrix>, HalManifestConverter and
-        // CompatibilityMatrixConverter fills in metaversion and pass down to children.
-        // For other nodes, we don't know metaversion of the original XML, so just leave empty
-        // for maximum backwards compatibility.
-        bool ret = (*this)(o, getRootChild(doc), BuildObjectParam{error, {}});
+        bool ret = (*this)(o, getRootChild(doc), error);
         deleteDocument(doc);
         return ret;
     }
 
-    // convenience methods for subclasses to implement virtual functions.
+    // convenience methods for implementor.
 
     // All append* functions helps mutateNode() to serialize the object into XML.
     template <typename T>
@@ -263,9 +225,10 @@
 
     template <typename T, typename Array>
     inline void appendChildren(NodeType* parent, const XmlNodeConverter<T>& conv,
-                               const Array& array, const MutateNodeParam& param) const {
+                               const Array& array, DocType* d,
+                               SerializeFlags::Type flags = SerializeFlags::EVERYTHING) const {
         for (const T &t : array) {
-            appendChild(parent, conv(t, param));
+            appendChild(parent, conv(t, d, flags));
         }
     }
 
@@ -338,48 +301,48 @@
 
     template <typename T>
     inline bool parseChild(NodeType* root, const XmlNodeConverter<T>& conv, T* t,
-                           const BuildObjectParam& param) const {
+                           std::string* error) const {
         NodeType *child = getChild(root, conv.elementName());
         if (child == nullptr) {
-            *param.error = "Could not find element with name <" + conv.elementName() +
-                           "> in element <" + this->elementName() + ">";
+            *error = "Could not find element with name <" + conv.elementName() + "> in element <" +
+                     this->elementName() + ">";
             return false;
         }
-        return conv(t, child, param);
+        return conv(t, child, error);
     }
 
     template <typename T>
     inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
-                                   T&& defaultValue, T* t, const BuildObjectParam& param) const {
+                                   T&& defaultValue, T* t, std::string* error) const {
         NodeType *child = getChild(root, conv.elementName());
         if (child == nullptr) {
             *t = std::move(defaultValue);
             return true;
         }
-        return conv(t, child, param);
+        return conv(t, child, error);
     }
 
     template <typename T>
     inline bool parseOptionalChild(NodeType* root, const XmlNodeConverter<T>& conv,
-                                   std::optional<T>* t, const BuildObjectParam& param) const {
+                                   std::optional<T>* t, std::string* error) const {
         NodeType* child = getChild(root, conv.elementName());
         if (child == nullptr) {
             *t = std::nullopt;
             return true;
         }
         *t = std::make_optional<T>();
-        return conv(&**t, child, param);
+        return conv(&**t, child, error);
     }
 
     template <typename T>
     inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, std::vector<T>* v,
-                              const BuildObjectParam& param) const {
+                              std::string* error) const {
         auto nodes = getChildren(root, conv.elementName());
         v->resize(nodes.size());
         for (size_t i = 0; i < nodes.size(); ++i) {
-            if (!conv(&v->at(i), nodes[i], param)) {
-                *param.error = "Could not parse element with name <" + conv.elementName() +
-                               "> in element <" + this->elementName() + ">: " + *param.error;
+            if (!conv(&v->at(i), nodes[i], error)) {
+                *error = "Could not parse element with name <" + conv.elementName() +
+                         "> in element <" + this->elementName() + ">: " + *error;
                 return false;
             }
         }
@@ -389,16 +352,16 @@
     template <typename Container, typename T = typename Container::value_type,
               typename = typename Container::key_compare>
     inline bool parseChildren(NodeType* root, const XmlNodeConverter<T>& conv, Container* s,
-                              const BuildObjectParam& param) const {
+                              std::string* error) const {
         std::vector<T> vec;
-        if (!parseChildren(root, conv, &vec, param)) {
+        if (!parseChildren(root, conv, &vec, error)) {
             return false;
         }
         s->clear();
         s->insert(vec.begin(), vec.end());
         if (s->size() != vec.size()) {
-            *param.error = "Duplicated elements <" + conv.elementName() + "> in element <" +
-                           this->elementName() + ">";
+            *error = "Duplicated elements <" + conv.elementName() + "> in element <" +
+                     this->elementName() + ">";
             s->clear();
             return false;
         }
@@ -407,8 +370,8 @@
 
     template <typename K, typename V>
     inline bool parseChildren(NodeType* root, const XmlNodeConverter<std::pair<K, V>>& conv,
-                              std::map<K, V>* s, const BuildObjectParam& param) const {
-        return parseChildren<std::map<K, V>, std::pair<K, V>>(root, conv, s, param);
+                              std::map<K, V>* s, std::string* error) const {
+        return parseChildren<std::map<K, V>, std::pair<K, V>>(root, conv, s, error);
     }
 
     inline bool parseText(NodeType* node, std::string* s, std::string* /* error */) const {
@@ -437,25 +400,23 @@
 
 template<typename Object>
 struct XmlTextConverter : public XmlNodeConverter<Object> {
-    void mutateNode(const Object& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendText(root, ::android::vintf::to_string(object), param.d);
+    virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
+        appendText(root, ::android::vintf::to_string(object), d);
     }
-    bool buildObject(Object* object, NodeType* root, const BuildObjectParam& param) const override {
-        return this->parseText(root, object, param.error);
+    virtual bool buildObject(Object* object, NodeType* root, std::string* error) const override {
+        return this->parseText(root, object, error);
     }
 };
 
 template <typename Pair, typename FirstConverter, typename SecondConverter>
 struct XmlPairConverter : public XmlNodeConverter<Pair> {
-    void mutateNode(const Pair& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChild(root, FirstConverter{}(object.first, param));
-        appendChild(root, SecondConverter{}(object.second, param));
+    virtual void mutateNode(const Pair& pair, NodeType* root, DocType* d) const override {
+        appendChild(root, FirstConverter{}(pair.first, d));
+        appendChild(root, SecondConverter{}(pair.second, d));
     }
-    bool buildObject(Pair* object, NodeType* root, const BuildObjectParam& param) const override {
-        return this->parseChild(root, FirstConverter{}, &object->first, param) &&
-               this->parseChild(root, SecondConverter{}, &object->second, param);
+    virtual bool buildObject(Pair* pair, NodeType* root, std::string* error) const override {
+        return this->parseChild(root, FirstConverter{}, &pair->first, error) &&
+               this->parseChild(root, SecondConverter{}, &pair->second, error);
     }
 };
 
@@ -472,13 +433,11 @@
 // <version>100</version> <=> Version{kFakeAidlMajorVersion, 100}
 struct AidlVersionConverter : public XmlNodeConverter<Version> {
     std::string elementName() const override { return "version"; }
-    void mutateNode(const Version& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendText(root, aidlVersionToString(object), param.d);
+    void mutateNode(const Version& object, NodeType* root, DocType* d) const override {
+        appendText(root, aidlVersionToString(object), d);
     }
-    bool buildObject(Version* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseText(root, object, {parseAidlVersion}, param.error);
+    bool buildObject(Version* object, NodeType* root, std::string* error) const override {
+        return parseText(root, object, {parseAidlVersion}, error);
     }
 };
 
@@ -486,40 +445,28 @@
 // <version>100-105</version> <=> VersionRange{kFakeAidlMajorVersion, 100, 105}
 struct AidlVersionRangeConverter : public XmlNodeConverter<VersionRange> {
     std::string elementName() const override { return "version"; }
-    void mutateNode(const VersionRange& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendText(root, aidlVersionRangeToString(object), param.d);
+    void mutateNode(const VersionRange& object, NodeType* root, DocType* d) const override {
+        appendText(root, aidlVersionRangeToString(object), d);
     }
-    bool buildObject(VersionRange* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseText(root, object, {parseAidlVersionRange}, param.error);
+    bool buildObject(VersionRange* object, NodeType* root, std::string* error) const override {
+        return parseText(root, object, {parseAidlVersionRange}, error);
     }
 };
 
 struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
     std::string elementName() const override { return "transport"; }
-    void mutateNode(const TransportArch& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
+    void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override {
         if (object.arch != Arch::ARCH_EMPTY) {
             appendAttr(root, "arch", object.arch);
         }
-        if (object.ip.has_value()) {
-            appendAttr(root, "ip", *object.ip);
-        }
-        if (object.port.has_value()) {
-            appendAttr(root, "port", *object.port);
-        }
-        appendText(root, ::android::vintf::to_string(object.transport), param.d);
+        appendText(root, ::android::vintf::to_string(object.transport), d);
     }
-    bool buildObject(TransportArch* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, param.error) ||
-            !parseOptionalAttr(root, "ip", {}, &object->ip, param.error) ||
-            !parseOptionalAttr(root, "port", {}, &object->port, param.error) ||
-            !parseText(root, &object->transport, param.error)) {
+    bool buildObject(TransportArch* object, NodeType* root, std::string* error) const override {
+        if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch, error) ||
+            !parseText(root, &object->transport, error)) {
             return false;
         }
-        if (!object->isValid(param.error)) {
+        if (!object->isValid(error)) {
             return false;
         }
         return true;
@@ -528,20 +475,19 @@
 
 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
     std::string elementName() const override { return "value"; }
-    void mutateNode(const KernelConfigTypedValue& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
+    void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override {
         appendAttr(root, "type", object.mType);
-        appendText(root, ::android::vintf::to_string(object), param.d);
+        appendText(root, ::android::vintf::to_string(object), d);
     }
     bool buildObject(KernelConfigTypedValue* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
+                     std::string* error) const override {
         std::string stringValue;
-        if (!parseAttr(root, "type", &object->mType, param.error) ||
-            !parseText(root, &stringValue, param.error)) {
+        if (!parseAttr(root, "type", &object->mType, error) ||
+            !parseText(root, &stringValue, error)) {
             return false;
         }
         if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
-            *param.error = "Could not parse kernel config value \"" + stringValue + "\"";
+            *error = "Could not parse kernel config value \"" + stringValue + "\"";
             return false;
         }
         return true;
@@ -559,39 +505,37 @@
 
 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
     std::string elementName() const override { return "interface"; }
-    void mutateNode(const HalInterface& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendTextElement(root, "name", object.name(), param.d);
-        appendTextElements(root, "instance", object.mInstances, param.d);
-        appendTextElements(root, "regex-instance", object.mRegexes, param.d);
+    void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override {
+        appendTextElement(root, "name", intf.name(), d);
+        appendTextElements(root, "instance", intf.mInstances, d);
+        appendTextElements(root, "regex-instance", intf.mRegexes, d);
     }
-    bool buildObject(HalInterface* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
+    bool buildObject(HalInterface* intf, NodeType* root, std::string* error) const override {
         std::vector<std::string> instances;
         std::vector<std::string> regexes;
-        if (!parseTextElement(root, "name", &object->mName, param.error) ||
-            !parseTextElements(root, "instance", &instances, param.error) ||
-            !parseTextElements(root, "regex-instance", &regexes, param.error)) {
+        if (!parseTextElement(root, "name", &intf->mName, error) ||
+            !parseTextElements(root, "instance", &instances, error) ||
+            !parseTextElements(root, "regex-instance", &regexes, error)) {
             return false;
         }
         bool success = true;
         for (const auto& e : instances) {
-            if (!object->insertInstance(e, false /* isRegex */)) {
-                if (!param.error->empty()) *param.error += "\n";
-                *param.error += "Duplicated instance '" + e + "' in " + object->name();
+            if (!intf->insertInstance(e, false /* isRegex */)) {
+                if (!error->empty()) *error += "\n";
+                *error += "Duplicated instance '" + e + "' in " + intf->name();
                 success = false;
             }
         }
         for (const auto& e : regexes) {
             details::Regex regex;
             if (!regex.compile(e)) {
-                if (!param.error->empty()) *param.error += "\n";
-                *param.error += "Invalid regular expression '" + e + "' in " + object->name();
+                if (!error->empty()) *error += "\n";
+                *error += "Invalid regular expression '" + e + "' in " + intf->name();
                 success = false;
             }
-            if (!object->insertInstance(e, true /* isRegex */)) {
-                if (!param.error->empty()) *param.error += "\n";
-                *param.error += "Duplicated regex-instance '" + e + "' in " + object->name();
+            if (!intf->insertInstance(e, true /* isRegex */)) {
+                if (!error->empty()) *error += "\n";
+                *error += "Duplicated regex-instance '" + e + "' in " + intf->name();
                 success = false;
             }
         }
@@ -601,36 +545,34 @@
 
 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
     std::string elementName() const override { return "hal"; }
-    void mutateNode(const MatrixHal& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendAttr(root, "format", object.format);
-        appendAttr(root, "optional", object.optional);
-        appendTextElement(root, "name", object.name, param.d);
-        if (object.format == HalFormat::AIDL) {
+    void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override {
+        appendAttr(root, "format", hal.format);
+        appendAttr(root, "optional", hal.optional);
+        appendTextElement(root, "name", hal.name, d);
+        if (hal.format == HalFormat::AIDL) {
             // By default, buildObject() assumes a <version>0</version> tag if no <version> tag
             // is specified. Don't output any <version> tag if there's only one <version>0</version>
             // tag.
-            if (object.versionRanges.size() != 1 ||
-                object.versionRanges[0] != details::kDefaultAidlVersionRange) {
-                appendChildren(root, AidlVersionRangeConverter{}, object.versionRanges, param);
+            if (hal.versionRanges.size() != 1 ||
+                hal.versionRanges[0] != details::kDefaultAidlVersionRange) {
+                appendChildren(root, AidlVersionRangeConverter{}, hal.versionRanges, d);
             }
         } else {
-            appendChildren(root, VersionRangeConverter{}, object.versionRanges, param);
+            appendChildren(root, VersionRangeConverter{}, hal.versionRanges, d);
         }
-        appendChildren(root, HalInterfaceConverter{}, iterateValues(object.interfaces), param);
+        appendChildren(root, HalInterfaceConverter{}, iterateValues(hal.interfaces), d);
     }
-    bool buildObject(MatrixHal* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
+    bool buildObject(MatrixHal* object, NodeType* root, std::string* error) const override {
         std::vector<HalInterface> interfaces;
-        if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, param.error) ||
+        if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) ||
             !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional,
-                               param.error) ||
-            !parseTextElement(root, "name", &object->name, param.error) ||
-            !parseChildren(root, HalInterfaceConverter{}, &interfaces, param)) {
+                               error) ||
+            !parseTextElement(root, "name", &object->name, error) ||
+            !parseChildren(root, HalInterfaceConverter{}, &interfaces, error)) {
             return false;
         }
         if (object->format == HalFormat::AIDL) {
-            if (!parseChildren(root, AidlVersionRangeConverter{}, &object->versionRanges, param)) {
+            if (!parseChildren(root, AidlVersionRangeConverter{}, &object->versionRanges, error)) {
                 return false;
             }
             // Insert fake version for AIDL HALs so that compatibility check for AIDL and other
@@ -639,7 +581,7 @@
                 object->versionRanges.push_back(details::kDefaultAidlVersionRange);
             }
         } else {
-            if (!parseChildren(root, VersionRangeConverter{}, &object->versionRanges, param)) {
+            if (!parseChildren(root, VersionRangeConverter{}, &object->versionRanges, error)) {
                 return false;
             }
         }
@@ -647,21 +589,21 @@
             std::string name{interface.name()};
             auto res = object->interfaces.emplace(std::move(name), std::move(interface));
             if (!res.second) {
-                *param.error = "Duplicated interface entry \"" + res.first->first +
-                               "\"; if additional instances are needed, add them to the "
-                               "existing <interface> node.";
+                *error = "Duplicated interface entry \"" + res.first->first +
+                         "\"; if additional instances are needed, add them to the "
+                         "existing <interface> node.";
                 return false;
             }
         }
 // Do not check for target-side libvintf to avoid restricting ability for upgrade accidentally.
 #ifndef LIBVINTF_TARGET
-        if (!checkAdditionalRestrictionsOnHal(*object, param.error)) {
+        if (!checkAdditionalRestrictionsOnHal(*object, error)) {
             return false;
         }
 #endif
 
-        if (!object->isValid(param.error)) {
-            param.error->insert(0, "'" + object->name + "' is not a valid Matrix HAL: ");
+        if (!object->isValid(error)) {
+            error->insert(0, "'" + object->name + "' is not a valid Matrix HAL: ");
             return false;
         }
         return true;
@@ -700,46 +642,47 @@
 
 struct MatrixKernelConditionsConverter : public XmlNodeConverter<std::vector<KernelConfig>> {
     std::string elementName() const override { return "conditions"; }
-    void mutateNode(const std::vector<KernelConfig>& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChildren(root, MatrixKernelConfigConverter{}, object, param);
+    void mutateNode(const std::vector<KernelConfig>& conds, NodeType* root,
+                    DocType* d) const override {
+        appendChildren(root, MatrixKernelConfigConverter{}, conds, d);
     }
     bool buildObject(std::vector<KernelConfig>* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseChildren(root, MatrixKernelConfigConverter{}, object, param);
+                     std::string* error) const override {
+        return parseChildren(root, MatrixKernelConfigConverter{}, object, error);
     }
 };
 
 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
     std::string elementName() const override { return "kernel"; }
-    void mutateNode(const MatrixKernel& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        KernelVersion kv = object.mMinLts;
-        if (!param.flags.isKernelMinorRevisionEnabled()) {
+    void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d) const override {
+        mutateNode(kernel, root, d, SerializeFlags::EVERYTHING);
+    }
+    void mutateNode(const MatrixKernel& kernel, NodeType* root, DocType* d,
+                    SerializeFlags::Type flags) const override {
+        KernelVersion kv = kernel.mMinLts;
+        if (!flags.isKernelMinorRevisionEnabled()) {
             kv.minorRev = 0u;
         }
         appendAttr(root, "version", kv);
 
-        if (object.getSourceMatrixLevel() != Level::UNSPECIFIED) {
-            appendAttr(root, "level", object.getSourceMatrixLevel());
+        if (kernel.getSourceMatrixLevel() != Level::UNSPECIFIED) {
+            appendAttr(root, "level", kernel.getSourceMatrixLevel());
         }
 
-        if (!object.mConditions.empty()) {
-            appendChild(root, MatrixKernelConditionsConverter{}(object.mConditions, param));
+        if (!kernel.mConditions.empty()) {
+            appendChild(root, MatrixKernelConditionsConverter{}(kernel.mConditions, d));
         }
-        if (param.flags.isKernelConfigsEnabled()) {
-            appendChildren(root, MatrixKernelConfigConverter{}, object.mConfigs, param);
+        if (flags.isKernelConfigsEnabled()) {
+            appendChildren(root, MatrixKernelConfigConverter{}, kernel.mConfigs, d);
         }
     }
-    bool buildObject(MatrixKernel* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
+    bool buildObject(MatrixKernel* object, NodeType* root, std::string* error) const override {
         Level sourceMatrixLevel = Level::UNSPECIFIED;
-        if (!parseAttr(root, "version", &object->mMinLts, param.error) ||
-            !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &sourceMatrixLevel,
-                               param.error) ||
+        if (!parseAttr(root, "version", &object->mMinLts, error) ||
+            !parseOptionalAttr(root, "level", Level::UNSPECIFIED, &sourceMatrixLevel, error) ||
             !parseOptionalChild(root, MatrixKernelConditionsConverter{}, {}, &object->mConditions,
-                                param) ||
-            !parseChildren(root, MatrixKernelConfigConverter{}, &object->mConfigs, param)) {
+                                error) ||
+            !parseChildren(root, MatrixKernelConfigConverter{}, &object->mConfigs, error)) {
             return false;
         }
         object->setSourceMatrixLevel(sourceMatrixLevel);
@@ -755,100 +698,83 @@
 // .isValid() == true.
 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
     std::string elementName() const override { return "hal"; }
-    void mutateNode(const ManifestHal& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendAttr(root, "format", object.format);
-        appendTextElement(root, "name", object.name, param.d);
-        if (!object.transportArch.empty()) {
-            appendChild(root, TransportArchConverter{}(object.transportArch, param));
+    void mutateNode(const ManifestHal& m, NodeType* root, DocType* d) const override {
+        mutateNode(m, root, d, SerializeFlags::EVERYTHING);
+    }
+    void mutateNode(const ManifestHal& hal, NodeType* root, DocType* d,
+                    SerializeFlags::Type flags) const override {
+        appendAttr(root, "format", hal.format);
+        appendTextElement(root, "name", hal.name, d);
+        if (!hal.transportArch.empty()) {
+            appendChild(root, TransportArchConverter{}(hal.transportArch, d));
         }
-        if (object.format == HalFormat::AIDL) {
+        if (hal.format == HalFormat::AIDL) {
             // By default, buildObject() assumes a <version>0</version> tag if no <version> tag
             // is specified. Don't output any <version> tag if there's only one <version>0</version>
             // tag.
-            if (object.versions.size() != 1 || object.versions[0] != details::kDefaultAidlVersion) {
-                appendChildren(root, AidlVersionConverter{}, object.versions, param);
+            if (hal.versions.size() != 1 || hal.versions[0] != details::kDefaultAidlVersion) {
+                appendChildren(root, AidlVersionConverter{}, hal.versions, d);
             }
         } else {
-            appendChildren(root, VersionConverter{}, object.versions, param);
+            appendChildren(root, VersionConverter{}, hal.versions, d);
         }
-        appendChildren(root, HalInterfaceConverter{}, iterateValues(object.interfaces), param);
-        if (object.isOverride()) {
-            appendAttr(root, "override", object.isOverride());
+        appendChildren(root, HalInterfaceConverter{}, iterateValues(hal.interfaces), d);
+        if (hal.isOverride()) {
+            appendAttr(root, "override", hal.isOverride());
         }
-        if (const auto& apex = object.updatableViaApex(); apex.has_value()) {
+        if (const auto& apex = hal.updatableViaApex(); apex.has_value()) {
             appendAttr(root, "updatable-via-apex", apex.value());
         }
-        if (param.flags.isFqnameEnabled()) {
+        if (flags.isFqnameEnabled()) {
             std::set<std::string> simpleFqInstances;
-            object.forEachInstance([&simpleFqInstances](const auto& manifestInstance) {
+            hal.forEachInstance([&simpleFqInstances](const auto& manifestInstance) {
                 simpleFqInstances.emplace(manifestInstance.getSimpleFqInstance());
                 return true;
             });
-            appendTextElements(root, FqInstanceConverter{}.elementName(), simpleFqInstances,
-                               param.d);
+            appendTextElements(root, FqInstanceConverter{}.elementName(), simpleFqInstances, d);
         }
-        if (object.getMaxLevel() != Level::UNSPECIFIED) {
-            appendAttr(root, "max-level", object.getMaxLevel());
+        if (hal.getMaxLevel() != Level::UNSPECIFIED) {
+            appendAttr(root, "max-level", hal.getMaxLevel());
         }
     }
-    bool buildObject(ManifestHal* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
+    bool buildObject(ManifestHal* object, NodeType* root, std::string* error) const override {
         std::vector<HalInterface> interfaces;
-        if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, param.error) ||
-            !parseOptionalAttr(root, "override", false, &object->mIsOverride, param.error) ||
-            !parseOptionalAttr(root, "updatable-via-apex", {}, &object->mUpdatableViaApex,
-                               param.error) ||
-            !parseTextElement(root, "name", &object->name, param.error) ||
+        if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format, error) ||
+            !parseOptionalAttr(root, "override", false, &object->mIsOverride, error) ||
+            !parseOptionalAttr(root, "updatable-via-apex", {}, &object->mUpdatableViaApex, error) ||
+            !parseTextElement(root, "name", &object->name, error) ||
             !parseOptionalChild(root, TransportArchConverter{}, {}, &object->transportArch,
-                                param) ||
-            !parseChildren(root, HalInterfaceConverter{}, &interfaces, param) ||
-            !parseOptionalAttr(root, "max-level", Level::UNSPECIFIED, &object->mMaxLevel,
-                               param.error)) {
+                                error) ||
+            !parseChildren(root, HalInterfaceConverter{}, &interfaces, error) ||
+            !parseOptionalAttr(root, "max-level", Level::UNSPECIFIED, &object->mMaxLevel, error)) {
             return false;
         }
 
         switch (object->format) {
             case HalFormat::HIDL: {
-                if (!parseChildren(root, VersionConverter{}, &object->versions, param))
+                if (!parseChildren(root, VersionConverter{}, &object->versions, error))
                     return false;
                 if (object->transportArch.empty()) {
-                    *param.error =
-                        "HIDL HAL '" + object->name + "' should have <transport> defined.";
-                    return false;
-                }
-                if (object->transportArch.transport == Transport::INET ||
-                    object->transportArch.ip.has_value() ||
-                    object->transportArch.port.has_value()) {
-                    *param.error = "HIDL HAL '" + object->name +
-                                   "' should not have <transport> \"inet\" " +
-                                   "or ip or port attributes defined.";
+                    *error = "HIDL HAL '" + object->name + "' should have <transport> defined.";
                     return false;
                 }
             } break;
             case HalFormat::NATIVE: {
-                if (!parseChildren(root, VersionConverter{}, &object->versions, param))
+                if (!parseChildren(root, VersionConverter{}, &object->versions, error))
                     return false;
                 if (!object->transportArch.empty()) {
-                    *param.error =
+                    *error =
                         "Native HAL '" + object->name + "' should not have <transport> defined.";
                     return false;
                 }
             } break;
             case HalFormat::AIDL: {
-                if (!object->transportArch.empty() &&
-                    object->transportArch.transport != Transport::INET) {
-                    if (param.metaVersion >= kMetaVersionAidlInet) {
-                        *param.error = "AIDL HAL '" + object->name +
-                                       R"(' only supports "inet" or empty <transport>, found ")" +
-                                       to_string(object->transportArch) + "\"";
-                        return false;
-                    }
+                if (!object->transportArch.empty()) {
                     LOG(WARNING) << "Ignoring <transport> on manifest <hal format=\"aidl\"> "
-                                 << object->name << ". Only \"inet\" supported.";
+                                 << object->name;
                     object->transportArch = {};
                 }
-                if (!parseChildren(root, AidlVersionConverter{}, &object->versions, param)) {
+                if (!parseChildren(root, AidlVersionConverter{}, &object->versions, error)) {
                     return false;
                 }
                 // Insert fake version for AIDL HALs so that forEachInstance works.
@@ -862,40 +788,40 @@
                                   object->format);
             } break;
         }
-        if (!object->transportArch.isValid(param.error)) return false;
+        if (!object->transportArch.isValid(error)) return false;
 
         object->interfaces.clear();
         for (auto &&interface : interfaces) {
             auto res = object->interfaces.emplace(interface.name(), std::move(interface));
             if (!res.second) {
-                *param.error = "Duplicated interface entry \"" + res.first->first +
-                               "\"; if additional instances are needed, add them to the "
-                               "existing <interface> node.";
+                *error = "Duplicated interface entry \"" + res.first->first +
+                         "\"; if additional instances are needed, add them to the "
+                         "existing <interface> node.";
                 return false;
             }
         }
 // Do not check for target-side libvintf to avoid restricting upgrade accidentally.
 #ifndef LIBVINTF_TARGET
-        if (!checkAdditionalRestrictionsOnHal(*object, param.error)) {
+        if (!checkAdditionalRestrictionsOnHal(*object, error)) {
             return false;
         }
 #endif
 
         std::set<FqInstance> fqInstances;
-        if (!parseChildren(root, FqInstanceConverter{}, &fqInstances, param)) {
+        if (!parseChildren(root, FqInstanceConverter{}, &fqInstances, error)) {
             return false;
         }
         std::set<FqInstance> fqInstancesToInsert;
         for (auto& e : fqInstances) {
             if (e.hasPackage()) {
-                *param.error = "Should not specify package: \"" + e.string() + "\"";
+                *error = "Should not specify package: \"" + e.string() + "\"";
                 return false;
             }
             if (object->format == HalFormat::AIDL) {
                 // <fqname> in AIDL HALs should not contain version.
                 if (e.hasVersion()) {
-                    *param.error = "Should not specify version in <fqname> for AIDL HAL: \"" +
-                                   e.string() + "\"";
+                    *error = "Should not specify version in <fqname> for AIDL HAL: \"" +
+                             e.string() + "\"";
                     return false;
                 }
                 // Put in the fake kDefaultAidlVersion so that HalManifest can
@@ -911,12 +837,12 @@
                 fqInstancesToInsert.emplace(std::move(e));
             }
         }
-        if (!object->insertInstances(fqInstancesToInsert, param.error)) {
+        if (!object->insertInstances(fqInstancesToInsert, error)) {
             return false;
         }
 
-        if (!object->isValid(param.error)) {
-            param.error->insert(0, "'" + object->name + "' is not a valid Manifest HAL: ");
+        if (!object->isValid(error)) {
+            error->insert(0, "'" + object->name + "' is not a valid Manifest HAL: ");
             return false;
         }
 
@@ -952,17 +878,15 @@
 
 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
     std::string elementName() const override { return "sepolicy"; }
-    void mutateNode(const Sepolicy& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChild(root, KernelSepolicyVersionConverter{}(object.kernelSepolicyVersion(), param));
-        appendChildren(root, SepolicyVersionConverter{}, object.sepolicyVersions(), param);
+    void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override {
+        appendChild(root, KernelSepolicyVersionConverter{}(object.kernelSepolicyVersion(), d));
+        appendChildren(root, SepolicyVersionConverter{}, object.sepolicyVersions(), d);
     }
-    bool buildObject(Sepolicy* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
+    bool buildObject(Sepolicy* object, NodeType* root, std::string* error) const override {
         if (!parseChild(root, KernelSepolicyVersionConverter{}, &object->mKernelSepolicyVersion,
-                        param) ||
+                        error) ||
             !parseChildren(root, SepolicyVersionConverter{}, &object->mSepolicyVersionRanges,
-                           param)) {
+                           error)) {
             return false;
         }
         return true;
@@ -983,14 +907,13 @@
 
 struct [[deprecated]] VndkConverter : public XmlNodeConverter<Vndk> {
     std::string elementName() const override { return "vndk"; }
-    void mutateNode(const Vndk& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChild(root, VndkVersionRangeConverter{}(object.mVersionRange, param));
-        appendChildren(root, VndkLibraryConverter{}, object.mLibraries, param);
+    void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override {
+        appendChild(root, VndkVersionRangeConverter{}(object.mVersionRange, d));
+        appendChildren(root, VndkLibraryConverter{}, object.mLibraries, d);
     }
-    bool buildObject(Vndk* object, NodeType* root, const BuildObjectParam& param) const override {
-        if (!parseChild(root, VndkVersionRangeConverter{}, &object->mVersionRange, param) ||
-            !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, param)) {
+    bool buildObject(Vndk* object, NodeType* root, std::string* error) const override {
+        if (!parseChild(root, VndkVersionRangeConverter{}, &object->mVersionRange, error) ||
+            !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, error)) {
             return false;
         }
         return true;
@@ -999,15 +922,13 @@
 
 struct VendorNdkConverter : public XmlNodeConverter<VendorNdk> {
     std::string elementName() const override { return "vendor-ndk"; }
-    void mutateNode(const VendorNdk& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChild(root, VndkVersionConverter{}(object.mVersion, param));
-        appendChildren(root, VndkLibraryConverter{}, object.mLibraries, param);
+    void mutateNode(const VendorNdk& object, NodeType* root, DocType* d) const override {
+        appendChild(root, VndkVersionConverter{}(object.mVersion, d));
+        appendChildren(root, VndkLibraryConverter{}, object.mLibraries, d);
     }
-    bool buildObject(VendorNdk* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        if (!parseChild(root, VndkVersionConverter{}, &object->mVersion, param) ||
-            !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, param)) {
+    bool buildObject(VendorNdk* object, NodeType* root, std::string* error) const override {
+        if (!parseChild(root, VndkVersionConverter{}, &object->mVersion, error) ||
+            !parseChildren(root, VndkLibraryConverter{}, &object->mLibraries, error)) {
             return false;
         }
         return true;
@@ -1020,43 +941,37 @@
 
 struct SystemSdkConverter : public XmlNodeConverter<SystemSdk> {
     std::string elementName() const override { return "system-sdk"; }
-    void mutateNode(const SystemSdk& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChildren(root, SystemSdkVersionConverter{}, object.versions(), param);
+    void mutateNode(const SystemSdk& object, NodeType* root, DocType* d) const override {
+        appendChildren(root, SystemSdkVersionConverter{}, object.versions(), d);
     }
-    bool buildObject(SystemSdk* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseChildren(root, SystemSdkVersionConverter{}, &object->mVersions, param);
+    bool buildObject(SystemSdk* object, NodeType* root, std::string* error) const override {
+        return parseChildren(root, SystemSdkVersionConverter{}, &object->mVersions, error);
     }
 };
 
 struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
     std::string elementName() const override { return "sepolicy"; }
-    void mutateNode(const Version& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChild(root, VersionConverter{}(object, param));
+    void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
+        appendChild(root, VersionConverter{}(m, d));
     }
-    bool buildObject(Version* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseChild(root, VersionConverter{}, object, param);
+    bool buildObject(Version* object, NodeType* root, std::string* error) const override {
+        return parseChild(root, VersionConverter{}, object, error);
     }
 };
 
 struct ManifestXmlFileConverter : public XmlNodeConverter<ManifestXmlFile> {
     std::string elementName() const override { return "xmlfile"; }
-    void mutateNode(const ManifestXmlFile& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendTextElement(root, "name", object.name(), param.d);
-        appendChild(root, VersionConverter{}(object.version(), param));
-        if (!object.overriddenPath().empty()) {
-            appendTextElement(root, "path", object.overriddenPath(), param.d);
+    void mutateNode(const ManifestXmlFile& f, NodeType* root, DocType* d) const override {
+        appendTextElement(root, "name", f.name(), d);
+        appendChild(root, VersionConverter{}(f.version(), d));
+        if (!f.overriddenPath().empty()) {
+            appendTextElement(root, "path", f.overriddenPath(), d);
         }
     }
-    bool buildObject(ManifestXmlFile* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        if (!parseTextElement(root, "name", &object->mName, param.error) ||
-            !parseChild(root, VersionConverter{}, &object->mVersion, param) ||
-            !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, param.error)) {
+    bool buildObject(ManifestXmlFile* object, NodeType* root, std::string* error) const override {
+        if (!parseTextElement(root, "name", &object->mName, error) ||
+            !parseChild(root, VersionConverter{}, &object->mVersion, error) ||
+            !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) {
             return false;
         }
         return true;
@@ -1079,93 +994,95 @@
 
 struct KernelInfoConverter : public XmlNodeConverter<KernelInfo> {
     std::string elementName() const override { return "kernel"; }
-    void mutateNode(const KernelInfo& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        if (object.version() != KernelVersion{}) {
-            appendAttr(root, "version", object.version());
+    void mutateNode(const KernelInfo& o, NodeType* root, DocType* d) const override {
+        mutateNode(o, root, d, SerializeFlags::EVERYTHING);
+    }
+    void mutateNode(const KernelInfo& o, NodeType* root, DocType* d,
+                    SerializeFlags::Type flags) const override {
+        if (o.version() != KernelVersion{}) {
+            appendAttr(root, "version", o.version());
         }
-        if (object.level() != Level::UNSPECIFIED) {
-            appendAttr(root, "target-level", object.level());
+        if (o.level() != Level::UNSPECIFIED) {
+            appendAttr(root, "target-level", o.level());
         }
-        if (param.flags.isKernelConfigsEnabled()) {
-            appendChildren(root, StringKernelConfigConverter{}, object.configs(), param);
+        if (flags.isKernelConfigsEnabled()) {
+            appendChildren(root, StringKernelConfigConverter{}, o.configs(), d);
         }
     }
-    bool buildObject(KernelInfo* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseOptionalAttr(root, "version", {}, &object->mVersion, param.error) &&
-               parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
-                                 param.error) &&
-               parseChildren(root, StringKernelConfigConverter{}, &object->mConfigs, param);
+    bool buildObject(KernelInfo* o, NodeType* root, std::string* error) const override {
+        return parseOptionalAttr(root, "version", {}, &o->mVersion, error) &&
+               parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &o->mLevel, error) &&
+               parseChildren(root, StringKernelConfigConverter{}, &o->mConfigs, error);
     }
 };
 
 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
     std::string elementName() const override { return "manifest"; }
-    void mutateNode(const HalManifest& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        if (param.flags.isMetaVersionEnabled()) {
-            appendAttr(root, "version", object.getMetaVersion());
+    void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
+        mutateNode(m, root, d, SerializeFlags::EVERYTHING);
+    }
+    void mutateNode(const HalManifest& m, NodeType* root, DocType* d,
+                    SerializeFlags::Type flags) const override {
+        if (flags.isMetaVersionEnabled()) {
+            appendAttr(root, "version", m.getMetaVersion());
         }
-        if (param.flags.isSchemaTypeEnabled()) {
-            appendAttr(root, "type", object.mType);
+        if (flags.isSchemaTypeEnabled()) {
+            appendAttr(root, "type", m.mType);
         }
 
-        if (param.flags.isHalsEnabled()) {
-            appendChildren(root, ManifestHalConverter{}, object.getHals(), param);
+        if (flags.isHalsEnabled()) {
+            appendChildren(root, ManifestHalConverter{}, m.getHals(), d, flags);
         }
-        if (object.mType == SchemaType::DEVICE) {
-            if (param.flags.isSepolicyEnabled()) {
-                if (object.device.mSepolicyVersion != Version{}) {
-                    appendChild(root, HalManifestSepolicyConverter{}(object.device.mSepolicyVersion,
-                                                                     param));
+        if (m.mType == SchemaType::DEVICE) {
+            if (flags.isSepolicyEnabled()) {
+                if (m.device.mSepolicyVersion != Version{}) {
+                    appendChild(root, HalManifestSepolicyConverter{}(m.device.mSepolicyVersion, d));
                 }
             }
-            if (object.mLevel != Level::UNSPECIFIED) {
-                this->appendAttr(root, "target-level", object.mLevel);
+            if (m.mLevel != Level::UNSPECIFIED) {
+                this->appendAttr(root, "target-level", m.mLevel);
             }
 
-            if (param.flags.isKernelEnabled()) {
-                if (!!object.kernel()) {
-                    appendChild(root, KernelInfoConverter{}(*object.kernel(), param));
+            if (flags.isKernelEnabled()) {
+                if (!!m.kernel()) {
+                    appendChild(root, KernelInfoConverter{}(*m.kernel(), d, flags));
                 }
             }
-        } else if (object.mType == SchemaType::FRAMEWORK) {
-            if (param.flags.isVndkEnabled()) {
+        } else if (m.mType == SchemaType::FRAMEWORK) {
+            if (flags.isVndkEnabled()) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-                appendChildren(root, VndkConverter{}, object.framework.mVndks, param);
+                appendChildren(root, VndkConverter{}, m.framework.mVndks, d);
 #pragma clang diagnostic pop
 
-                appendChildren(root, VendorNdkConverter{}, object.framework.mVendorNdks, param);
+                appendChildren(root, VendorNdkConverter{}, m.framework.mVendorNdks, d);
             }
-            if (param.flags.isSsdkEnabled()) {
-                if (!object.framework.mSystemSdk.empty()) {
-                    appendChild(root, SystemSdkConverter{}(object.framework.mSystemSdk, param));
+            if (flags.isSsdkEnabled()) {
+                if (!m.framework.mSystemSdk.empty()) {
+                    appendChild(root, SystemSdkConverter{}(m.framework.mSystemSdk, d));
                 }
             }
         }
 
-        if (param.flags.isXmlFilesEnabled()) {
-            appendChildren(root, ManifestXmlFileConverter{}, object.getXmlFiles(), param);
+        if (flags.isXmlFilesEnabled()) {
+            appendChildren(root, ManifestXmlFileConverter{}, m.getXmlFiles(), d);
         }
     }
-    bool buildObject(HalManifest* object, NodeType* root,
-                     const BuildObjectParam& constParam) const override {
-        BuildObjectParam param = constParam;
-        if (!parseAttr(root, "version", &param.metaVersion, param.error)) return false;
-        if (param.metaVersion > kMetaVersion) {
-            *param.error = "Unrecognized manifest.version " + to_string(param.metaVersion) +
-                           " (libvintf@" + to_string(kMetaVersion) + ")";
+    bool buildObject(HalManifest* object, NodeType* root, std::string* error) const override {
+        Version metaVersion;
+        if (!parseAttr(root, "version", &metaVersion, error)) return false;
+        if (metaVersion > kMetaVersion) {
+            *error = "Unrecognized manifest.version " + to_string(metaVersion) + " (libvintf@" +
+                     to_string(kMetaVersion) + ")";
             return false;
         }
 
-        if (!parseAttr(root, "type", &object->mType, param.error)) {
+        if (!parseAttr(root, "type", &object->mType, error)) {
             return false;
         }
 
         std::vector<ManifestHal> hals;
-        if (!parseChildren(root, ManifestHalConverter{}, &hals, param)) {
+        if (!parseChildren(root, ManifestHalConverter{}, &hals, error)) {
             return false;
         }
         for (auto&& hal : hals) {
@@ -1177,68 +1094,68 @@
             // <sepolicy> can be missing because it can be determined at build time, not hard-coded
             // in the XML file.
             if (!parseOptionalChild(root, HalManifestSepolicyConverter{}, {},
-                                    &object->device.mSepolicyVersion, param)) {
+                                    &object->device.mSepolicyVersion, error)) {
                 return false;
             }
 
             if (!parseOptionalAttr(root, "target-level", Level::UNSPECIFIED, &object->mLevel,
-                                   param.error)) {
+                                   error)) {
                 return false;
             }
 
-            if (!parseOptionalChild(root, KernelInfoConverter{}, &object->device.mKernel, param)) {
+            if (!parseOptionalChild(root, KernelInfoConverter{}, &object->device.mKernel, error)) {
                 return false;
             }
         } else if (object->mType == SchemaType::FRAMEWORK) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-            if (!parseChildren(root, VndkConverter{}, &object->framework.mVndks, param)) {
+            if (!parseChildren(root, VndkConverter{}, &object->framework.mVndks, error)) {
                 return false;
             }
-            for (const auto& vndk : object->framework.mVndks) {
+            for (const auto &vndk : object->framework.mVndks) {
                 if (!vndk.mVersionRange.isSingleVersion()) {
-                    *param.error = "vndk.version " + to_string(vndk.mVersionRange) +
-                                   " cannot be a range for manifests";
+                    *error = "vndk.version " + to_string(vndk.mVersionRange) +
+                             " cannot be a range for manifests";
                     return false;
                 }
             }
 #pragma clang diagnostic pop
 
-            if (!parseChildren(root, VendorNdkConverter{}, &object->framework.mVendorNdks, param)) {
+            if (!parseChildren(root, VendorNdkConverter{}, &object->framework.mVendorNdks, error)) {
                 return false;
             }
 
             std::set<std::string> vendorNdkVersions;
             for (const auto& vendorNdk : object->framework.mVendorNdks) {
                 if (vendorNdkVersions.find(vendorNdk.version()) != vendorNdkVersions.end()) {
-                    *param.error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
+                    *error = "Duplicated manifest.vendor-ndk.version " + vendorNdk.version();
                     return false;
                 }
                 vendorNdkVersions.insert(vendorNdk.version());
             }
 
             if (!parseOptionalChild(root, SystemSdkConverter{}, {}, &object->framework.mSystemSdk,
-                                    param)) {
+                                    error)) {
                 return false;
             }
         }
         for (auto &&hal : hals) {
             std::string description{hal.name};
             if (!object->add(std::move(hal))) {
-                *param.error = "Duplicated manifest.hal entry " + description;
+                *error = "Duplicated manifest.hal entry " + description;
                 return false;
             }
         }
 
         std::vector<ManifestXmlFile> xmlFiles;
-        if (!parseChildren(root, ManifestXmlFileConverter{}, &xmlFiles, param)) {
+        if (!parseChildren(root, ManifestXmlFileConverter{}, &xmlFiles, error)) {
             return false;
         }
         for (auto&& xmlFile : xmlFiles) {
             std::string description{xmlFile.name()};
             if (!object->addXmlFile(std::move(xmlFile))) {
-                *param.error = "Duplicated manifest.xmlfile entry " + description +
-                               "; entries cannot have duplicated name and version";
+                *error = "Duplicated manifest.xmlfile entry " + description +
+                         "; entries cannot have duplicated name and version";
                 return false;
             }
         }
@@ -1253,35 +1170,31 @@
 
 struct AvbConverter : public XmlNodeConverter<Version> {
     std::string elementName() const override { return "avb"; }
-    void mutateNode(const Version& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendChild(root, AvbVersionConverter{}(object, param));
+    void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
+        appendChild(root, AvbVersionConverter{}(m, d));
     }
-    bool buildObject(Version* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        return parseChild(root, AvbVersionConverter{}, object, param);
+    bool buildObject(Version* object, NodeType* root, std::string* error) const override {
+        return parseChild(root, AvbVersionConverter{}, object, error);
     }
 };
 
 struct MatrixXmlFileConverter : public XmlNodeConverter<MatrixXmlFile> {
     std::string elementName() const override { return "xmlfile"; }
-    void mutateNode(const MatrixXmlFile& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        appendTextElement(root, "name", object.name(), param.d);
-        appendAttr(root, "format", object.format());
-        appendAttr(root, "optional", object.optional());
-        appendChild(root, VersionRangeConverter{}(object.versionRange(), param));
-        if (!object.overriddenPath().empty()) {
-            appendTextElement(root, "path", object.overriddenPath(), param.d);
+    void mutateNode(const MatrixXmlFile& f, NodeType* root, DocType* d) const override {
+        appendTextElement(root, "name", f.name(), d);
+        appendAttr(root, "format", f.format());
+        appendAttr(root, "optional", f.optional());
+        appendChild(root, VersionRangeConverter{}(f.versionRange(), d));
+        if (!f.overriddenPath().empty()) {
+            appendTextElement(root, "path", f.overriddenPath(), d);
         }
     }
-    bool buildObject(MatrixXmlFile* object, NodeType* root,
-                     const BuildObjectParam& param) const override {
-        if (!parseTextElement(root, "name", &object->mName, param.error) ||
-            !parseAttr(root, "format", &object->mFormat, param.error) ||
-            !parseOptionalAttr(root, "optional", false, &object->mOptional, param.error) ||
-            !parseChild(root, VersionRangeConverter{}, &object->mVersionRange, param) ||
-            !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, param.error)) {
+    bool buildObject(MatrixXmlFile* object, NodeType* root, std::string* error) const override {
+        if (!parseTextElement(root, "name", &object->mName, error) ||
+            !parseAttr(root, "format", &object->mFormat, error) ||
+            !parseOptionalAttr(root, "optional", false, &object->mOptional, error) ||
+            !parseChild(root, VersionRangeConverter{}, &object->mVersionRange, error) ||
+            !parseOptionalTextElement(root, "path", {}, &object->mOverriddenPath, error)) {
             return false;
         }
         return true;
@@ -1290,85 +1203,87 @@
 
 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
     std::string elementName() const override { return "compatibility-matrix"; }
-    void mutateNode(const CompatibilityMatrix& object, NodeType* root,
-                    const MutateNodeParam& param) const override {
-        if (param.flags.isMetaVersionEnabled()) {
+    void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
+        mutateNode(m, root, d, SerializeFlags::EVERYTHING);
+    }
+    void mutateNode(const CompatibilityMatrix& m, NodeType* root, DocType* d,
+                    SerializeFlags::Type flags) const override {
+        if (flags.isMetaVersionEnabled()) {
             appendAttr(root, "version", kMetaVersion);
         }
-        if (param.flags.isSchemaTypeEnabled()) {
-            appendAttr(root, "type", object.mType);
+        if (flags.isSchemaTypeEnabled()) {
+            appendAttr(root, "type", m.mType);
         }
 
-        if (param.flags.isHalsEnabled()) {
-            appendChildren(root, MatrixHalConverter{}, iterateValues(object.mHals), param);
+        if (flags.isHalsEnabled()) {
+            appendChildren(root, MatrixHalConverter{}, iterateValues(m.mHals), d);
         }
-        if (object.mType == SchemaType::FRAMEWORK) {
-            if (param.flags.isKernelEnabled()) {
-                appendChildren(root, MatrixKernelConverter{}, object.framework.mKernels, param);
+        if (m.mType == SchemaType::FRAMEWORK) {
+            if (flags.isKernelEnabled()) {
+                appendChildren(root, MatrixKernelConverter{}, m.framework.mKernels, d, flags);
             }
-            if (param.flags.isSepolicyEnabled()) {
-                if (!(object.framework.mSepolicy == Sepolicy{})) {
-                    appendChild(root, SepolicyConverter{}(object.framework.mSepolicy, param));
+            if (flags.isSepolicyEnabled()) {
+                if (!(m.framework.mSepolicy == Sepolicy{})) {
+                    appendChild(root, SepolicyConverter{}(m.framework.mSepolicy, d));
                 }
             }
-            if (param.flags.isAvbEnabled()) {
-                if (!(object.framework.mAvbMetaVersion == Version{})) {
-                    appendChild(root, AvbConverter{}(object.framework.mAvbMetaVersion, param));
+            if (flags.isAvbEnabled()) {
+                if (!(m.framework.mAvbMetaVersion == Version{})) {
+                    appendChild(root, AvbConverter{}(m.framework.mAvbMetaVersion, d));
                 }
             }
-            if (object.mLevel != Level::UNSPECIFIED) {
-                this->appendAttr(root, "level", object.mLevel);
+            if (m.mLevel != Level::UNSPECIFIED) {
+                this->appendAttr(root, "level", m.mLevel);
             }
-        } else if (object.mType == SchemaType::DEVICE) {
-            if (param.flags.isVndkEnabled()) {
+        } else if (m.mType == SchemaType::DEVICE) {
+            if (flags.isVndkEnabled()) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-                if (!(object.device.mVndk == Vndk{})) {
-                    appendChild(root, VndkConverter{}(object.device.mVndk, param));
+                if (!(m.device.mVndk == Vndk{})) {
+                    appendChild(root, VndkConverter{}(m.device.mVndk, d));
                 }
 #pragma clang diagnostic pop
 
-                if (!(object.device.mVendorNdk == VendorNdk{})) {
-                    appendChild(root, VendorNdkConverter{}(object.device.mVendorNdk, param));
+                if (!(m.device.mVendorNdk == VendorNdk{})) {
+                    appendChild(root, VendorNdkConverter{}(m.device.mVendorNdk, d));
                 }
             }
 
-            if (param.flags.isSsdkEnabled()) {
-                if (!object.device.mSystemSdk.empty()) {
-                    appendChild(root, SystemSdkConverter{}(object.device.mSystemSdk, param));
+            if (flags.isSsdkEnabled()) {
+                if (!m.device.mSystemSdk.empty()) {
+                    appendChild(root, SystemSdkConverter{}(m.device.mSystemSdk, d));
                 }
             }
         }
 
-        if (param.flags.isXmlFilesEnabled()) {
-            appendChildren(root, MatrixXmlFileConverter{}, object.getXmlFiles(), param);
+        if (flags.isXmlFilesEnabled()) {
+            appendChildren(root, MatrixXmlFileConverter{}, m.getXmlFiles(), d);
         }
     }
     bool buildObject(CompatibilityMatrix* object, NodeType* root,
-                     const BuildObjectParam& constParam) const override {
-        BuildObjectParam param = constParam;
-        if (!parseAttr(root, "version", &param.metaVersion, param.error)) return false;
-        if (param.metaVersion > kMetaVersion) {
-            *param.error = "Unrecognized compatibility-matrix.version " +
-                           to_string(param.metaVersion) + " (libvintf@" + to_string(kMetaVersion) +
-                           ")";
+                     std::string* error) const override {
+        Version metaVersion;
+        if (!parseAttr(root, "version", &metaVersion, error)) return false;
+        if (metaVersion > kMetaVersion) {
+            *error = "Unrecognized compatibility-matrix.version " + to_string(metaVersion) +
+                     " (libvintf@" + to_string(kMetaVersion) + ")";
             return false;
         }
 
         std::vector<MatrixHal> hals;
-        if (!parseAttr(root, "type", &object->mType, param.error) ||
-            !parseChildren(root, MatrixHalConverter{}, &hals, param)) {
+        if (!parseAttr(root, "type", &object->mType, error) ||
+            !parseChildren(root, MatrixHalConverter{}, &hals, error)) {
             return false;
         }
 
         if (object->mType == SchemaType::FRAMEWORK) {
             // <avb> and <sepolicy> can be missing because it can be determined at build time, not
             // hard-coded in the XML file.
-            if (!parseChildren(root, MatrixKernelConverter{}, &object->framework.mKernels, param) ||
+            if (!parseChildren(root, MatrixKernelConverter{}, &object->framework.mKernels, error) ||
                 !parseOptionalChild(root, SepolicyConverter{}, {}, &object->framework.mSepolicy,
-                                    param) ||
+                                    error) ||
                 !parseOptionalChild(root, AvbConverter{}, {}, &object->framework.mAvbMetaVersion,
-                                    param)) {
+                                    error)) {
                 return false;
             }
 
@@ -1379,15 +1294,14 @@
                     continue;
                 }
                 if (!kernel.conditions().empty()) {
-                    *param.error = "First <kernel> for version " + to_string(minLts) +
-                                   " must have empty <conditions> for backwards compatibility.";
+                    *error = "First <kernel> for version " + to_string(minLts) +
+                             " must have empty <conditions> for backwards compatibility.";
                     return false;
                 }
                 seenKernelVersions.insert(minLts);
             }
 
-            if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel,
-                                   param.error)) {
+            if (!parseOptionalAttr(root, "level", Level::UNSPECIFIED, &object->mLevel, error)) {
                 return false;
             }
 
@@ -1396,42 +1310,42 @@
             // in the XML file.
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-            if (!parseOptionalChild(root, VndkConverter{}, {}, &object->device.mVndk, param)) {
+            if (!parseOptionalChild(root, VndkConverter{}, {}, &object->device.mVndk, error)) {
                 return false;
             }
 #pragma clang diagnostic pop
 
             if (!parseOptionalChild(root, VendorNdkConverter{}, {}, &object->device.mVendorNdk,
-                                    param)) {
+                                    error)) {
                 return false;
             }
 
             if (!parseOptionalChild(root, SystemSdkConverter{}, {}, &object->device.mSystemSdk,
-                                    param)) {
+                                    error)) {
                 return false;
             }
         }
 
         for (auto &&hal : hals) {
             if (!object->add(std::move(hal))) {
-                *param.error = "Duplicated compatibility-matrix.hal entry";
+                *error = "Duplicated compatibility-matrix.hal entry";
                 return false;
             }
         }
 
         std::vector<MatrixXmlFile> xmlFiles;
-        if (!parseChildren(root, MatrixXmlFileConverter{}, &xmlFiles, param)) {
+        if (!parseChildren(root, MatrixXmlFileConverter{}, &xmlFiles, error)) {
             return false;
         }
         for (auto&& xmlFile : xmlFiles) {
             if (!xmlFile.optional()) {
-                *param.error = "compatibility-matrix.xmlfile entry " + xmlFile.name() +
-                               " has to be optional for compatibility matrix version 1.0";
+                *error = "compatibility-matrix.xmlfile entry " + xmlFile.name() +
+                         " has to be optional for compatibility matrix version 1.0";
                 return false;
             }
             std::string description{xmlFile.name()};
             if (!object->addXmlFile(std::move(xmlFile))) {
-                *param.error = "Duplicated compatibility-matrix.xmlfile entry " + description;
+                *error = "Duplicated compatibility-matrix.xmlfile entry " + description;
                 return false;
             }
         }
@@ -1442,10 +1356,10 @@
 
 #define CREATE_CONVERT_FN(type)                                         \
     std::string toXml(const type& o, SerializeFlags::Type flags) {      \
-        return type##Converter{}.toXml(o, flags);                       \
+        return type##Converter{}(o, flags);                             \
     }                                                                   \
     bool fromXml(type* o, const std::string& xml, std::string* error) { \
-        return type##Converter{}.fromXml(o, xml, error);                \
+        return type##Converter{}(o, xml, error);                        \
     }
 
 // Create convert functions for public usage.
diff --git a/test/Android.bp b/test/Android.bp
index 579eab8..dfd49dd 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -25,9 +25,6 @@
     defaults: ["libvintf-defaults"],
     host_supported: true,
     gtest: false,
-    tidy_timeout_srcs: [
-        "LibVintfTest.cpp",
-    ],
     srcs: [
         "AssembleVintfTest.cpp",
         "LibVintfTest.cpp",
@@ -76,9 +73,6 @@
     defaults: ["libvintf-defaults"],
     host_supported: true,
     native_coverage: true,
-    tidy_timeout_srcs: [
-        "vintf_object_tests.cpp",
-    ],
     srcs: [
         "RuntimeInfo-fake.cpp",
         "vintf_object_tests.cpp",
@@ -131,23 +125,3 @@
         "VintfFmTest.cpp",
     ],
 }
-
-cc_test_host {
-    name: "vintf_object_recovery_test",
-    defaults: [
-        "libvintf-defaults",
-        "libvintf_static_user_defaults",
-    ],
-    static_libs: [
-        "libgmock",
-        "libvintf",
-        "libutils",
-    ],
-    header_libs: [
-        "libvintf_local_headers",
-    ],
-    srcs: [
-        "RuntimeInfo-fake.cpp",
-        "VintfObjectRecoveryTest.cpp",
-    ],
-}
diff --git a/test/AssembleVintfTest.cpp b/test/AssembleVintfTest.cpp
index ff5da3e..882f882 100644
--- a/test/AssembleVintfTest.cpp
+++ b/test/AssembleVintfTest.cpp
@@ -17,16 +17,12 @@
 #define LOG_TAG "AssembleVintfTest"
 
 #include <android-base/logging.h>
-#include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
 #include <vintf/AssembleVintf.h>
 #include <vintf/parse_string.h>
-#include "constants-private.h"
 #include "test_constants.h"
 
-using android::base::StringPrintf;
-
 namespace android {
 namespace vintf {
 
@@ -617,15 +613,6 @@
     EXPECT_IN("<kernel version=\"3.18.10\">", getOutput());
 }
 
-TEST_F(AssembleVintfTest, NoKernelFcmT) {
-    addInput("manifest.xml",
-        StringPrintf(R"(<manifest %s type="device" target-level="%s">
-                            <kernel target-level="10"/>
-                        </manifest>)", kMetaVersionStr.c_str(),
-                        to_string(details::kEnforceDeviceManifestNoKernelLevel).c_str()));
-    EXPECT_FALSE(getInstance()->assemble());
-}
-
 // Automatically add kernel FCM when parsing framework matrix for a single FCM version.
 TEST_F(AssembleVintfTest, AutoSetMatrixKernelFcm) {
     addInput("compatibility_matrix.xml",
diff --git a/test/LibVintfTest.cpp b/test/LibVintfTest.cpp
index c1bb612..182beea 100644
--- a/test/LibVintfTest.cpp
+++ b/test/LibVintfTest.cpp
@@ -18,11 +18,9 @@
 
 #include <algorithm>
 #include <functional>
-#include <vector>
 
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -37,21 +35,24 @@
 #include "parse_xml_internal.h"
 #include "test_constants.h"
 
-using android::base::StringPrintf;
-using ::testing::Combine;
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::HasSubstr;
 using ::testing::Optional;
 using ::testing::Property;
-using ::testing::Range;
 using ::testing::SizeIs;
-using ::testing::TestParamInfo;
 
 namespace android {
 namespace vintf {
 
-#define EXPECT_IN(sub, str) EXPECT_THAT(str, HasSubstr(sub))
+static bool In(const std::string& sub, const std::string& str) {
+    return str.find(sub) != std::string::npos;
+}
+#define EXPECT_IN(sub, str) EXPECT_TRUE(In((sub), (str))) << (str);
+
+#ifndef LIBVINTF_TARGET
+#define EXPECT_CONTAINS(str, sub) EXPECT_IN(sub, str);
+#endif
 
 struct LibVintfTest : public ::testing::Test {
 public:
@@ -2922,129 +2923,6 @@
     EXPECT_THAT(foo.front()->updatableViaApex(), Optional(Eq("com.android.foo")));
 }
 
-TEST_F(LibVintfTest, ParsingHalsInetTransport) {
-    std::string error;
-
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
-        "    <hal format=\"aidl\">\n"
-        "        <name>android.hardware.foo</name>\n"
-        "        <transport ip=\"1.2.3.4\" port=\"12\">inet</transport>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>default</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "</manifest>\n";
-    EXPECT_TRUE(fromXml(&manifest, manifestXml, &error)) << error;
-    EXPECT_EQ(manifestXml, toXml(manifest, SerializeFlags::HALS_NO_FQNAME));
-
-    auto foo = getHals(manifest, "android.hardware.foo");
-    ASSERT_EQ(1u, foo.size());
-    ASSERT_TRUE(foo.front()->ip().has_value());
-    ASSERT_TRUE(foo.front()->port().has_value());
-    EXPECT_EQ("1.2.3.4", *foo.front()->ip());
-    EXPECT_EQ(12, *foo.front()->port());
-}
-
-TEST_F(LibVintfTest, RejectHalsInetTransportNoAttrs) {
-    std::string error;
-
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
-        "    <hal format=\"aidl\">\n"
-        "        <name>android.hardware.foo</name>\n"
-        "        <transport>inet</transport>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>default</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "</manifest>\n";
-    EXPECT_FALSE(fromXml(&manifest, manifestXml, &error));
-    EXPECT_IN("Transport inet requires ip and port attributes", error);
-}
-
-TEST_F(LibVintfTest, RejectHalsInetTransportMissingAttrs) {
-    std::string error;
-
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
-        "    <hal format=\"aidl\">\n"
-        "        <name>android.hardware.foo</name>\n"
-        "        <transport ip=\"1.2.3.4\">inet</transport>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>default</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "</manifest>\n";
-    EXPECT_FALSE(fromXml(&manifest, manifestXml, &error));
-    EXPECT_IN("Transport inet requires ip and port", error);
-}
-
-TEST_F(LibVintfTest, RejectHalsEmptyTransportWithInetAttrs) {
-    std::string error;
-
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
-        "    <hal format=\"aidl\">\n"
-        "        <name>android.hardware.foo</name>\n"
-        "        <transport ip=\"1.2.3.4\" port=\"12\"></transport>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>default</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "</manifest>\n";
-    EXPECT_FALSE(fromXml(&manifest, manifestXml, &error));
-    EXPECT_IN("Transport  requires empty ip and port attributes", error);
-}
-
-TEST_F(LibVintfTest, RejectHidlHalsInetTransport) {
-    std::string error;
-
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>android.hardware.foo</name>\n"
-        "        <transport ip=\"1.2.3.4\" port=\"12\">inet</transport>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>default</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "</manifest>\n";
-    EXPECT_FALSE(fromXml(&manifest, manifestXml, &error));
-    EXPECT_IN(
-            "HIDL HAL 'android.hardware.foo' should not have <transport> \"inet\" or ip or port",
-            error);
-}
-
-TEST_F(LibVintfTest, RejectHidlHalsHwbinderInetAttrs) {
-    std::string error;
-
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + " type=\"device\">\n"
-        "    <hal format=\"hidl\">\n"
-        "        <name>android.hardware.foo</name>\n"
-        "        <transport ip=\"1.2.3.4\" port=\"12\">hwbinder</transport>\n"
-        "        <interface>\n"
-        "            <name>IFoo</name>\n"
-        "            <instance>default</instance>\n"
-        "        </interface>\n"
-        "    </hal>\n"
-        "</manifest>\n";
-    EXPECT_FALSE(fromXml(&manifest, manifestXml, &error));
-    EXPECT_IN("Transport hwbinder requires empty ip and port attributes", error);
-}
-
 TEST_F(LibVintfTest, SystemSdk) {
     CompatibilityMatrix cm;
     std::string xml;
@@ -3165,8 +3043,8 @@
             "</compatibility-matrix>\n";
         EXPECT_TRUE(fromXml(&cm, xml, &error)) << error;
         EXPECT_FALSE(manifest.checkCompatibility(cm, &error));
-        EXPECT_IN("Manifest level = 103", error);
-        EXPECT_IN("Matrix level = 100", error);
+        EXPECT_IN("Manifest level = 103", error)
+        EXPECT_IN("Matrix level = 100", error)
         EXPECT_IN(
             "android.hardware.foo:\n"
             "    required: \n"
@@ -4218,30 +4096,11 @@
                                         "default"));
 }
 
-TEST_F(LibVintfTest, RejectAidlHalsWithUnsupportedTransport) {
-    std::string error;
-    HalManifest manifest;
-    std::string manifestXml =
-        "<manifest " + kMetaVersionStr + R"( type="framework">"
-             <hal format="aidl">
-                 <name>android.system.foo</name>
-                 <transport>hwbinder</transport>
-                 <fqname>IFoo/default</fqname>
-             </hal>
-         </manifest>)";
-    EXPECT_FALSE(fromXml(&manifest, manifestXml, &error));
-    EXPECT_IN("android.system.foo", error);
-    EXPECT_IN("hwbinder", error);
-}
-
 TEST_F(LibVintfTest, GetTransportAidlHalWithDummyTransport) {
     // Check that even if <transport> is specified for AIDL, it is ignored and getHidlTransport
     // will return EMPTY.
-    // This is only supported for libvintf 4.0 and below.
-    constexpr Version kLegacyMetaVersion{4, 0};
-    ASSERT_GE(kMetaVersionAidlInet, kLegacyMetaVersion);
     std::string xml =
-        "<manifest version=\"" + to_string(kLegacyMetaVersion) + "\" type=\"framework\">\n"
+        "<manifest " + kMetaVersionStr + " type=\"framework\">\n"
         "    <hal format=\"aidl\">\n"
         "        <name>android.system.foo</name>\n"
         "        <transport>hwbinder</transport>\n"
@@ -4269,7 +4128,7 @@
     EXPECT_TRUE(fromXml(&manifest, xml, &error)) << error;
     auto names = manifest.getHalNamesAndVersions();
     ASSERT_EQ(1u, names.size());
-    EXPECT_EQ("android.system.foo@1", *names.begin());
+    EXPECT_EQ("android.system.foo", *names.begin());
 }
 
 TEST_F(LibVintfTest, ManifestAddAidl) {
@@ -4492,14 +4351,9 @@
     }
     // Access to private methods.
     std::unique_ptr<CompatibilityMatrix> combine(Level deviceLevel,
-                                                 std::vector<CompatibilityMatrix>* theMatrices,
-                                                 std::string* errorPtr) {
-        return CompatibilityMatrix::combine(deviceLevel, Level::UNSPECIFIED, theMatrices, errorPtr);
-    }
-    std::unique_ptr<CompatibilityMatrix> combine(Level deviceLevel, Level kernellevel,
-                                                 std::vector<CompatibilityMatrix>* theMatrices,
-                                                 std::string* errorPtr) {
-        return CompatibilityMatrix::combine(deviceLevel, kernellevel, theMatrices, errorPtr);
+                                                 std::vector<CompatibilityMatrix>* matrices,
+                                                 std::string* error) {
+        return CompatibilityMatrix::combine(deviceLevel, matrices, error);
     }
 
     std::vector<CompatibilityMatrix> matrices;
@@ -4690,94 +4544,6 @@
     }
 }
 
-// clang-format on
-
-class FcmCombineKernelTest : public FrameworkCompatibilityMatrixCombineTest,
-                             public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {
-   public:
-    static std::string PrintTestParams(const TestParamInfo<FcmCombineKernelTest::ParamType>& info) {
-        auto [deviceLevelNum, kernelLevelNum] = info.param;
-        return "device_" + std::to_string(deviceLevelNum) + "_kernel_" +
-               std::to_string(kernelLevelNum);
-    }
-    static constexpr size_t kMinLevel = 1;
-    static constexpr size_t kMaxLevel = 5;
-};
-
-TEST_P(FcmCombineKernelTest, OlderKernel) {
-    auto [deviceLevelNum, kernelLevelNum] = GetParam();
-
-    std::vector<size_t> levelNums;
-    for (size_t i = kMinLevel; i <= kMaxLevel; ++i) levelNums.push_back(i);
-
-    constexpr auto fmt = R"(
-        <compatibility-matrix %s type="framework" level="%s">
-            <hal format="hidl" optional="false">
-                <name>android.system.foo</name>
-                <version>%zu.0</version>
-                <interface>
-                    <name>IFoo</name>
-                    <instance>default</instance>
-                </interface>
-            </hal>
-            <kernel version="%zu.0.0">
-                <config>
-                    <key>CONFIG_%zu</key>
-                    <value type="tristate">y</value>
-                </config>
-            </kernel>
-        </compatibility-matrix>
-    )";
-    std::string error;
-    std::vector<CompatibilityMatrix> matrices;
-    for (size_t levelNum : levelNums) {
-        auto levelStr = android::vintf::to_string((Level)levelNum);
-        auto xml = StringPrintf(fmt, kMetaVersionStr.c_str(), levelStr.c_str(), levelNum, levelNum,
-                                levelNum);
-        CompatibilityMatrix& matrix = matrices.emplace_back();
-        ASSERT_TRUE(fromXml(&matrix, xml, &error)) << error;
-    }
-    ASSERT_FALSE(matrices.empty());
-
-    auto combined = combine(Level(deviceLevelNum), Level(kernelLevelNum), &matrices, &error);
-    ASSERT_NE(nullptr, combined);
-    auto combinedXml = toXml(*combined);
-
-    // Check that HALs are combined correctly.
-    for (size_t i = kMinLevel; i < deviceLevelNum; ++i)
-        EXPECT_THAT(combinedXml, Not(HasSubstr(StringPrintf("<version>%zu.0</version>", i))));
-
-    for (size_t i = deviceLevelNum; i <= kMaxLevel; ++i)
-        EXPECT_THAT(combinedXml, HasSubstr(StringPrintf("<version>%zu.0</version>", i)));
-
-    // Check that kernels are combined correctly. <kernel> tags from
-    // matrices with level >= min(kernelLevel, deviceLevel) are added.
-    // The "level" tag on <kernel> must also be set properly so that old kernel requirements from
-    // deviceLevel <= x < kernelLevel won't be used.
-    auto hasKernelFrom = std::min(kernelLevelNum, deviceLevelNum);
-    for (size_t i = kMinLevel; i < hasKernelFrom; ++i) {
-        EXPECT_THAT(combinedXml,
-                    Not(HasSubstr(StringPrintf(R"(<kernel version="%zu.0.0" level="%zu")", i, i))));
-        EXPECT_THAT(combinedXml, Not(HasSubstr(StringPrintf("CONFIG_%zu", i))));
-    }
-
-    for (size_t i = hasKernelFrom; i <= kMaxLevel; ++i) {
-        EXPECT_THAT(combinedXml,
-                    HasSubstr(StringPrintf(R"(<kernel version="%zu.0.0" level="%zu")", i, i)));
-        EXPECT_THAT(combinedXml, HasSubstr(StringPrintf("CONFIG_%zu", i)));
-    }
-
-    if (::testing::Test::HasFailure()) ADD_FAILURE() << "Resulting matrix is \n" << combinedXml;
-}
-
-INSTANTIATE_TEST_CASE_P(
-    FrameworkCompatibilityMatrixCombineTest, FcmCombineKernelTest,
-    Combine(Range(FcmCombineKernelTest::kMinLevel, FcmCombineKernelTest::kMaxLevel + 1),
-            Range(FcmCombineKernelTest::kMinLevel, FcmCombineKernelTest::kMaxLevel + 1)),
-    FcmCombineKernelTest::PrintTestParams);
-
-// clang-format off
-
 struct DeviceCompatibilityMatrixCombineTest : public LibVintfTest {
     virtual void SetUp() override {
         matrices.resize(2);
@@ -4785,9 +4551,9 @@
         matrices[1].setFileName("compatibility_matrix.2.xml");
     }
     // Access to private methods.
-    std::unique_ptr<CompatibilityMatrix> combine(std::vector<CompatibilityMatrix>* theMatrices,
-                                                 std::string* errorPtr) {
-        return CompatibilityMatrix::combineDeviceMatrices(theMatrices, errorPtr);
+    std::unique_ptr<CompatibilityMatrix> combine(std::vector<CompatibilityMatrix>* matrices,
+                                                 std::string* error) {
+        return CompatibilityMatrix::combineDeviceMatrices(matrices, error);
     }
 
     std::vector<CompatibilityMatrix> matrices;
diff --git a/test/VintfObjectRecoveryTest.cpp b/test/VintfObjectRecoveryTest.cpp
deleted file mode 100644
index 381d805..0000000
--- a/test/VintfObjectRecoveryTest.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2021 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 <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <vintf/VintfObjectRecovery.h>
-#include <vintf/parse_string.h>
-
-#include "constants-private.h"
-#include "test_constants.h"
-#include "utils-fake.h"
-
-using android::base::ConsumePrefix;
-using android::base::StringPrintf;
-using testing::_;
-using testing::Combine;
-using testing::Invoke;
-using testing::IsEmpty;
-using testing::Mock;
-using testing::NiceMock;
-using testing::StartsWith;
-using testing::StrEq;
-using testing::TestParamInfo;
-using testing::UnorderedElementsAre;
-using testing::ValuesIn;
-
-namespace android::vintf::testing {
-
-using details::kSystemManifest;
-using details::kSystemManifestFragmentDir;
-using details::MockFileSystemWithError;
-using details::MockPropertyFetcher;
-using details::MockRuntimeInfo;
-using details::MockRuntimeInfoFactory;
-
-template <typename T>
-using StatusOr = std::variant<status_t, T>;
-
-using DirectoryContent = std::map<std::string, StatusOr<std::string>>;
-
-using OptionalType = std::optional<SchemaType>;
-std::vector<OptionalType> OptionalTypes() {
-    return {std::nullopt, SchemaType::DEVICE, SchemaType::FRAMEWORK};
-}
-
-std::string OptionalTypeToString(const OptionalType& optionalType) {
-    if (!optionalType.has_value()) return "broken";
-    return to_string(*optionalType);
-}
-
-constexpr const char* kMainFmt = R"(<manifest %s type="%s">
-    <hal format="aidl">
-        <name>android.hardware.main</name>
-        <fqname>IMain/default</fqname>
-    </hal>
-</manifest>
-)";
-
-constexpr const char* kFragment1Fmt = R"(<manifest %s type="%s">
-    <hal format="aidl">
-        <name>android.hardware.fragment1</name>
-        <fqname>IFragment/default</fqname>
-    </hal>
-</manifest>
-)";
-
-constexpr const char* kFragment2Fmt = R"(<manifest %s type="%s">
-    <hal format="aidl">
-        <name>android.hardware.fragment2</name>
-        <fqname>IFragment/default</fqname>
-    </hal>
-</manifest>
-)";
-
-std::string formatManifest(const char* fmt, const OptionalType& optionalType) {
-    if (!optionalType.has_value()) {
-        return "(broken manifest)";
-    }
-    return StringPrintf(fmt, kMetaVersionStr.c_str(), to_string(*optionalType).c_str());
-}
-
-using VintfObjectRecoveryTestParam = std::tuple<OptionalType, OptionalType, OptionalType>;
-class VintfObjectRecoveryTest : public ::testing::TestWithParam<VintfObjectRecoveryTestParam> {
-   public:
-    virtual void SetUp() {
-        vintfObject = VintfObjectRecovery::Builder()
-                          .setFileSystem(std::make_unique<NiceMock<MockFileSystemWithError>>())
-                          .setRuntimeInfoFactory(std::make_unique<NiceMock<MockRuntimeInfoFactory>>(
-                              std::make_shared<NiceMock<MockRuntimeInfo>>()))
-                          .setPropertyFetcher(std::make_unique<NiceMock<MockPropertyFetcher>>())
-                          .build<VintfObjectRecovery>();
-        auto [mainType, fragType1, fragType2] = GetParam();
-        main = formatManifest(kMainFmt, mainType);
-        frag1 = formatManifest(kFragment1Fmt, fragType1);
-        frag2 = formatManifest(kFragment2Fmt, fragType2);
-    }
-    virtual void TearDown() { Mock::VerifyAndClear(&fs()); }
-
-    MockFileSystemWithError& fs() {
-        return static_cast<MockFileSystemWithError&>(*vintfObject->getFileSystem());
-    }
-
-    void setUpManifests(const StatusOr<std::string>& mainContent,
-                        const StatusOr<DirectoryContent>& frags) {
-        // By default, no files exist in the file system.
-        ON_CALL(fs(), listFiles(_, _, _)).WillByDefault(Return(NAME_NOT_FOUND));
-        ON_CALL(fs(), fetch(_, _, _))
-            .WillByDefault(Invoke([](const auto& path, auto*, auto* error) {
-                if (error != nullptr) {
-                    *error = "fetch " + path + ": cannot be found on empty filesystem: " +
-                             statusToString(NAME_NOT_FOUND);
-                }
-                return NAME_NOT_FOUND;
-            }));
-        ON_CALL(fs(), fetch(StrEq(kSystemManifest), _, _))
-            .WillByDefault(Invoke([=](const auto& path, auto* content, auto* error) -> status_t {
-                if (std::holds_alternative<status_t>(mainContent)) {
-                    if (error != nullptr) {
-                        *error = "fetch " + path + ": set to return " +
-                                 statusToString(std::get<status_t>(mainContent));
-                    }
-                    return std::get<status_t>(mainContent);
-                }
-                *content = std::get<std::string>(mainContent);
-                return OK;
-            }));
-        ON_CALL(fs(), listFiles(StrEq(kSystemManifestFragmentDir), _, _))
-            .WillByDefault(Invoke([=](const std::string& path, std::vector<std::string>* out,
-                                      auto* error) -> status_t {
-                if (std::holds_alternative<status_t>(frags)) {
-                    if (error != nullptr) {
-                        *error = "list " + path + ": set to return " +
-                                 statusToString(std::get<status_t>(frags));
-                    }
-                    return std::get<status_t>(frags);
-                }
-                for (const auto& [name, statusOrFile] : std::get<DirectoryContent>(frags)) {
-                    out->push_back(name);
-                }
-                return OK;
-            }));
-        ON_CALL(fs(), fetch(StartsWith(kSystemManifestFragmentDir), _, _))
-            .WillByDefault(Invoke([=](const auto& path, auto* content, auto* error) -> status_t {
-                if (std::holds_alternative<status_t>(frags)) {
-                    if (error != nullptr) {
-                        *error = "fetch " + path + ": for dir, set to return " +
-                                 statusToString(std::get<status_t>(frags));
-                    }
-                    return std::get<status_t>(frags);
-                }
-                const auto& directoryContent = std::get<DirectoryContent>(frags);
-                std::string_view subpath = path;
-                bool consumed = ConsumePrefix(&subpath, kSystemManifestFragmentDir);
-                EXPECT_TRUE(consumed)
-                    << path << " does not start with " << kSystemManifestFragmentDir;
-                auto it = directoryContent.find(std::string(subpath));
-                if (it == directoryContent.end()) {
-                    if (error != nullptr) {
-                        *error = "fetch " + path +
-                                 ": not in DirectoryContent: " + statusToString(NAME_NOT_FOUND);
-                    }
-                    return NAME_NOT_FOUND;
-                }
-
-                const auto& [name, statusOrFile] = *it;
-                if (std::holds_alternative<status_t>(statusOrFile)) {
-                    *error = "fetch " + path + ": for file, set to return " +
-                             statusToString(std::get<status_t>(statusOrFile));
-                    return std::get<status_t>(statusOrFile);
-                }
-                *content = std::get<std::string>(statusOrFile);
-                return OK;
-            }));
-    }
-
-    static std::string ParamToString(const TestParamInfo<ParamType>& info) {
-        auto [mainType, fragType1, fragType2] = info.param;
-        auto s = "main_" + OptionalTypeToString(mainType);
-        s += "_frag1_" + OptionalTypeToString(fragType1);
-        s += "_frag2_" + OptionalTypeToString(fragType2);
-        return s;
-    }
-
-    std::unique_ptr<VintfObjectRecovery> vintfObject;
-    std::string main;
-    std::string frag1;
-    std::string frag2;
-};
-
-TEST_P(VintfObjectRecoveryTest, Empty) {
-    setUpManifests(NAME_NOT_FOUND, NAME_NOT_FOUND);
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    ASSERT_NE(nullptr, manifest);
-    auto hals = manifest->getHalNames();
-    EXPECT_THAT(hals, IsEmpty());
-}
-
-TEST_P(VintfObjectRecoveryTest, InaccessibleMainManifest) {
-    setUpManifests(UNKNOWN_ERROR, NAME_NOT_FOUND);
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    EXPECT_EQ(nullptr, manifest);
-}
-
-TEST_P(VintfObjectRecoveryTest, MainManifestOnly) {
-    auto [mainType, fragType1, fragType2] = GetParam();
-    setUpManifests(main, NAME_NOT_FOUND);
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    if (!mainType.has_value()) {  // main manifest is broken
-        EXPECT_EQ(nullptr, manifest);
-        return;
-    }
-    ASSERT_NE(nullptr, manifest);
-    EXPECT_THAT(manifest->getHalNames(), UnorderedElementsAre("android.hardware.main"));
-}
-
-TEST_P(VintfObjectRecoveryTest, MainManifestAndDirectoryOnly) {
-    auto [mainType, fragType1, fragType2] = GetParam();
-    setUpManifests(main, {});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    if (!mainType.has_value()) {  // main manifest is broken
-        EXPECT_EQ(nullptr, manifest);
-        return;
-    }
-    ASSERT_NE(nullptr, manifest);
-    EXPECT_THAT(manifest->getHalNames(), UnorderedElementsAre("android.hardware.main"));
-}
-
-TEST_P(VintfObjectRecoveryTest, MainManifestAndInaccessibleFragment) {
-    setUpManifests(main, DirectoryContent{{"frag1.xml", UNKNOWN_ERROR}});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    EXPECT_EQ(nullptr, manifest);
-}
-
-TEST_P(VintfObjectRecoveryTest, MainManifestAndFragments) {
-    auto [mainType, fragType1, fragType2] = GetParam();
-    setUpManifests(main, DirectoryContent{{"frag1.xml", frag1}, {"frag2.xml", frag2}});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    if (!mainType.has_value() || !fragType1.has_value() || !fragType2.has_value()) {
-        // some manifest(s) are broken
-        EXPECT_EQ(nullptr, manifest);
-        return;
-    }
-    ASSERT_NE(nullptr, manifest);
-    EXPECT_THAT(manifest->getHalNames(),
-                UnorderedElementsAre("android.hardware.main", "android.hardware.fragment1",
-                                     "android.hardware.fragment2"));
-}
-
-TEST_P(VintfObjectRecoveryTest, InaccessibleDirectory) {
-    setUpManifests(NAME_NOT_FOUND, UNKNOWN_ERROR);
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    EXPECT_EQ(nullptr, manifest);
-}
-
-TEST_P(VintfObjectRecoveryTest, InaccessibleFragment) {
-    setUpManifests(NAME_NOT_FOUND, DirectoryContent{{"frag1.xml", UNKNOWN_ERROR}});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    EXPECT_EQ(nullptr, manifest);
-}
-
-TEST_P(VintfObjectRecoveryTest, SomeInaccessibleFragment) {
-    setUpManifests(NAME_NOT_FOUND,
-                   DirectoryContent{{"frag1.xml", UNKNOWN_ERROR}, {"frag2.xml", frag2}});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    EXPECT_EQ(nullptr, manifest);
-}
-
-TEST_P(VintfObjectRecoveryTest, DirectoryOnly) {
-    setUpManifests(NAME_NOT_FOUND, {});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    ASSERT_NE(nullptr, manifest);
-    EXPECT_THAT(manifest->getHalNames(), IsEmpty());
-}
-
-TEST_P(VintfObjectRecoveryTest, FragmentsOnly) {
-    auto [mainType, fragType1, fragType2] = GetParam();
-    setUpManifests(NAME_NOT_FOUND, DirectoryContent{{"frag1.xml", frag1}, {"frag2.xml", frag2}});
-    auto manifest = vintfObject->getRecoveryHalManifest();
-    if (!fragType1.has_value() || !fragType2.has_value()) {
-        // some manifest(s) are broken
-        EXPECT_EQ(nullptr, manifest);
-        return;
-    }
-    ASSERT_NE(nullptr, manifest);
-    EXPECT_THAT(manifest->getHalNames(),
-                UnorderedElementsAre("android.hardware.fragment1", "android.hardware.fragment2"));
-}
-
-INSTANTIATE_TEST_CASE_P(VintfObjectRecoveryTest, VintfObjectRecoveryTest,
-                        Combine(ValuesIn(OptionalTypes()), ValuesIn(OptionalTypes()),
-                                ValuesIn(OptionalTypes())),
-                        VintfObjectRecoveryTest::ParamToString);
-
-}  // namespace android::vintf::testing
diff --git a/test/utils-fake.h b/test/utils-fake.h
index 37219fa..846ea2c 100644
--- a/test/utils-fake.h
+++ b/test/utils-fake.h
@@ -45,14 +45,6 @@
     FileSystemImpl mImpl;
 };
 
-class MockFileSystemWithError : public FileSystem {
-   public:
-    MOCK_METHOD(status_t, fetch, (const std::string&, std::string*, std::string*),
-                (const override));
-    MOCK_METHOD(status_t, listFiles, (const std::string&, std::vector<std::string>*, std::string*),
-                (const override));
-};
-
 class MockRuntimeInfo : public RuntimeInfo {
    public:
     MockRuntimeInfo();
diff --git a/test/vintf_object_recovery_test.sh b/test/vintf_object_recovery_test.sh
new file mode 100755
index 0000000..7918c5f
--- /dev/null
+++ b/test/vintf_object_recovery_test.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -ex
+
+if [[ "$@" != *"--no-reboot"* ]]; then
+    adb reboot recovery
+    echo "Waiting for device to boot into recovery..."
+    adb wait-for-recovery
+fi
+adb root
+adb wait-for-recovery
+
+# There is no /data in recovery unless mounted.
+# Push test to /system directory in the recovery ramdisk
+adb push ${ANDROID_PRODUCT_OUT}/data/nativetest64/vintf_object_recovery_test/vintf_object_recovery_test \
+       /system/bin/vintf_object_recovery_test
+
+adb shell /system/bin/vintf_object_recovery_test
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 3a4c74a..75cdf28 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -18,11 +18,10 @@
 #include "gmock-logging-compat.h"
 
 #include <stdio.h>
-#include <optional>
+#include <unistd.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/result-gmock.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <gtest/gtest.h>
@@ -40,12 +39,13 @@
 using namespace std::literals;
 
 using android::FqInstance;
-using android::base::testing::HasError;
-using android::base::testing::Ok;
-using android::base::testing::WithMessage;
 
-#define EXPECT_IN(sub, str) EXPECT_THAT(str, HasSubstr(sub))
-#define EXPECT_NOT_IN(sub, str) EXPECT_THAT(str, Not(HasSubstr(sub)))
+static AssertionResult In(const std::string& sub, const std::string& str) {
+    return (str.find(sub) != std::string::npos ? AssertionSuccess() : AssertionFailure())
+           << "Value is " << str;
+}
+#define EXPECT_IN(sub, str) EXPECT_TRUE(In((sub), (str)))
+#define EXPECT_NOT_IN(sub, str) EXPECT_FALSE(In((sub), (str)))
 
 namespace android {
 namespace vintf {
@@ -1458,8 +1458,9 @@
     auto runtime = vintfObject->getRuntimeInfo();
     ASSERT_NE(nullptr, matrix);
     ASSERT_NE(nullptr, runtime);
-    std::string fallbackError = "Matrix is compatible with kernel info, but it shouldn't. Matrix:\n"
-        + toXml(*matrix) + "\nKernelInfo:\n" + toXml(info);
+    std::string fallbackError = kernelFcm == Level::UNSPECIFIED
+        ? "\nOld requirements must not change"
+        : "\nMust not pull unnecessary requirements from new matrices";
     std::string error;
     ASSERT_EQ(pass, runtime->checkCompatibility(*matrix, &error))
             << (pass ? error : fallbackError);
@@ -1481,11 +1482,6 @@
     ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D2"), Level{1}, Level{1}, false);
     ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{1}, Level{1}, true);
 
-    // Kernel FCM lower than target FCM
-    ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{2}, Level{1}, true);
-    ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{2}, Level{1}, true);
-    ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{2}, Level{1}, true);
-
     matrices = systemMatrixKernelXmls;
     ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{1}, Level::UNSPECIFIED, true);
     ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{1}, Level::UNSPECIFIED, true);
@@ -1521,25 +1517,6 @@
     ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{4}, Level{4}, true);
     ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{5}, Level{5}, false);
 
-    // Kernel FCM lower than target FCM
-    ret.emplace_back(matrices, MakeKernelInfo("1.0.0", "A1"), Level{2}, Level{1}, true);
-    ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B1"), Level{2}, Level{1}, true);
-    ret.emplace_back(matrices, MakeKernelInfo("2.0.0", "B2"), Level{2}, Level{1}, true);
-    ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C2"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("3.0.0", "C3"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D2"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("4.0.0", "D3"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("5.0.0", "E3"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("5.0.0", "E4"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F5"), Level{2}, Level{1}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("7.0.0", "G5"), Level{2}, Level{1}, false);
-
-    ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{3}, Level{2}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{4}, Level{3}, false);
-    ret.emplace_back(matrices, MakeKernelInfo("6.0.0", "F4"), Level{5}, Level{4}, true);
-    // We don't have device FCM 6 in systemMatrixKernelXmls, skip
-
     return ret;
 }
 
@@ -1893,6 +1870,35 @@
     OemFcmLevelTestParamToString);
 // clang-format on
 
+// A matcher that checks if a Result object contains an error message, and the error message
+// contains the given substring.
+class ErrorMessageMatcher {
+   public:
+    ErrorMessageMatcher(const std::string& message) : mMessage(message) {}
+    template <class T>
+    bool MatchAndExplain(const android::base::Result<T>& result,
+                         MatchResultListener* listener) const {
+        if (result.ok()) {
+            *listener << "result is ok";
+            return false;
+        }
+        *listener << "result has error message \"" << result.error().message() << "\"";
+        return result.error().message().find(mMessage) != std::string::npos;
+    }
+    void DescribeTo(std::ostream* os) const {
+        *os << "error message contains \"" << mMessage << "\"";
+    }
+    void DescribeNegationTo(std::ostream* os) const {
+        *os << "error message does not contain \"" << mMessage << "\"";
+    }
+
+   private:
+    std::string mMessage;
+};
+PolymorphicMatcher<ErrorMessageMatcher> HasErrorMessage(const std::string& message) {
+    return MakePolymorphicMatcher(ErrorMessageMatcher(message));
+}
+
 // Common test set up for checking matrices against lib*idlmetadata.
 class CheckMatricesWithHalDefTestBase : public MultiMatrixTest {
     void SetUp() override {
@@ -1928,15 +1934,15 @@
 class CheckMissingHalsTest : public CheckMatricesWithHalDefTestBase {};
 
 TEST_F(CheckMissingHalsTest, Empty) {
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices({}, {}), Ok());
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices({}, {}));
 }
 
 TEST_F(CheckMissingHalsTest, Pass) {
     std::vector<HidlInterfaceMetadata> hidl{{.name = "android.hardware.hidl@1.0::IHidl"}};
     std::vector<AidlInterfaceMetadata> aidl{{.types = {"android.hardware.aidl.IAidl"}}};
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices(hidl, {}), Ok());
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices({}, aidl), Ok());
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices(hidl, aidl), Ok());
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, {}));
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices({}, aidl));
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, aidl));
 }
 
 TEST_F(CheckMissingHalsTest, FailVendor) {
@@ -1944,21 +1950,21 @@
     std::vector<AidlInterfaceMetadata> aidl{{.types = {"vendor.foo.aidl.IAidl"}}};
 
     auto res = vintfObject->checkMissingHalsInMatrices(hidl, {});
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("vendor.foo.hidl@1.0"))));
+    EXPECT_THAT(res, HasErrorMessage("vendor.foo.hidl@1.0"));
 
     res = vintfObject->checkMissingHalsInMatrices({}, aidl);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("vendor.foo.aidl"))));
+    EXPECT_THAT(res, HasErrorMessage("vendor.foo.aidl"));
 
     res = vintfObject->checkMissingHalsInMatrices(hidl, aidl);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("vendor.foo.hidl@1.0"))));
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("vendor.foo.aidl"))));
+    EXPECT_THAT(res, HasErrorMessage("vendor.foo.hidl@1.0"));
+    EXPECT_THAT(res, HasErrorMessage("vendor.foo.aidl"));
 
     auto predicate = [](const auto& interfaceName) {
         return android::base::StartsWith(interfaceName, "android.hardware");
     };
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices(hidl, {}, predicate), Ok());
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices({}, aidl, predicate), Ok());
-    EXPECT_THAT(vintfObject->checkMissingHalsInMatrices(hidl, aidl, predicate), Ok());
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, {}, predicate));
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices({}, aidl, predicate));
+    EXPECT_RESULT_OK(vintfObject->checkMissingHalsInMatrices(hidl, aidl, predicate));
 }
 
 TEST_F(CheckMissingHalsTest, FailVersion) {
@@ -1966,28 +1972,28 @@
     std::vector<AidlInterfaceMetadata> aidl{{.types = {"android.hardware.aidl2.IAidl"}}};
 
     auto res = vintfObject->checkMissingHalsInMatrices(hidl, {});
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.hidl@2.0"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0"));
 
     res = vintfObject->checkMissingHalsInMatrices({}, aidl);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.aidl2"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2"));
 
     res = vintfObject->checkMissingHalsInMatrices(hidl, aidl);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.hidl@2.0"))));
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.aidl2"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0"));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2"));
 
     auto predicate = [](const auto& interfaceName) {
         return android::base::StartsWith(interfaceName, "android.hardware");
     };
 
     res = vintfObject->checkMissingHalsInMatrices(hidl, {}, predicate);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.hidl@2.0"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0"));
 
     res = vintfObject->checkMissingHalsInMatrices({}, aidl, predicate);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.aidl2"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2"));
 
     res = vintfObject->checkMissingHalsInMatrices(hidl, aidl, predicate);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.hidl@2.0"))));
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.aidl2"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@2.0"));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl2"));
 }
 
 // A set of tests on VintfObject::checkMatrixHalsHasDefinition
@@ -1996,340 +2002,27 @@
 TEST_F(CheckMatrixHalsHasDefinitionTest, Pass) {
     std::vector<HidlInterfaceMetadata> hidl{{.name = "android.hardware.hidl@1.0::IHidl"}};
     std::vector<AidlInterfaceMetadata> aidl{{.types = {"android.hardware.aidl.IAidl"}}};
-    EXPECT_THAT(vintfObject->checkMatrixHalsHasDefinition(hidl, aidl), Ok());
+    EXPECT_RESULT_OK(vintfObject->checkMatrixHalsHasDefinition(hidl, aidl));
 }
 
 TEST_F(CheckMatrixHalsHasDefinitionTest, FailMissingHidl) {
     std::vector<AidlInterfaceMetadata> aidl{{.types = {"android.hardware.aidl.IAidl"}}};
     auto res = vintfObject->checkMatrixHalsHasDefinition({}, aidl);
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.hidl@1.0::IHidl"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@1.0::IHidl"));
 }
 
 TEST_F(CheckMatrixHalsHasDefinitionTest, FailMissingAidl) {
     std::vector<HidlInterfaceMetadata> hidl{{.name = "android.hardware.hidl@1.0::IHidl"}};
     auto res = vintfObject->checkMatrixHalsHasDefinition(hidl, {});
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.aidl.IAidl"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl.IAidl"));
 }
 
 TEST_F(CheckMatrixHalsHasDefinitionTest, FailMissingBoth) {
     auto res = vintfObject->checkMatrixHalsHasDefinition({}, {});
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.hidl@1.0::IHidl"))));
-    EXPECT_THAT(res, HasError(WithMessage(HasSubstr("android.hardware.aidl.IAidl"))));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.hidl@1.0::IHidl"));
+    EXPECT_THAT(res, HasErrorMessage("android.hardware.aidl.IAidl"));
 }
 
-constexpr const char* systemMatrixHealthFormat = R"(
-<compatibility-matrix %s type="framework" level="%s">
-    <hal format="%s" optional="%s">
-        <name>android.hardware.health</name>
-        <version>%s</version>
-        <interface>
-            <name>IHealth</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</compatibility-matrix>
-)";
-
-constexpr const char* vendorManifestHealthHidlFormat = R"(
-<manifest %s type="device" target-level="%s">
-    <hal format="hidl">
-        <name>android.hardware.health</name>
-        <transport>hwbinder</transport>
-        <fqname>@%s::IHealth/default</fqname>
-    </hal>
-</manifest>
-)";
-
-constexpr const char* vendorManifestHealthAidlFormat = R"(
-<manifest %s type="device" target-level="%s">
-    <hal format="aidl">
-        <name>android.hardware.health</name>
-        <version>%s</version>
-        <fqname>IHealth/default</fqname>
-    </hal>
-</manifest>
-)";
-
-using HealthHalVersion = std::variant<Version /* HIDL */, size_t /* AIDL */>;
-struct VintfObjectHealthHalTestParam {
-    Level targetLevel;
-    HealthHalVersion halVersion;
-    bool expected;
-
-    HalFormat getHalFormat() const {
-        if (std::holds_alternative<Version>(halVersion)) return HalFormat::HIDL;
-        if (std::holds_alternative<size_t>(halVersion)) return HalFormat::AIDL;
-        __builtin_unreachable();
-    }
-};
-std::ostream& operator<<(std::ostream& os, const VintfObjectHealthHalTestParam& param) {
-    os << param.targetLevel << "_" << param.getHalFormat() << "_";
-    switch (param.getHalFormat()) {
-        case HalFormat::HIDL: {
-            const auto& v = std::get<Version>(param.halVersion);
-            os << "v" << v.majorVer << "_" << v.minorVer;
-        } break;
-        case HalFormat::AIDL: {
-            os << "v" << std::get<size_t>(param.halVersion);
-        } break;
-        default:
-            __builtin_unreachable();
-    }
-    return os << "_" << (param.expected ? "ok" : "not_ok");
-}
-
-// Test fixture that provides compatible metadata from the mock device.
-class VintfObjectHealthHalTest : public MultiMatrixTest,
-                                 public WithParamInterface<VintfObjectHealthHalTestParam> {
-   public:
-    virtual void SetUp() {
-        MultiMatrixTest::SetUp();
-        SetUpMockSystemMatrices({
-            android::base::StringPrintf(
-                systemMatrixHealthFormat, kMetaVersionStr.c_str(), to_string(Level::P).c_str(),
-                to_string(HalFormat::HIDL).c_str(), "true", to_string(Version{2, 0}).c_str()),
-            android::base::StringPrintf(
-                systemMatrixHealthFormat, kMetaVersionStr.c_str(), to_string(Level::Q).c_str(),
-                to_string(HalFormat::HIDL).c_str(), "true", to_string(Version{2, 0}).c_str()),
-            android::base::StringPrintf(
-                systemMatrixHealthFormat, kMetaVersionStr.c_str(), to_string(Level::R).c_str(),
-                to_string(HalFormat::HIDL).c_str(), "true", to_string(Version{2, 1}).c_str()),
-            android::base::StringPrintf(
-                systemMatrixHealthFormat, kMetaVersionStr.c_str(), to_string(Level::S).c_str(),
-                to_string(HalFormat::HIDL).c_str(), "true", to_string(Version{2, 1}).c_str()),
-            android::base::StringPrintf(
-                systemMatrixHealthFormat, kMetaVersionStr.c_str(), to_string(Level::T).c_str(),
-                to_string(HalFormat::AIDL).c_str(), "false", to_string(1).c_str()),
-        });
-        switch (GetParam().getHalFormat()) {
-            case HalFormat::HIDL:
-                expectFetchRepeatedly(
-                    kVendorManifest,
-                    android::base::StringPrintf(
-                        vendorManifestHealthHidlFormat, kMetaVersionStr.c_str(),
-                        to_string(GetParam().targetLevel).c_str(),
-                        to_string(std::get<Version>(GetParam().halVersion)).c_str()));
-                break;
-            case HalFormat::AIDL:
-                expectFetchRepeatedly(
-                    kVendorManifest,
-                    android::base::StringPrintf(
-                        vendorManifestHealthAidlFormat, kMetaVersionStr.c_str(),
-                        to_string(GetParam().targetLevel).c_str(),
-                        to_string(std::get<size_t>(GetParam().halVersion)).c_str()));
-                break;
-            default:
-                __builtin_unreachable();
-        }
-    }
-    static std::vector<VintfObjectHealthHalTestParam> GetParams() {
-        std::vector<VintfObjectHealthHalTestParam> ret;
-        for (auto level : {Level::P, Level::Q, Level::R, Level::S, Level::T}) {
-            ret.push_back({level, Version{2, 0}, level < Level::R});
-            ret.push_back({level, Version{2, 1}, level < Level::T});
-            ret.push_back({level, 1, true});
-        }
-        return ret;
-    }
-};
-
-TEST_P(VintfObjectHealthHalTest, Test) {
-    auto manifest = vintfObject->getDeviceHalManifest();
-    ASSERT_NE(nullptr, manifest);
-    std::string deprecatedError;
-    auto deprecation = vintfObject->checkDeprecation({}, &deprecatedError);
-    bool hasHidl =
-        manifest->hasHidlInstance("android.hardware.health", {2, 0}, "IHealth", "default");
-    bool hasAidl = manifest->hasAidlInstance("android.hardware.health", 1, "IHealth", "default");
-    bool hasHal = hasHidl || hasAidl;
-    EXPECT_EQ(GetParam().expected, deprecation == NO_DEPRECATED_HALS && hasHal)
-        << "checkDeprecation() returns " << deprecation << "; hasHidl = " << hasHidl
-        << ", hasAidl = " << hasAidl;
-}
-
-INSTANTIATE_TEST_SUITE_P(VintfObjectHealthHalTest, VintfObjectHealthHalTest,
-                         ::testing::ValuesIn(VintfObjectHealthHalTest::GetParams()),
-                         [](const auto& info) { return to_string(info.param); });
-
-constexpr const char* systemMatrixComposerFormat = R"(
-<compatibility-matrix %s type="framework" level="%s">
-    %s
-</compatibility-matrix>
-)";
-
-constexpr const char* systemMatrixComposerHalFragmentFormat = R"(
-    <hal format="%s" optional="%s">
-        <name>%s</name>
-        <version>%s</version>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-)";
-
-constexpr const char* vendorManifestComposerHidlFormat = R"(
-<manifest %s type="device" target-level="%s">
-    %s
-</manifest>
-)";
-
-constexpr const char* vendorManifestComposerHidlFragmentFormat = R"(
-    <hal format="hidl">
-        <name>android.hardware.graphics.composer</name>
-        <version>%s</version>
-        <transport>hwbinder</transport>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-)";
-
-constexpr const char* vendorManifestComposerAidlFragmentFormat = R"(
-    <hal format="aidl">
-        <name>android.hardware.graphics.composer3</name>
-        <version>%s</version>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-)";
-
-constexpr const char* composerHidlHalName = "android.hardware.graphics.composer";
-constexpr const char* composerAidlHalName = "android.hardware.graphics.composer3";
-
-using ComposerHalVersion = std::variant<Version /* HIDL */, size_t /* AIDL */>;
-struct VintfObjectComposerHalTestParam {
-    Level targetLevel;
-    std::optional<ComposerHalVersion> halVersion;
-    bool expected;
-
-    bool hasHal() const { return halVersion.has_value(); }
-
-    HalFormat getHalFormat() const {
-        if (std::holds_alternative<Version>(*halVersion)) return HalFormat::HIDL;
-        if (std::holds_alternative<size_t>(*halVersion)) return HalFormat::AIDL;
-        __builtin_unreachable();
-    }
-};
-std::ostream& operator<<(std::ostream& os, const VintfObjectComposerHalTestParam& param) {
-    os << param.targetLevel << "_";
-    if (param.hasHal()) {
-        os << param.getHalFormat() << "_";
-        switch (param.getHalFormat()) {
-            case HalFormat::HIDL: {
-                const auto& v = std::get<Version>(*param.halVersion);
-                os << "v" << v.majorVer << "_" << v.minorVer;
-            } break;
-            case HalFormat::AIDL: {
-                os << "v" << std::get<size_t>(*param.halVersion);
-            } break;
-            default:
-                __builtin_unreachable();
-        }
-    } else {
-        os << "no_hal";
-    }
-    return os << "_" << (param.expected ? "ok" : "not_ok");
-}
-
-// Test fixture that provides compatible metadata from the mock device.
-class VintfObjectComposerHalTest : public MultiMatrixTest,
-                                   public WithParamInterface<VintfObjectComposerHalTestParam> {
-   public:
-    virtual void SetUp() {
-        MultiMatrixTest::SetUp();
-
-        const std::string requiresHidl2_1To2_2 = android::base::StringPrintf(
-            systemMatrixComposerHalFragmentFormat, to_string(HalFormat::HIDL).c_str(), "false",
-            composerHidlHalName, to_string(VersionRange{2, 1, 2}).c_str());
-        const std::string requiresHidl2_1To2_3 = android::base::StringPrintf(
-            systemMatrixComposerHalFragmentFormat, to_string(HalFormat::HIDL).c_str(), "false",
-            composerHidlHalName, to_string(VersionRange{2, 1, 3}).c_str());
-        const std::string requiresHidl2_1To2_4 = android::base::StringPrintf(
-            systemMatrixComposerHalFragmentFormat, to_string(HalFormat::HIDL).c_str(), "false",
-            composerHidlHalName, to_string(VersionRange{2, 1, 4}).c_str());
-        const std::string optionalHidl2_1To2_4 = android::base::StringPrintf(
-            systemMatrixComposerHalFragmentFormat, to_string(HalFormat::HIDL).c_str(), "true",
-            composerHidlHalName, to_string(VersionRange{2, 1, 4}).c_str());
-        const std::string optionalAidl1 = android::base::StringPrintf(
-            systemMatrixComposerHalFragmentFormat, to_string(HalFormat::AIDL).c_str(), "true",
-            composerAidlHalName, "1");
-        const std::string optionalHidl2_1To2_4OrAidl1 = optionalHidl2_1To2_4 + optionalAidl1;
-
-        SetUpMockSystemMatrices({
-            android::base::StringPrintf(systemMatrixComposerFormat, kMetaVersionStr.c_str(),
-                                        to_string(Level::P).c_str(), requiresHidl2_1To2_2.c_str()),
-            android::base::StringPrintf(systemMatrixComposerFormat, kMetaVersionStr.c_str(),
-                                        to_string(Level::Q).c_str(), requiresHidl2_1To2_3.c_str()),
-            android::base::StringPrintf(systemMatrixComposerFormat, kMetaVersionStr.c_str(),
-                                        to_string(Level::R).c_str(), requiresHidl2_1To2_4.c_str()),
-            android::base::StringPrintf(systemMatrixComposerFormat, kMetaVersionStr.c_str(),
-                                        to_string(Level::S).c_str(), requiresHidl2_1To2_4.c_str()),
-            android::base::StringPrintf(systemMatrixComposerFormat, kMetaVersionStr.c_str(),
-                                        to_string(Level::T).c_str(),
-                                        optionalHidl2_1To2_4OrAidl1.c_str()),
-        });
-
-        const auto param = GetParam();
-
-        std::string vendorHalFragment;
-        if (param.hasHal()) {
-            switch (param.getHalFormat()) {
-                case HalFormat::HIDL:
-                    vendorHalFragment = android::base::StringPrintf(
-                        vendorManifestComposerHidlFragmentFormat,
-                        to_string(std::get<Version>(*param.halVersion)).c_str());
-                    break;
-                case HalFormat::AIDL:
-                    vendorHalFragment = android::base::StringPrintf(
-                        vendorManifestComposerAidlFragmentFormat,
-                        to_string(std::get<size_t>(*param.halVersion)).c_str());
-                    break;
-                default:
-                    __builtin_unreachable();
-            }
-        } else {
-            vendorHalFragment = "";
-        }
-        expectFetchRepeatedly(kVendorManifest,
-                              android::base::StringPrintf(
-                                  vendorManifestComposerHidlFormat, kMetaVersionStr.c_str(),
-                                  to_string(param.targetLevel).c_str(), vendorHalFragment.c_str()));
-    }
-    static std::vector<VintfObjectComposerHalTestParam> GetParams() {
-        std::vector<VintfObjectComposerHalTestParam> ret;
-        for (auto level : {Level::P, Level::Q, Level::R, Level::S, Level::T}) {
-            ret.push_back({level, std::nullopt, false});
-            ret.push_back({level, ComposerHalVersion{Version{2, 1}}, true});
-            ret.push_back({level, ComposerHalVersion{Version{2, 2}}, true});
-            ret.push_back({level, ComposerHalVersion{Version{2, 3}}, true});
-            ret.push_back({level, ComposerHalVersion{Version{2, 4}}, true});
-            ret.push_back({level, ComposerHalVersion{1}, true});
-        }
-        return ret;
-    }
-};
-
-TEST_P(VintfObjectComposerHalTest, Test) {
-    auto manifest = vintfObject->getDeviceHalManifest();
-    ASSERT_NE(nullptr, manifest);
-    std::string deprecatedError;
-    auto deprecation = vintfObject->checkDeprecation({}, &deprecatedError);
-    bool hasHidl = manifest->hasHidlInstance(composerHidlHalName, {2, 1}, "IComposer", "default");
-    bool hasAidl = manifest->hasAidlInstance(composerAidlHalName, 1, "IComposer", "default");
-    bool hasHal = hasHidl || hasAidl;
-    EXPECT_EQ(GetParam().expected, deprecation == NO_DEPRECATED_HALS && hasHal)
-        << "checkDeprecation() returns " << deprecation << "; hasHidl = " << hasHidl
-        << ", hasAidl = " << hasAidl;
-}
-
-INSTANTIATE_TEST_SUITE_P(VintfObjectComposerHalTest, VintfObjectComposerHalTest,
-                         ::testing::ValuesIn(VintfObjectComposerHalTest::GetParams()),
-                         [](const auto& info) { return to_string(info.param); });
-
 }  // namespace testing
 }  // namespace vintf
 }  // namespace android
diff --git a/xsd/halManifest/api/current.txt b/xsd/halManifest/api/current.txt
index 2e4db0e..9599c20 100644
--- a/xsd/halManifest/api/current.txt
+++ b/xsd/halManifest/api/current.txt
@@ -21,12 +21,8 @@
   public static class Hal.Transport {
     ctor public Hal.Transport();
     method public String getArch();
-    method public String getIp();
-    method public String getPort();
     method public String getValue();
     method public void setArch(String);
-    method public void setIp(String);
-    method public void setPort(String);
     method public void setValue(String);
   }
 
diff --git a/xsd/halManifest/hal_manifest.xsd b/xsd/halManifest/hal_manifest.xsd
index cf3a53f..acc3ad8 100644
--- a/xsd/halManifest/hal_manifest.xsd
+++ b/xsd/halManifest/hal_manifest.xsd
@@ -41,8 +41,6 @@
                     <xs:simpleContent>
                         <xs:extension base="xs:string">
                             <xs:attribute name="arch" type="xs:string"/>
-                            <xs:attribute name="ip" type="xs:string" />
-                            <xs:attribute name="port" type="xs:string" />
                         </xs:extension>
                     </xs:simpleContent>
                 </xs:complexType>