Merge changes from topic "lshal_improve"
* changes:
lshal: arch unknown => ?
lshal: Add VINTF column
lshal: refactor: Use vintf::Arch instead of enum Architecture
lshal: refactor: Use vintf::Transport instead of string
lshal: Released column is now Y/N/?
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index c99b863..c0e1a35 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -126,6 +126,67 @@
return process;
}
+bool match(const vintf::ManifestInstance& instance, const FqInstance& fqInstance,
+ vintf::TransportArch ta) {
+ // For hwbinder libs, allow missing arch in manifest.
+ // For passthrough libs, allow missing interface/instance in table.
+ return (ta.transport == instance.transport()) &&
+ (ta.transport == vintf::Transport::HWBINDER ||
+ vintf::contains(instance.arch(), ta.arch)) &&
+ (!fqInstance.hasInterface() || fqInstance.getInterface() == instance.interface()) &&
+ (!fqInstance.hasInstance() || fqInstance.getInstance() == instance.instance());
+}
+
+bool match(const vintf::MatrixInstance& instance, const FqInstance& fqInstance,
+ vintf::TransportArch /* ta */) {
+ return (!fqInstance.hasInterface() || fqInstance.getInterface() == instance.interface()) &&
+ (!fqInstance.hasInstance() || instance.matchInstance(fqInstance.getInstance()));
+}
+
+template <typename ObjectType>
+VintfInfo getVintfInfo(const std::shared_ptr<const ObjectType>& object,
+ const FqInstance& fqInstance, vintf::TransportArch ta, VintfInfo value) {
+ bool found = false;
+ (void)object->forEachInstanceOfVersion(fqInstance.getPackage(), fqInstance.getVersion(),
+ [&](const auto& instance) {
+ found = match(instance, fqInstance, ta);
+ return !found; // continue if not found
+ });
+ return found ? value : VINTF_INFO_EMPTY;
+}
+
+std::shared_ptr<const vintf::HalManifest> ListCommand::getDeviceManifest() const {
+ return vintf::VintfObject::GetDeviceHalManifest();
+}
+
+std::shared_ptr<const vintf::CompatibilityMatrix> ListCommand::getDeviceMatrix() const {
+ return vintf::VintfObject::GetDeviceCompatibilityMatrix();
+}
+
+std::shared_ptr<const vintf::HalManifest> ListCommand::getFrameworkManifest() const {
+ return vintf::VintfObject::GetFrameworkHalManifest();
+}
+
+std::shared_ptr<const vintf::CompatibilityMatrix> ListCommand::getFrameworkMatrix() const {
+ return vintf::VintfObject::GetFrameworkCompatibilityMatrix();
+}
+
+VintfInfo ListCommand::getVintfInfo(const std::string& fqInstanceName,
+ vintf::TransportArch ta) const {
+ FqInstance fqInstance;
+ if (!fqInstance.setTo(fqInstanceName) &&
+ // Ignore interface / instance for passthrough libs
+ !fqInstance.setTo(splitFirst(fqInstanceName, ':').first)) {
+ err() << "Warning: Cannot parse '" << fqInstanceName << "'; no VINTF info." << std::endl;
+ return VINTF_INFO_EMPTY;
+ }
+
+ return lshal::getVintfInfo(getDeviceManifest(), fqInstance, ta, DEVICE_MANIFEST) |
+ lshal::getVintfInfo(getFrameworkManifest(), fqInstance, ta, FRAMEWORK_MANIFEST) |
+ lshal::getVintfInfo(getDeviceMatrix(), fqInstance, ta, DEVICE_MATRIX) |
+ lshal::getVintfInfo(getFrameworkMatrix(), fqInstance, ta, FRAMEWORK_MATRIX);
+}
+
static bool scanBinderContext(pid_t pid,
const std::string &contextName,
std::function<void(const std::string&)> eachLine) {
@@ -269,6 +330,7 @@
}
for (TableEntry& entry : table) {
entry.partition = getPartition(entry.serverPid);
+ entry.vintfInfo = getVintfInfo(entry.interfaceName, {entry.transport, entry.arch});
}
});
// use a double for loop here because lshal doesn't care about efficiency.
@@ -279,7 +341,7 @@
continue;
}
for (TableEntry &interfaceEntry : mPassthroughRefTable) {
- if (interfaceEntry.arch != ARCH_UNKNOWN) {
+ if (interfaceEntry.arch != vintf::Arch::ARCH_EMPTY) {
continue;
}
FQName interfaceName;
@@ -330,35 +392,22 @@
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;
+ if (entry.transport == vintf::Transport::HWBINDER) {
+ arch = vintf::Arch::ARCH_EMPTY; // no need to specify arch in manifest
+ } else if (entry.transport == vintf::Transport::PASSTHROUGH) {
+ if (entry.arch == vintf::Arch::ARCH_EMPTY) {
+ err() << "Warning: '" << entry.interfaceName << "' doesn't have bitness info.";
+ return false;
}
+ arch = entry.arch;
} 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)) {
+ if (!manifest->insertInstance(fqInstance, entry.transport, arch, vintf::HalFormat::HIDL, &e)) {
err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl;
return false;
}
@@ -440,15 +489,15 @@
" until they are updated.\n"
};
-static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+static vintf::Arch fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
switch (a) {
case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
- return ARCH64;
+ return vintf::Arch::ARCH_64;
case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
- return ARCH32;
+ return vintf::Arch::ARCH_32;
case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
default:
- return ARCH_UNKNOWN;
+ return vintf::Arch::ARCH_EMPTY;
}
}
@@ -534,7 +583,7 @@
std::string{info.instanceName.c_str()};
entries.emplace(interfaceName, TableEntry{
.interfaceName = interfaceName,
- .transport = "passthrough",
+ .transport = vintf::Transport::PASSTHROUGH,
.clientPids = info.clientPids,
}).first->second.arch |= fromBaseArchitecture(info.arch);
}
@@ -566,7 +615,7 @@
.interfaceName =
std::string{info.interfaceName.c_str()} + "/" +
std::string{info.instanceName.c_str()},
- .transport = "passthrough",
+ .transport = vintf::Transport::PASSTHROUGH,
.serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
.clientPids = info.clientPids,
.arch = fromBaseArchitecture(info.arch)
@@ -582,9 +631,11 @@
}
Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
+ using vintf::operator<<;
+
if (!shouldReportHalType(HalType::BINDERIZED_SERVICES)) { return OK; }
- const std::string mode = "hwbinder";
+ const vintf::Transport mode = vintf::Transport::HWBINDER;
hidl_vec<hidl_string> fqInstanceNames;
// copying out for timeoutIPC
auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
@@ -748,7 +799,7 @@
mOptions.push_back({'l', "released", no_argument, v++, [](ListCommand* thiz, const char*) {
thiz->mSelectedColumns.push_back(TableColumnType::RELEASED);
return OK;
- }, "print the 'is released?' column\n(Y=released, empty=unreleased or unknown)"});
+ }, "print the 'is released?' column\n(Y=released, N=unreleased, ?=unknown)"});
mOptions.push_back({'t', "transport", no_argument, v++, [](ListCommand* thiz, const char*) {
thiz->mSelectedColumns.push_back(TableColumnType::TRANSPORT);
return OK;
@@ -788,6 +839,15 @@
}, "Emit debug info from\nIBase::debug with empty options. Cannot be used with --neat.\n"
"Writes to specified file if 'arg' is provided, otherwise stdout."});
+ mOptions.push_back({'V', "vintf", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::VINTF);
+ return OK;
+ }, "print VINTF info. This column contains a comma-separated list of:\n"
+ " - DM: device manifest\n"
+ " - DC: device compatibility matrix\n"
+ " - FM: framework manifest\n"
+ " - FC: framework compatibility matrix"});
+
// long options without short alternatives
mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
thiz->mVintf = true;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index c35561d..87d93b5 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -28,6 +28,7 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-util/FqInstance.h>
#include <vintf/HalManifest.h>
+#include <vintf/VintfObject.h>
#include "Command.h"
#include "NullableOStream.h"
@@ -87,7 +88,9 @@
protected:
Status parseArgs(const Arg &arg);
+ // Retrieve first-hand information
Status fetch();
+ // Retrieve derived information base on existing table
virtual void postprocess();
Status dump();
void putEntry(TableEntrySource source, TableEntry &&entry);
@@ -122,6 +125,13 @@
virtual Partition getPartition(pid_t pid);
Partition resolvePartition(Partition processPartition, const FqInstance &fqInstance) const;
+ VintfInfo getVintfInfo(const std::string &fqInstanceName, vintf::TransportArch ta) const;
+ // Allow to mock these functions for testing.
+ virtual std::shared_ptr<const vintf::HalManifest> getDeviceManifest() const;
+ virtual std::shared_ptr<const vintf::CompatibilityMatrix> getDeviceMatrix() const;
+ virtual std::shared_ptr<const vintf::HalManifest> getFrameworkManifest() const;
+ virtual std::shared_ptr<const vintf::CompatibilityMatrix> getFrameworkMatrix() const;
+
void forEachTable(const std::function<void(Table &)> &f);
void forEachTable(const std::function<void(const Table &)> &f) const;
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index e8792a4..4ad3e92 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -16,7 +16,11 @@
#define LOG_TAG "lshal"
#include <android-base/logging.h>
+#include <map>
+
+#include <android-base/strings.h>
#include <hidl-hash/Hash.h>
+#include <vintf/parse_string.h>
#include "TableEntry.h"
@@ -26,19 +30,19 @@
namespace android {
namespace lshal {
-static const std::string &getArchString(Architecture arch) {
+static const std::string &getArchString(vintf::Arch arch) {
static const std::string sStr64 = "64";
static const std::string sStr32 = "32";
static const std::string sStrBoth = "32+64";
- static const std::string sStrUnknown = "";
+ static const std::string sStrUnknown = "?";
switch (arch) {
- case ARCH64:
+ case vintf::Arch::ARCH_64:
return sStr64;
- case ARCH32:
+ case vintf::Arch::ARCH_32:
return sStr32;
- case ARCH_BOTH:
+ case vintf::Arch::ARCH_32_64:
return sStrBoth;
- case ARCH_UNKNOWN: // fall through
+ case vintf::Arch::ARCH_EMPTY: // fall through
default:
return sStrUnknown;
}
@@ -57,6 +61,7 @@
case TableColumnType::THREADS: return "Thread Use";
case TableColumnType::RELEASED: return "R";
case TableColumnType::HASH: return "Hash";
+ case TableColumnType::VINTF: return "VINTF";
default:
LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
return "";
@@ -68,7 +73,7 @@
case TableColumnType::INTERFACE_NAME:
return interfaceName;
case TableColumnType::TRANSPORT:
- return transport;
+ return vintf::to_string(transport);
case TableColumnType::SERVER_PID:
return serverPid == NO_PID ? "N/A" : std::to_string(serverPid);
case TableColumnType::SERVER_CMD:
@@ -87,6 +92,8 @@
return isReleased();
case TableColumnType::HASH:
return hash;
+ case TableColumnType::VINTF:
+ return getVintfInfo();
default:
LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
return "";
@@ -96,12 +103,32 @@
std::string TableEntry::isReleased() const {
static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
- if (hash.empty() || hash == unreleased) {
- return " "; // unknown or unreleased
+ if (hash.empty()) {
+ return "?";
+ }
+ if (hash == unreleased) {
+ return "N"; // unknown or unreleased
}
return "Y"; // released
}
+std::string TableEntry::getVintfInfo() const {
+ static const std::map<VintfInfo, std::string> values{
+ {DEVICE_MANIFEST, "DM"},
+ {DEVICE_MATRIX, "DC"},
+ {FRAMEWORK_MANIFEST, "FM"},
+ {FRAMEWORK_MATRIX, "FC"},
+ };
+ std::vector<std::string> ret;
+ for (const auto& pair : values) {
+ if (vintfInfo & pair.first) {
+ ret.push_back(pair.second);
+ }
+ }
+ auto joined = base::Join(ret, ',');
+ return joined.empty() ? "X" : joined;
+}
+
TextTable Table::createTextTable(bool neat,
const std::function<std::string(const std::string&)>& emitDebugInfo) const {
@@ -152,6 +179,7 @@
}
std::string TableEntry::to_string() const {
+ using vintf::operator<<;
std::stringstream ss;
ss << "name=" << interfaceName << ";transport=" << transport << ";thread=" << getThreadUsage()
<< ";server=" << serverPid
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 24ea438..c9a6a23 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -24,6 +24,8 @@
#include <iostream>
#include <procpartition/procpartition.h>
+#include <vintf/Arch.h>
+#include <vintf/Transport.h>
#include "TextTable.h"
@@ -40,14 +42,6 @@
};
using TableEntrySource = unsigned int;
-enum : unsigned int {
- ARCH_UNKNOWN = 0,
- ARCH32 = 1 << 0,
- ARCH64 = 1 << 1,
- ARCH_BOTH = ARCH32 | ARCH64
-};
-using Architecture = unsigned int;
-
enum class TableColumnType : unsigned int {
INTERFACE_NAME,
TRANSPORT,
@@ -60,8 +54,18 @@
THREADS,
RELEASED,
HASH,
+ VINTF,
};
+enum : unsigned int {
+ VINTF_INFO_EMPTY = 0,
+ DEVICE_MANIFEST = 1 << 0,
+ DEVICE_MATRIX = 1 << 1,
+ FRAMEWORK_MANIFEST = 1 << 2,
+ FRAMEWORK_MATRIX = 1 << 3,
+};
+using VintfInfo = unsigned int;
+
enum {
NO_PID = -1,
NO_PTR = 0
@@ -69,7 +73,7 @@
struct TableEntry {
std::string interfaceName{};
- std::string transport{};
+ vintf::Transport transport{vintf::Transport::EMPTY};
int32_t serverPid{NO_PID};
uint32_t threadUsage{0};
uint32_t threadCount{0};
@@ -77,10 +81,11 @@
uint64_t serverObjectAddress{NO_PTR};
Pids clientPids{};
std::vector<std::string> clientCmdlines{};
- Architecture arch{ARCH_UNKNOWN};
+ vintf::Arch arch{vintf::Arch::ARCH_EMPTY};
// empty: unknown, all zeros: unreleased, otherwise: released
std::string hash{};
Partition partition{Partition::UNKNOWN};
+ VintfInfo vintfInfo{VINTF_INFO_EMPTY};
static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
return a.interfaceName < b.interfaceName;
@@ -99,6 +104,8 @@
std::string isReleased() const;
+ std::string getVintfInfo() const;
+
std::string getField(TableColumnType type) const;
bool operator==(const TableEntry& other) const;
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 3fc957b..501c04d 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -44,6 +44,13 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using android::vintf::Arch;
+using android::vintf::CompatibilityMatrix;
+using android::vintf::gCompatibilityMatrixConverter;
+using android::vintf::gHalManifestConverter;
+using android::vintf::HalManifest;
+using android::vintf::Transport;
+using android::vintf::VintfObject;
using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
@@ -207,6 +214,11 @@
MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
MOCK_METHOD1(getPartition, Partition(pid_t));
+
+ MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
+ MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
+ MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
+ MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
};
class ListParseArgsTest : public ::testing::Test {
@@ -335,6 +347,15 @@
});
}));
ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
+
+ ON_CALL(*mockList, getDeviceManifest())
+ .WillByDefault(Return(VintfObject::GetDeviceHalManifest()));
+ ON_CALL(*mockList, getDeviceMatrix())
+ .WillByDefault(Return(VintfObject::GetDeviceCompatibilityMatrix()));
+ ON_CALL(*mockList, getFrameworkManifest())
+ .WillByDefault(Return(VintfObject::GetFrameworkHalManifest()));
+ ON_CALL(*mockList, getFrameworkMatrix())
+ .WillByDefault(Return(VintfObject::GetFrameworkCompatibilityMatrix()));
}
void initMockServiceManager() {
@@ -389,25 +410,28 @@
TEST_F(ListTest, Fetch) {
EXPECT_EQ(0u, mockList->fetch());
- std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
- "passthrough", "passthrough", "passthrough"}};
- std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
+ vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
+ vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
+ std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
+ passthrough, passthrough, passthrough}};
int id = 1;
mockList->forEachTable([&](const Table& table) {
ASSERT_EQ(2u, table.size());
for (const auto& entry : table) {
- const auto& transport = transports[id - 1];
+ auto transport = transportArchs.at(id - 1).transport;
TableEntry expected{
.interfaceName = getFqInstanceName(id),
.transport = transport,
- .serverPid = transport == "hwbinder" ? id : NO_PID,
- .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
- .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
+ .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
+ .threadUsage =
+ transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
+ .threadCount =
+ transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
.serverCmdline = {},
- .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
+ .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
.clientPids = getClients(id),
.clientCmdlines = {},
- .arch = archs[id - 1],
+ .arch = transportArchs.at(id - 1).arch,
};
EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
@@ -460,18 +484,18 @@
const std::string expected =
"[fake description 0]\n"
"R Interface Thread Use Server Clients\n"
- " a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
+ "N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
"Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
"\n"
"[fake description 1]\n"
"R Interface Thread Use Server Clients\n"
- " a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
- " a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
+ "? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
+ "? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
"\n"
"[fake description 2]\n"
"R Interface Thread Use Server Clients\n"
- " a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
- " a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
+ "? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
+ "? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
"\n";
optind = 1; // mimic Lshal::parseArg()
@@ -484,18 +508,18 @@
const std::string expected =
"[fake description 0]\n"
"Interface R Hash\n"
- "a.h.foo1@1.0::IFoo/1 0000000000000000000000000000000000000000000000000000000000000000\n"
+ "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
"a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
"\n"
"[fake description 1]\n"
"Interface R Hash\n"
- "a.h.foo3@3.0::IFoo/3 \n"
- "a.h.foo4@4.0::IFoo/4 \n"
+ "a.h.foo3@3.0::IFoo/3 ? \n"
+ "a.h.foo4@4.0::IFoo/4 ? \n"
"\n"
"[fake description 2]\n"
"Interface R Hash\n"
- "a.h.foo5@5.0::IFoo/5 \n"
- "a.h.foo6@6.0::IFoo/6 \n"
+ "a.h.foo5@5.0::IFoo/5 ? \n"
+ "a.h.foo6@6.0::IFoo/6 ? \n"
"\n";
optind = 1; // mimic Lshal::parseArg()
@@ -651,6 +675,87 @@
EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: a"));
}
+TEST_F(ListTest, Vintf) {
+ std::string deviceManifestXml =
+ "<manifest version=\"1.0\" type=\"device\">\n"
+ " <hal>\n"
+ " <name>a.h.foo1</name>\n"
+ " <transport>hwbinder</transport>\n"
+ " <fqname>@1.0::IFoo/1</fqname>\n"
+ " </hal>\n"
+ " <hal>\n"
+ " <name>a.h.foo3</name>\n"
+ " <transport arch=\"32+64\">passthrough</transport>\n"
+ " <fqname>@3.0::IFoo/3</fqname>\n"
+ " </hal>\n"
+ "</manifest>\n";
+ std::string frameworkManifestXml =
+ "<manifest version=\"1.0\" type=\"framework\">\n"
+ " <hal>\n"
+ " <name>a.h.foo5</name>\n"
+ " <transport arch=\"32\">passthrough</transport>\n"
+ " <fqname>@5.0::IFoo/5</fqname>\n"
+ " </hal>\n"
+ "</manifest>\n";
+ std::string deviceMatrixXml =
+ "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
+ " <hal>\n"
+ " <name>a.h.foo5</name>\n"
+ " <version>5.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>5</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ "</compatibility-matrix>\n";
+ std::string frameworkMatrixXml =
+ "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+ " <hal>\n"
+ " <name>a.h.foo1</name>\n"
+ " <version>1.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>1</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ " <hal>\n"
+ " <name>a.h.foo3</name>\n"
+ " <version>3.0</version>\n"
+ " <interface>\n"
+ " <name>IFoo</name>\n"
+ " <instance>3</instance>\n"
+ " </interface>\n"
+ " </hal>\n"
+ "</compatibility-matrix>\n";
+
+ std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
+ "X a.h.foo2@2.0::IFoo/2\n"
+ "DM,FC a.h.foo3@3.0::IFoo/3\n"
+ "X a.h.foo4@4.0::IFoo/4\n"
+ "DC,FM a.h.foo5@5.0::IFoo/5\n"
+ "X a.h.foo6@6.0::IFoo/6\n";
+
+ auto deviceManifest = std::make_shared<HalManifest>();
+ auto frameworkManifest = std::make_shared<HalManifest>();
+ auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
+ auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
+
+ ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
+ ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
+ ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
+ ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
+
+ ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
+ ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
+ ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
+ ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
+ EXPECT_THAT(out.str(), HasSubstr(expected));
+ EXPECT_EQ("", err.str());
+}
+
class HelpTest : public ::testing::Test {
public:
void SetUp() override {
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 0f1fe5b..227d0ae 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -142,7 +142,7 @@
{
return remote();
}
-
+
// ----------------------------------------------------------------------
}; // namespace android