lshal: add Released column.
Example output:
$ lshal --neat -lis
...
Y android.hardware.configstore@1.0::ISurfaceFlingerConfigs/default 7f5fe8f4f8a24037153c504d8b4d3313c2ce33d81c8c69fe5194ddd2d4080e72
android.hardware.configstore@1.1::ISurfaceFlingerConfigs/default 0000000000000000000000000000000000000000000000000000000000000000
...
Bug: 65123158
Test: lshal_test
Test: lshal
Test: lshal -ils
Test: lshal --help
Change-Id: I18e52eb977461d68909057583be8223d53f6748b
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 5a87505..6cbe7e2 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -20,6 +20,7 @@
"libutils",
"libhidlbase",
"libhidltransport",
+ "libhidl-gen-hash",
"libhidl-gen-utils",
"libvintf",
],
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index f1f0808..7399692 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -27,6 +27,7 @@
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-hash/Hash.h>
#include <hidl-util/FQName.h>
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
@@ -590,6 +591,44 @@
entry->threadCount = pidInfo->threadCount;
}
} while (0);
+
+ // hash
+ do {
+ ssize_t hashIndex = -1;
+ auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) {
+ for (size_t i = 0; i < c.size(); ++i) {
+ if (serviceName == c[i]) {
+ hashIndex = static_cast<ssize_t>(i);
+ break;
+ }
+ }
+ });
+ if (!ifaceChainRet.isOk()) {
+ handleError(TRANSACTION_ERROR,
+ "interfaceChain fails: " + ifaceChainRet.description());
+ break; // skip getHashChain
+ }
+ if (hashIndex < 0) {
+ handleError(BAD_IMPL, "Interface name does not exist in interfaceChain.");
+ break; // skip getHashChain
+ }
+ auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) {
+ if (static_cast<size_t>(hashIndex) >= hashChain.size()) {
+ handleError(BAD_IMPL,
+ "interfaceChain indicates position " + std::to_string(hashIndex) +
+ " but getHashChain returns " + std::to_string(hashChain.size()) +
+ " hashes");
+ return;
+ }
+
+ auto&& hashArray = hashChain[hashIndex];
+ std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
+ entry->hash = Hash::hexString(hashVec);
+ });
+ if (!hashRet.isOk()) {
+ handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
+ }
+ } while (0);
return status;
}
@@ -627,6 +666,10 @@
thiz->mSelectedColumns.push_back(TableColumnType::INTERFACE_NAME);
return OK;
}, "print the instance name column"});
+ 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)"});
mOptions.push_back({'t', "transport", no_argument, v++, [](ListCommand* thiz, const char*) {
thiz->mSelectedColumns.push_back(TableColumnType::TRANSPORT);
return OK;
@@ -635,6 +678,10 @@
thiz->mSelectedColumns.push_back(TableColumnType::ARCH);
return OK;
}, "print the bitness column"});
+ mOptions.push_back({'s', "hash", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::HASH);
+ return OK;
+ }, "print hash of the interface"});
mOptions.push_back({'p', "pid", no_argument, v++, [](ListCommand* thiz, const char*) {
thiz->mSelectedColumns.push_back(TableColumnType::SERVER_PID);
return OK;
@@ -777,7 +824,8 @@
}
if (mSelectedColumns.empty()) {
- mSelectedColumns = {TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
+ mSelectedColumns = {TableColumnType::RELEASED,
+ TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
}
@@ -845,7 +893,7 @@
err() << "list:" << std::endl
<< " lshal" << std::endl
<< " lshal list" << std::endl
- << " List all hals with default ordering and columns (`lshal list -iepc`)" << std::endl
+ << " List all hals with default ordering and columns (`lshal list -riepc`)" << std::endl
<< " lshal list [-h|--help]" << std::endl
<< " -h, --help: Print help message for list (`lshal help list`)" << std::endl
<< " lshal [list] [OPTIONS...]" << std::endl;
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index cbcf979..e8792a4 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "lshal"
#include <android-base/logging.h>
+#include <hidl-hash/Hash.h>
+
#include "TableEntry.h"
#include "TextTable.h"
@@ -53,8 +55,10 @@
case TableColumnType::CLIENT_CMDS: return "Clients CMD";
case TableColumnType::ARCH: return "Arch";
case TableColumnType::THREADS: return "Thread Use";
+ case TableColumnType::RELEASED: return "R";
+ case TableColumnType::HASH: return "Hash";
default:
- LOG(FATAL) << "Should not reach here.";
+ LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
return "";
}
}
@@ -79,12 +83,25 @@
return getArchString(arch);
case TableColumnType::THREADS:
return getThreadUsage();
+ case TableColumnType::RELEASED:
+ return isReleased();
+ case TableColumnType::HASH:
+ return hash;
default:
- LOG(FATAL) << "Should not reach here.";
+ LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
return "";
}
}
+std::string TableEntry::isReleased() const {
+ static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+
+ if (hash.empty() || hash == unreleased) {
+ return " "; // unknown or unreleased
+ }
+ return "Y"; // released
+}
+
TextTable Table::createTextTable(bool neat,
const std::function<std::string(const std::string&)>& emitDebugInfo) const {
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 497bedf..69206cc 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -55,6 +55,8 @@
CLIENT_CMDS,
ARCH,
THREADS,
+ RELEASED,
+ HASH,
};
enum {
@@ -73,6 +75,8 @@
Pids clientPids{};
std::vector<std::string> clientCmdlines{};
Architecture arch{ARCH_UNKNOWN};
+ // empty: unknown, all zeros: unreleased, otherwise: released
+ std::string hash{};
static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
return a.interfaceName < b.interfaceName;
@@ -89,6 +93,8 @@
return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
}
+ std::string isReleased() 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 7d87d6d..9220fc0 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -39,6 +39,7 @@
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_array;
using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
@@ -46,6 +47,8 @@
using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
+using hidl_hash = hidl_array<uint8_t, 32>;
+
namespace android {
namespace hardware {
namespace tests {
@@ -277,17 +280,34 @@
if (serverId == NO_PID) return "";
return "command_line_" + std::to_string(serverId);
}
+static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
+static hidl_hash getHashFromId(pid_t serverId) {
+ hidl_hash hash;
+ bool isReleased = getIsReleasedFromId(serverId);
+ for (size_t i = 0; i < hash.size(); ++i) {
+ hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
+ }
+ return hash;
+}
// Fake service returned by mocked IServiceManager::get.
class TestService : public IBase {
public:
- TestService(DebugInfo&& info) : mInfo(std::move(info)) {}
+ TestService(pid_t id) : mId(id) {}
hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
- cb(mInfo);
+ cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
+ return hardware::Void();
+ }
+ hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
+ cb({getInterfaceName(mId), IBase::descriptor});
+ return hardware::Void();
+ }
+ hardware::Return<void> getHashChain(getHashChain_cb cb) override {
+ cb({getHashFromId(mId), getHashFromId(0xff)});
return hardware::Void();
}
private:
- DebugInfo mInfo;
+ pid_t mId;
};
class ListTest : public ::testing::Test {
@@ -328,7 +348,7 @@
ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
[&](const hidl_string&, const hidl_string& instance) {
int id = getIdFromInstanceName(instance);
- return sp<IBase>(new TestService({ id /* pid */, getPtr(id), A::IS_64BIT }));
+ return sp<IBase>(new TestService(id));
}));
ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
@@ -473,6 +493,55 @@
<< vintf::gHalManifestConverter.lastError();
}
+// test default columns
+TEST_F(ListTest, DumpDefault) {
+ 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"
+ "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"
+ "\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"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpHash) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "Interface R Hash\n"
+ "a.h.foo1@1.0::IFoo/1 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"
+ "\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"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
TEST_F(ListTest, Dump) {
const std::string expected =
"[fake description 0]\n"
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index 7eca14e..c09e8b1 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -44,6 +44,8 @@
NO_INTERFACE = 1 << 7,
// Transaction error from hwbinder transactions
TRANSACTION_ERROR = 1 << 8,
+ // No transaction error, but return value is unexpected.
+ BAD_IMPL = 1 << 9,
};
using Status = unsigned int;