diff options
| author | 2018-05-01 15:25:23 -0700 | |
|---|---|---|
| committer | 2018-05-02 16:03:59 -0700 | |
| commit | b2d096a2a528ffae20bd8ed6db541b49005cfaa9 (patch) | |
| tree | c3dda1ff53d86aec36c6e9d928febe8073ce89b6 /cmds | |
| parent | 93a0198e5f7a90150549f74fd2080c730f01b138 (diff) | |
lshal: --init-vintf use <fqname> only.
lshal --init-vintf helps creating the device manifest for
launch devices. For launch devices it is encouraged to use
<fqname> format.
Upgrading devices should not use this tool to generate device
manifest and replace the existing manifest directly, but should
edit the existing manifest manually.
Bug: 74247301
Test: lshal_test
Change-Id: Ifaf230a13637be9c8799291f28f48808b05fff18
Diffstat (limited to 'cmds')
| -rw-r--r-- | cmds/lshal/ListCommand.cpp | 235 | ||||
| -rw-r--r-- | cmds/lshal/ListCommand.h | 9 | ||||
| -rw-r--r-- | cmds/lshal/test.cpp | 79 |
3 files changed, 150 insertions, 173 deletions
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index 29ef648bb3..4249165df7 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -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,138 +283,138 @@ 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; + } + + if (fqInstance.getPackage() == gIBaseFqName.package()) { + return true; // always remove IBase from manifest + } + + Partition partition = resolvePartition(entry.partition, fqInstance); + + if (partition == Partition::UNKNOWN) { + err() << "Warning: Cannot guess the partition of FqInstance " << fqInstance.string() + << std::endl; + return false; + } + + if (partition != mVintfPartition) { + return true; // strip out instances that is in a different partition. + } + + vintf::Transport transport; + vintf::Arch arch; + if (entry.transport == "hwbinder") { + transport = vintf::Transport::HWBINDER; + arch = vintf::Arch::ARCH_EMPTY; + } else if (entry.transport == "passthrough") { + transport = vintf::Transport::PASSTHROUGH; + switch (entry.arch) { + case lshal::ARCH32: + arch = vintf::Arch::ARCH_32; + break; + case lshal::ARCH64: + arch = vintf::Arch::ARCH_64; + break; + case lshal::ARCH_BOTH: + arch = vintf::Arch::ARCH_32_64; + break; + case lshal::ARCH_UNKNOWN: // fallthrough + default: + err() << "Warning: '" << entry.interfaceName << "' doesn't have bitness info."; + return false; } + } else { + err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl; + return false; + } + + std::string e; + if (!manifest->insertInstance(fqInstance, transport, arch, vintf::HalFormat::HIDL, &e)) { + err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl; + return false; } - return false; + return true; +} + +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; } 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)); - forEachTable([this, &manifest] (const Table &table) { - for (const TableEntry &entry : table) { - std::string fqInstanceName = entry.interfaceName; + 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); - 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 - } - - Partition partition = resolvePartition(entry.partition, fqName); + std::vector<std::string> passthrough; + for (const TableEntry& entry : mImplementationsTable) + if (!addEntryWithoutInstance(entry, &manifest)) passthrough.push_back(entry.interfaceName); - if (partition == Partition::UNKNOWN) { - err() << "Warning: Cannot guess the partition of instance " << fqInstanceName - << ". It is removed from the generated manifest." << std::endl; - continue; - } - - if (partition != mVintfPartition) { - continue; // 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") { - transport = vintf::Transport::HWBINDER; - arch = vintf::Arch::ARCH_EMPTY; - } else if (entry.transport == "passthrough") { - transport = vintf::Transport::PASSTHROUGH; - switch (entry.arch) { - case lshal::ARCH32: - arch = vintf::Arch::ARCH_32; break; - case lshal::ARCH64: - arch = vintf::Arch::ARCH_64; break; - case lshal::ARCH_BOTH: - 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; - } - } else { - err() << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl; - continue; - } - - 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; - } - if (findAndBumpVersion(hal, version)) { - if (&table != &mImplementationsTable) { - hal->insertLegacyInstance(interfaceName, instanceName); - } - hal->transportArch.arch |= arch; - done = true; - break; - } - } - if (done) { - continue; // to next TableEntry - } - 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; - } - } - }); 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); + << " 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; + } + } + 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; + out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_ONLY); } std::string ListCommand::INIT_VINTF_NOTES{ - " 1. If a HAL is supported in both hwbinder and passthrough transport, \n" + " 1. If a HAL is supported in both hwbinder and passthrough transport,\n" " only hwbinder is shown.\n" " 2. It is likely that HALs in passthrough transport does not have\n" " <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) { diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h index 1e85ea0bef..88faac149d 100644 --- a/cmds/lshal/ListCommand.h +++ b/cmds/lshal/ListCommand.h @@ -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{}; diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp index 4fa941e95d..f23095e1b0 100644 --- a/cmds/lshal/test.cpp +++ b/cmds/lshal/test.cpp @@ -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" - " <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" - " </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" - " </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" - " </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" - " </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"; + 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" + " <fqname>@1.0::IFoo/1</fqname>\n" + " </hal>\n" + " <hal format=\"hidl\">\n" + " <name>a.h.foo2</name>\n" + " <transport>hwbinder</transport>\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" + " <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" + " <fqname>@4.0::IFoo/4</fqname>\n" + " </hal>\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; |