diff options
author | 2017-09-14 18:23:38 -0700 | |
---|---|---|
committer | 2017-09-15 12:36:50 -0700 | |
commit | fee209dda24dc94277df020fee3d91f1194e5ea1 (patch) | |
tree | cdcf51a4fe30f62b4c2f4340d1352870c2ad3459 | |
parent | 22ea7b851dbe753eda2a703952bbc803c1dcfc1f (diff) |
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
-rw-r--r-- | cmds/lshal/Android.bp | 1 | ||||
-rw-r--r-- | cmds/lshal/ListCommand.cpp | 52 | ||||
-rw-r--r-- | cmds/lshal/TableEntry.cpp | 21 | ||||
-rw-r--r-- | cmds/lshal/TableEntry.h | 6 | ||||
-rw-r--r-- | cmds/lshal/test.cpp | 77 | ||||
-rw-r--r-- | cmds/lshal/utils.h | 2 |
6 files changed, 151 insertions, 8 deletions
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp index 5a87505113..6cbe7e24fa 100644 --- a/cmds/lshal/Android.bp +++ b/cmds/lshal/Android.bp @@ -20,6 +20,7 @@ cc_library_shared { "libutils", "libhidlbase", "libhidltransport", + "libhidl-gen-hash", "libhidl-gen-utils", "libvintf", ], diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index f1f0808f30..73996925b1 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 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager, 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 @@ void ListCommand::registerAllOptions() { 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 @@ void ListCommand::registerAllOptions() { 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 @@ Status ListCommand::parseArgs(const Arg &arg) { } 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 @@ void ListCommand::usage() const { 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 cbcf979f90..e8792a4307 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 @@ static std::string getTitle(TableColumnType type) { 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 @@ std::string TableEntry::getField(TableColumnType type) const { 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 497bedf12d..69206cc51b 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -55,6 +55,8 @@ enum class TableColumnType : unsigned int { CLIENT_CMDS, ARCH, THREADS, + RELEASED, + HASH, }; enum { @@ -73,6 +75,8 @@ struct TableEntry { 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 @@ struct TableEntry { 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 7d87d6d4cc..9220fc09fb 100644 --- a/cmds/lshal/test.cpp +++ b/cmds/lshal/test.cpp @@ -39,6 +39,7 @@ using ::android::hidl::base::V1_0::DebugInfo; 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 ::android::hardware::hidl_vec; using InstanceDebugInfo = IServiceManager::InstanceDebugInfo; +using hidl_hash = hidl_array<uint8_t, 32>; + namespace android { namespace hardware { namespace tests { @@ -277,17 +280,34 @@ static std::string getCmdlineFromId(pid_t serverId) { 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 @@ public: 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 @@ TEST_F(ListTest, DumpVintf) { << 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 7eca14e0f7..c09e8b1666 100644 --- a/cmds/lshal/utils.h +++ b/cmds/lshal/utils.h @@ -44,6 +44,8 @@ enum : unsigned int { 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; |