lshal: add "Status" column and "Manifest HALs" section.
- Added "Status" column that has following values:
- alive: running hwbinder service
- registered;dead: registered, but service cannot accept calls
- declared: only in VINTF, not in hwservicemanager
- N/A: passthrough HALs
- Added a "Manifest HALs" section that lists all
HALs (hwbinder or passthrough) in device / framework manifest
Test: lshal_test
Bug: 71555570
Change-Id: I202b562ee73bcd49506bb43cc9af27b86f32651c
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index d497e5c..1a412b2 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -57,6 +57,19 @@
return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
}
+Partition toPartition(vintf::SchemaType t) {
+ switch (t) {
+ case vintf::SchemaType::FRAMEWORK: return Partition::SYSTEM;
+ // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM.
+ case vintf::SchemaType::DEVICE: return Partition::VENDOR;
+ }
+ return Partition::UNKNOWN;
+}
+
+std::string getPackageAndVersion(const std::string& fqInstance) {
+ return splitFirst(fqInstance, ':').first;
+}
+
NullableOStream<std::ostream> ListCommand::out() const {
return mLshal.out();
}
@@ -77,6 +90,8 @@
}
const std::string &ListCommand::getCmdline(pid_t pid) {
+ static const std::string kEmptyString{};
+ if (pid == NO_PID) return kEmptyString;
auto pair = mCmdlines.find(pid);
if (pair != mCmdlines.end()) {
return pair->second;
@@ -93,6 +108,7 @@
}
Partition ListCommand::getPartition(pid_t pid) {
+ if (pid == NO_PID) return Partition::UNKNOWN;
auto it = mPartitions.find(pid);
if (it != mPartitions.end()) {
return it->second;
@@ -176,7 +192,7 @@
FqInstance fqInstance;
if (!fqInstance.setTo(fqInstanceName) &&
// Ignore interface / instance for passthrough libs
- !fqInstance.setTo(splitFirst(fqInstanceName, ':').first)) {
+ !fqInstance.setTo(getPackageAndVersion(fqInstanceName))) {
err() << "Warning: Cannot parse '" << fqInstanceName << "'; no VINTF info." << std::endl;
return VINTF_INFO_EMPTY;
}
@@ -283,8 +299,8 @@
return &pair.first->second;
}
-bool ListCommand::shouldReportHalType(const HalType &type) const {
- return (std::find(mListTypes.begin(), mListTypes.end(), type) != mListTypes.end());
+bool ListCommand::shouldFetchHalType(const HalType &type) const {
+ return (std::find(mFetchTypes.begin(), mFetchTypes.end(), type) != mFetchTypes.end());
}
Table* ListCommand::tableForType(HalType type) {
@@ -295,6 +311,8 @@
return &mPassthroughRefTable;
case HalType::PASSTHROUGH_LIBRARIES:
return &mImplementationsTable;
+ case HalType::VINTF_MANIFEST:
+ return &mManifestHalsTable;
default:
LOG(FATAL) << "Unknown HAL type " << static_cast<int64_t>(type);
return nullptr;
@@ -328,7 +346,9 @@
}
}
for (TableEntry& entry : table) {
- entry.partition = getPartition(entry.serverPid);
+ if (entry.partition == Partition::UNKNOWN) {
+ entry.partition = getPartition(entry.serverPid);
+ }
entry.vintfInfo = getVintfInfo(entry.interfaceName, {entry.transport, entry.arch});
}
});
@@ -365,6 +385,8 @@
mImplementationsTable.setDescription(
"All available passthrough implementations (all -impl.so files).\n"
"These may return subclasses through their respective HIDL_FETCH_I* functions.");
+ mManifestHalsTable.setDescription(
+ "All HALs that are in VINTF manifest.");
}
bool ListCommand::addEntryWithInstance(const TableEntry& entry,
@@ -415,7 +437,7 @@
bool ListCommand::addEntryWithoutInstance(const TableEntry& entry,
const vintf::HalManifest* manifest) const {
- const auto& packageAndVersion = splitFirst(splitFirst(entry.interfaceName, ':').first, '@');
+ const auto& packageAndVersion = splitFirst(getPackageAndVersion(entry.interfaceName), '@');
const auto& package = packageAndVersion.first;
vintf::Version version;
if (!vintf::parse(packageAndVersion.second, &version)) {
@@ -445,6 +467,8 @@
if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
for (const TableEntry& entry : mPassthroughRefTable)
if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
+ for (const TableEntry& entry : mManifestHalsTable)
+ if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
std::vector<std::string> passthrough;
for (const TableEntry& entry : mImplementationsTable)
@@ -559,7 +583,7 @@
}
Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) {
- if (!shouldReportHalType(HalType::PASSTHROUGH_LIBRARIES)) { return OK; }
+ if (!shouldFetchHalType(HalType::PASSTHROUGH_LIBRARIES)) { return OK; }
using namespace ::android::hardware;
using namespace ::android::hidl::manager::V1_0;
@@ -589,7 +613,7 @@
}
Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) {
- if (!shouldReportHalType(HalType::PASSTHROUGH_CLIENTS)) { return OK; }
+ if (!shouldFetchHalType(HalType::PASSTHROUGH_CLIENTS)) { return OK; }
using namespace ::android::hardware;
using namespace ::android::hardware::details;
@@ -622,7 +646,7 @@
Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
using vintf::operator<<;
- if (!shouldReportHalType(HalType::BINDERIZED_SERVICES)) { return OK; }
+ if (!shouldFetchHalType(HalType::BINDERIZED_SERVICES)) { return OK; }
const vintf::Transport mode = vintf::Transport::HWBINDER;
hidl_vec<hidl_string> fqInstanceNames;
@@ -643,6 +667,7 @@
TableEntry& entry = allTableEntries[fqInstanceName];
entry.interfaceName = fqInstanceName;
entry.transport = mode;
+ entry.serviceStatus = ServiceStatus::NON_RESPONSIVE;
status |= fetchBinderizedEntry(manager, &entry);
}
@@ -748,6 +773,40 @@
handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
}
} while (0);
+ if (status == OK) {
+ entry->serviceStatus = ServiceStatus::ALIVE;
+ }
+ return status;
+}
+
+Status ListCommand::fetchManifestHals() {
+ if (!shouldFetchHalType(HalType::VINTF_MANIFEST)) { return OK; }
+ Status status = OK;
+
+ for (auto manifest : {getDeviceManifest(), getFrameworkManifest()}) {
+ if (manifest == nullptr) {
+ status |= VINTF_ERROR;
+ continue;
+ }
+
+ std::map<std::string, TableEntry> entries;
+
+ manifest->forEachInstance([&] (const vintf::ManifestInstance& manifestInstance) {
+ TableEntry entry{
+ .interfaceName = manifestInstance.getFqInstance().string(),
+ .transport = manifestInstance.transport(),
+ .arch = manifestInstance.arch(),
+ // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM.
+ .partition = toPartition(manifest->type()),
+ .serviceStatus = ServiceStatus::DECLARED};
+ std::string key = entry.interfaceName;
+ entries.emplace(std::move(key), std::move(entry));
+ return true;
+ });
+
+ for (auto&& pair : entries)
+ mManifestHalsTable.add(std::move(pair.second));
+ }
return status;
}
@@ -770,9 +829,14 @@
} else {
status |= fetchAllLibraries(pManager);
}
+ status |= fetchManifestHals();
return status;
}
+void ListCommand::initFetchTypes() {
+ mFetchTypes.insert(mListTypes.begin(), mListTypes.end());
+}
+
void ListCommand::registerAllOptions() {
int v = mOptions.size();
// A list of acceptable command line options
@@ -836,6 +900,14 @@
" - DC: device compatibility matrix\n"
" - FM: framework manifest\n"
" - FC: framework compatibility matrix"});
+ mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
+ return OK;
+ }, "print service status column. Possible values are:\n"
+ " - alive: alive and running hwbinder service;\n"
+ " - registered;dead: registered to hwservicemanager but is not responsive;\n"
+ " - declared: only declared in VINTF manifest but is not registered to hwservicemanager;\n"
+ " - N/A: no information for passthrough HALs."});
// long options without short alternatives
mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
@@ -876,7 +948,9 @@
{"passthrough_clients", HalType::PASSTHROUGH_CLIENTS},
{"c", HalType::PASSTHROUGH_CLIENTS},
{"passthrough_libs", HalType::PASSTHROUGH_LIBRARIES},
- {"l", HalType::PASSTHROUGH_LIBRARIES}
+ {"l", HalType::PASSTHROUGH_LIBRARIES},
+ {"vintf", HalType::VINTF_MANIFEST},
+ {"v", HalType::VINTF_MANIFEST},
};
std::vector<std::string> halTypesArgs = split(std::string(arg), ',');
@@ -900,9 +974,9 @@
if (thiz->mListTypes.empty()) { return USAGE; }
return OK;
- }, "comma-separated list of one or more HAL types.\nThe output is restricted to the selected "
- "association(s). Valid options\nare: (b|binderized), (c|passthrough_clients), and (l|"
- "passthrough_libs).\nBy default, lists all available HALs."});
+ }, "comma-separated list of one or more sections.\nThe output is restricted to the selected "
+ "section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
+ "passthrough_libs), and (v|vintf).\nDefault is `bcl`."});
}
// Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
@@ -1019,6 +1093,7 @@
mListTypes = {HalType::BINDERIZED_SERVICES, HalType::PASSTHROUGH_CLIENTS,
HalType::PASSTHROUGH_LIBRARIES};
}
+ initFetchTypes();
forEachTable([this] (Table& table) {
table.setSelectedColumns(this->mSelectedColumns);