Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52dcea71 authored by Yifan Hong's avatar Yifan Hong Committed by android-build-merger
Browse files

Merge "lshal: --init-vintf use <fqname> only."

am: a60de57f

Change-Id: Ibde0be3edcc8cafffe14aa316552e46f86a52c75
parents fd02e5c5 a60de57f
Loading
Loading
Loading
Loading
+117 −118
Original line number Diff line number Diff line
@@ -19,11 +19,12 @@
#include <getopt.h>

#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <sstream>
#include <regex>
#include <sstream>

#include <android-base/file.h>
#include <android-base/parseint.h>
@@ -101,21 +102,19 @@ Partition ListCommand::getPartition(pid_t pid) {

// Give sensible defaults when nothing can be inferred from runtime.
// process: Partition inferred from executable location or cmdline.
Partition ListCommand::resolvePartition(Partition process, const FQName& fqName) const {
    if (fqName.inPackage("vendor") ||
        fqName.inPackage("com")) {
Partition ListCommand::resolvePartition(Partition process, const FqInstance& fqInstance) const {
    if (fqInstance.inPackage("vendor") || fqInstance.inPackage("com")) {
        return Partition::VENDOR;
    }

    if (fqName.inPackage("android.frameworks") ||
        fqName.inPackage("android.system") ||
        fqName.inPackage("android.hidl")) {
    if (fqInstance.inPackage("android.frameworks") || fqInstance.inPackage("android.system") ||
        fqInstance.inPackage("android.hidl")) {
        return Partition::SYSTEM;
    }

    // Some android.hardware HALs are served from system. Check the value from executable
    // location / cmdline first.
    if (fqName.inPackage("android.hardware")) {
    if (fqInstance.inPackage("android.hardware")) {
        if (process != Partition::UNKNOWN) {
            return process;
        }
@@ -284,62 +283,30 @@ void ListCommand::postprocess() {
            "These may return subclasses through their respective HIDL_FETCH_I* functions.");
}

static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
    for (vintf::Version& v : hal->versions) {
        if (v.majorVer == version.majorVer) {
            v.minorVer = std::max(v.minorVer, version.minorVer);
            return true;
        }
    }
bool ListCommand::addEntryWithInstance(const TableEntry& entry,
                                       vintf::HalManifest* manifest) const {
    FqInstance fqInstance;
    if (!fqInstance.setTo(entry.interfaceName)) {
        err() << "Warning: '" << entry.interfaceName << "' is not a valid FqInstance." << std::endl;
        return false;
    }

void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
    using vintf::operator|=;
    using vintf::operator<<;

    vintf::HalManifest manifest;
    manifest.setType(toSchemaType(mVintfPartition));
    forEachTable([this, &manifest] (const Table &table) {
        for (const TableEntry &entry : table) {

            std::string fqInstanceName = entry.interfaceName;

            if (&table == &mImplementationsTable) {
                // Quick hack to work around *'s
                replaceAll(&fqInstanceName, '*', 'D');
            }
            auto splitFqInstanceName = splitFirst(fqInstanceName, '/');
            FQName fqName;
            if (!FQName::parse(splitFqInstanceName.first, &fqName)) {
                err() << "Warning: '" << splitFqInstanceName.first
                     << "' is not a valid FQName." << std::endl;
                continue;
            }

            if (fqName.package() == gIBaseFqName.package()) {
                continue; // always remove IBase from manifest
    if (fqInstance.getPackage() == gIBaseFqName.package()) {
        return true; // always remove IBase from manifest
    }

            Partition partition = resolvePartition(entry.partition, fqName);
    Partition partition = resolvePartition(entry.partition, fqInstance);

    if (partition == Partition::UNKNOWN) {
                err() << "Warning: Cannot guess the partition of instance " << fqInstanceName
                      << ". It is removed from the generated manifest." << std::endl;
                continue;
        err() << "Warning: Cannot guess the partition of FqInstance " << fqInstance.string()
              << std::endl;
        return false;
    }

    if (partition != mVintfPartition) {
                continue; // strip out instances that is in a different partition.
        return true; // strip out instances that is in a different partition.
    }

            std::string interfaceName =
                    &table == &mImplementationsTable ? "" : fqName.name();
            std::string instanceName =
                    &table == &mImplementationsTable ? "" : splitFqInstanceName.second;

            vintf::Version version{fqName.getPackageMajorVersion(),
                                   fqName.getPackageMinorVersion()};
    vintf::Transport transport;
    vintf::Arch arch;
    if (entry.transport == "hwbinder") {
@@ -349,64 +316,88 @@ void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
        transport = vintf::Transport::PASSTHROUGH;
        switch (entry.arch) {
            case lshal::ARCH32:
                        arch = vintf::Arch::ARCH_32;    break;
                arch = vintf::Arch::ARCH_32;
                break;
            case lshal::ARCH64:
                        arch = vintf::Arch::ARCH_64;    break;
                arch = vintf::Arch::ARCH_64;
                break;
            case lshal::ARCH_BOTH:
                        arch = vintf::Arch::ARCH_32_64; break;
                arch = vintf::Arch::ARCH_32_64;
                break;
            case lshal::ARCH_UNKNOWN: // fallthrough
            default:
                        err() << "Warning: '" << fqName.package()
                             << "' doesn't have bitness info, assuming 32+64." << std::endl;
                        arch = vintf::Arch::ARCH_32_64;
                err() << "Warning: '" << entry.interfaceName << "' doesn't have bitness info.";
                return false;
        }
    } else {
        err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
                continue;
        return false;
    }

            bool done = false;
            for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
                if (hal->transport() != transport) {
                    if (transport != vintf::Transport::PASSTHROUGH) {
                        err() << "Fatal: should not reach here. Generated result may be wrong for '"
                             << hal->name << "'."
                             << std::endl;
                    }
                    done = true;
                    break;
    std::string e;
    if (!manifest->insertInstance(fqInstance, transport, arch, vintf::HalFormat::HIDL, &e)) {
        err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl;
        return false;
    }
                if (findAndBumpVersion(hal, version)) {
                    if (&table != &mImplementationsTable) {
                        hal->insertLegacyInstance(interfaceName, instanceName);
    return true;
}
                    hal->transportArch.arch |= arch;
                    done = true;
                    break;

bool ListCommand::addEntryWithoutInstance(const TableEntry& entry,
                                          const vintf::HalManifest* manifest) const {
    const auto& packageAndVersion = splitFirst(splitFirst(entry.interfaceName, ':').first, '@');
    const auto& package = packageAndVersion.first;
    vintf::Version version;
    if (!vintf::parse(packageAndVersion.second, &version)) {
        err() << "Warning: Cannot parse version '" << packageAndVersion.second << "' for entry '"
              << entry.interfaceName << "'" << std::endl;
        return false;
    }

    bool found = false;
    (void)manifest->forEachInstanceOfVersion(package, version, [&found](const auto&) {
        found = true;
        return false; // break
    });
    return found;
}
            if (done) {
                continue; // to next TableEntry

void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
    using vintf::operator|=;
    using vintf::operator<<;
    using namespace std::placeholders;

    vintf::HalManifest manifest;
    manifest.setType(toSchemaType(mVintfPartition));

    std::vector<std::string> error;
    for (const TableEntry& entry : mServicesTable)
        if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
    for (const TableEntry& entry : mPassthroughRefTable)
        if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);

    std::vector<std::string> passthrough;
    for (const TableEntry& entry : mImplementationsTable)
        if (!addEntryWithoutInstance(entry, &manifest)) passthrough.push_back(entry.interfaceName);

    out << "<!-- " << std::endl
        << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
        << INIT_VINTF_NOTES;
    if (!error.empty()) {
        out << std::endl << "    The following HALs are not added; see warnings." << std::endl;
        for (const auto& e : error) {
            out << "        " << e << std::endl;
        }
            vintf::ManifestHal manifestHal{
                    vintf::HalFormat::HIDL,
                    std::string{fqName.package()},
                    {version},
                    {transport, arch},
                    {}};
            if (&table != &mImplementationsTable) {
                manifestHal.insertLegacyInstance(interfaceName, instanceName);
    }
            if (!manifest.add(std::move(manifestHal))) {
                err() << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
    if (!passthrough.empty()) {
        out << std::endl
            << "    The following HALs are passthrough and no interface or instance " << std::endl
            << "    names can be inferred." << std::endl;
        for (const auto& e : passthrough) {
            out << "        " << e << std::endl;
        }
    }
    });
    out << "<!-- " << std::endl
         << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
         << INIT_VINTF_NOTES
         << "-->" << std::endl;
    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_NO_FQNAME);
    out << "-->" << std::endl;
    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_ONLY);
}

std::string ListCommand::INIT_VINTF_NOTES{
@@ -416,6 +407,14 @@ std::string ListCommand::INIT_VINTF_NOTES{
    "       <interface> declared; users will have to write them by hand.\n"
    "    3. A HAL with lower minor version can be overridden by a HAL with\n"
    "       higher minor version if they have the same name and major version.\n"
    "    4. This output is intended for launch devices.\n"
    "       Upgrading devices should not use this tool to generate device\n"
    "       manifest and replace the existing manifest directly, but should\n"
    "       edit the existing manifest manually.\n"
    "       Specifically, devices which launched at Android O-MR1 or earlier\n"
    "       should not use the 'fqname' format for required HAL entries and\n"
    "       should instead use the legacy package, name, instance-name format\n"
    "       until they are updated.\n"
};

static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+7 −2
Original line number Diff line number Diff line
@@ -26,7 +26,8 @@

#include <android-base/macros.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-util/FQName.h>
#include <hidl-util/FqInstance.h>
#include <vintf/HalManifest.h>

#include "Command.h"
#include "NullableOStream.h"
@@ -113,7 +114,7 @@ protected:
    void removeDeadProcesses(Pids *pids);

    virtual Partition getPartition(pid_t pid);
    Partition resolvePartition(Partition processPartition, const FQName& fqName) const;
    Partition resolvePartition(Partition processPartition, const FqInstance &fqInstance) const;

    void forEachTable(const std::function<void(Table &)> &f);
    void forEachTable(const std::function<void(const Table &)> &f) const;
@@ -123,6 +124,10 @@ protected:

    void registerAllOptions();

    // helper functions to dumpVintf.
    bool addEntryWithInstance(const TableEntry &entry, vintf::HalManifest *manifest) const;
    bool addEntryWithoutInstance(const TableEntry &entry, const vintf::HalManifest *manifest) const;

    Table mServicesTable{};
    Table mPassthroughRefTable{};
    Table mImplementationsTable{};
+26 −53
Original line number Diff line number Diff line
@@ -418,62 +418,35 @@ TEST_F(ListTest, Fetch) {
}

TEST_F(ListTest, DumpVintf) {
    const std::string expected =
        "<!-- \n"
        "    This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
        "-->\n"
        "<manifest version=\"1.0\" type=\"device\">\n"
    const std::string expected = "<manifest version=\"1.0\" type=\"device\">\n"
                                 "    <hal format=\"hidl\">\n"
                                 "        <name>a.h.foo1</name>\n"
                                 "        <transport>hwbinder</transport>\n"
        "        <version>1.0</version>\n"
        "        <interface>\n"
        "            <name>IFoo</name>\n"
        "            <instance>1</instance>\n"
        "        </interface>\n"
                                 "        <fqname>@1.0::IFoo/1</fqname>\n"
                                 "    </hal>\n"
                                 "    <hal format=\"hidl\">\n"
                                 "        <name>a.h.foo2</name>\n"
                                 "        <transport>hwbinder</transport>\n"
        "        <version>2.0</version>\n"
        "        <interface>\n"
        "            <name>IFoo</name>\n"
        "            <instance>2</instance>\n"
        "        </interface>\n"
                                 "        <fqname>@2.0::IFoo/2</fqname>\n"
                                 "    </hal>\n"
                                 "    <hal format=\"hidl\">\n"
                                 "        <name>a.h.foo3</name>\n"
                                 "        <transport arch=\"32\">passthrough</transport>\n"
        "        <version>3.0</version>\n"
        "        <interface>\n"
        "            <name>IFoo</name>\n"
        "            <instance>3</instance>\n"
        "        </interface>\n"
                                 "        <fqname>@3.0::IFoo/3</fqname>\n"
                                 "    </hal>\n"
                                 "    <hal format=\"hidl\">\n"
                                 "        <name>a.h.foo4</name>\n"
                                 "        <transport arch=\"32\">passthrough</transport>\n"
        "        <version>4.0</version>\n"
        "        <interface>\n"
        "            <name>IFoo</name>\n"
        "            <instance>4</instance>\n"
        "        </interface>\n"
        "    </hal>\n"
        "    <hal format=\"hidl\">\n"
        "        <name>a.h.foo5</name>\n"
        "        <transport arch=\"32\">passthrough</transport>\n"
        "        <version>5.0</version>\n"
                                 "        <fqname>@4.0::IFoo/4</fqname>\n"
                                 "    </hal>\n"
        "    <hal format=\"hidl\">\n"
        "        <name>a.h.foo6</name>\n"
        "        <transport arch=\"32\">passthrough</transport>\n"
        "        <version>6.0</version>\n"
        "    </hal>\n"
        "</manifest>\n";
                                 "</manifest>";

    optind = 1; // mimic Lshal::parseArg()
    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
    EXPECT_EQ(expected, out.str());
    auto output = out.str();
    EXPECT_THAT(output, HasSubstr(expected));
    EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
    EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
    EXPECT_EQ("", err.str());

    vintf::HalManifest m;