From 30528a2d917aae624f01a89213147da44fee2ab9 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 7 Aug 2020 18:24:06 -0700 Subject: [PATCH] lshal: Add --all --types=all, and use in bugreport Also clang-format. When --all is specified, put "clients" at the end because it is usually the longest. Test: lshal --all Test: lshal --all --cmdline Test: lshal --types=all Test: adb bugreport Bug: 163060248 Change-Id: If95a18cff50d3b6ef3f70b300f16105b41ca28ed --- cmds/dumpstate/dumpstate.cpp | 4 +- cmds/lshal/ListCommand.cpp | 100 +++++++++++++++++++++++------------ cmds/lshal/ListCommand.h | 3 ++ cmds/lshal/TableEntry.h | 14 +++-- cmds/lshal/test.cpp | 69 +++++++++++++++++++++++- 5 files changed, 147 insertions(+), 43 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 78c09f2b5a..e2884e578c 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1237,12 +1237,12 @@ static Dumpstate::RunStatus RunDumpsysNormal() { static void DumpHals() { if (!ds.IsZipping()) { - RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"}, + RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); return; } DurationReporter duration_reporter("DUMP HALS"); - RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"}, + RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build()); using android::hidl::manager::V1_0::IServiceManager; diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index a805a4844a..92958d957b 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -916,6 +916,18 @@ void ListCommand::initFetchTypes() { } } +// Get all values of enum type T, assuming the first value is 0 and the last value is T::LAST. +// T::LAST is not included in the returned list. +template +std::vector GetAllValues() { + using BaseType = std::underlying_type_t; + std::vector ret; + for (BaseType i = 0; i < static_cast(T::LAST); ++i) { + ret.push_back(static_cast(i)); + } + return ret; +} + void ListCommand::registerAllOptions() { int v = mOptions.size(); // A list of acceptable command line options @@ -989,6 +1001,15 @@ void ListCommand::registerAllOptions() { " - declared: only declared in VINTF manifest but is not registered to hwservicemanager;\n" " - N/A: no information for passthrough HALs."}); + mOptions.push_back({'A', "all", no_argument, v++, + [](ListCommand* thiz, const char*) { + auto allColumns = GetAllValues(); + thiz->mSelectedColumns.insert(thiz->mSelectedColumns.end(), + allColumns.begin(), allColumns.end()); + return OK; + }, + "print all columns"}); + // long options without short alternatives mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) { thiz->mVintf = true; @@ -1019,46 +1040,55 @@ void ListCommand::registerAllOptions() { thiz->mNeat = true; return OK; }, "output is machine parsable (no explanatory text).\nCannot be used with --debug."}); - mOptions.push_back({'\0', "types", required_argument, v++, [](ListCommand* thiz, const char* arg) { - if (!arg) { return USAGE; } + mOptions.push_back( + {'\0', "types", required_argument, v++, + [](ListCommand* thiz, const char* arg) { + if (!arg) { + return USAGE; + } - static const std::map kHalTypeMap { - {"binderized", HalType::BINDERIZED_SERVICES}, - {"b", HalType::BINDERIZED_SERVICES}, - {"passthrough_clients", HalType::PASSTHROUGH_CLIENTS}, - {"c", HalType::PASSTHROUGH_CLIENTS}, - {"passthrough_libs", HalType::PASSTHROUGH_LIBRARIES}, - {"l", HalType::PASSTHROUGH_LIBRARIES}, - {"vintf", HalType::VINTF_MANIFEST}, - {"v", HalType::VINTF_MANIFEST}, - {"lazy", HalType::LAZY_HALS}, - {"z", HalType::LAZY_HALS}, - }; + static const std::map> kHalTypeMap{ + {"binderized", {HalType::BINDERIZED_SERVICES}}, + {"b", {HalType::BINDERIZED_SERVICES}}, + {"passthrough_clients", {HalType::PASSTHROUGH_CLIENTS}}, + {"c", {HalType::PASSTHROUGH_CLIENTS}}, + {"passthrough_libs", {HalType::PASSTHROUGH_LIBRARIES}}, + {"l", {HalType::PASSTHROUGH_LIBRARIES}}, + {"vintf", {HalType::VINTF_MANIFEST}}, + {"v", {HalType::VINTF_MANIFEST}}, + {"lazy", {HalType::LAZY_HALS}}, + {"z", {HalType::LAZY_HALS}}, + {"all", GetAllValues()}, + {"a", GetAllValues()}, + }; - std::vector halTypesArgs = split(std::string(arg), ','); - for (const auto& halTypeArg : halTypesArgs) { - if (halTypeArg.empty()) continue; + std::vector halTypesArgs = split(std::string(arg), ','); + for (const auto& halTypeArg : halTypesArgs) { + if (halTypeArg.empty()) continue; - const auto& halTypeIter = kHalTypeMap.find(halTypeArg); - if (halTypeIter == kHalTypeMap.end()) { + const auto& halTypeIter = kHalTypeMap.find(halTypeArg); + if (halTypeIter == kHalTypeMap.end()) { + thiz->err() << "Unrecognized HAL type: " << halTypeArg << std::endl; + return USAGE; + } - thiz->err() << "Unrecognized HAL type: " << halTypeArg << std::endl; - return USAGE; - } + // Append unique (non-repeated) HAL types to the reporting list + for (auto halType : halTypeIter->second) { + if (std::find(thiz->mListTypes.begin(), thiz->mListTypes.end(), halType) == + thiz->mListTypes.end()) { + thiz->mListTypes.push_back(halType); + } + } + } - // Append unique (non-repeated) HAL types to the reporting list - HalType halType = halTypeIter->second; - if (std::find(thiz->mListTypes.begin(), thiz->mListTypes.end(), halType) == - thiz->mListTypes.end()) { - thiz->mListTypes.push_back(halType); - } - } - - if (thiz->mListTypes.empty()) { return USAGE; } - return OK; - }, "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), (v|vintf), and (z|lazy).\nDefault is `bcl`."}); + if (thiz->mListTypes.empty()) { + return USAGE; + } + return OK; + }, + "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), (v|vintf), (z|lazy), and (a|all).\nDefault is `b,c,l`."}); } // Create 'longopts' argument to getopt_long. Caller is responsible for maintaining diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h index acc0dcfc2e..412aadd7e4 100644 --- a/cmds/lshal/ListCommand.h +++ b/cmds/lshal/ListCommand.h @@ -52,6 +52,9 @@ enum class HalType { PASSTHROUGH_LIBRARIES, VINTF_MANIFEST, LAZY_HALS, + + // Not a real HalType. Used to determine all HalTypes. + LAST, }; class ListCommand : public Command { diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h index 0ff0c96d38..3c368132a5 100644 --- a/cmds/lshal/TableEntry.h +++ b/cmds/lshal/TableEntry.h @@ -35,19 +35,25 @@ using android::procpartition::Partition; using Pids = std::vector; enum class TableColumnType : unsigned int { - INTERFACE_NAME, + INTERFACE_NAME = 0, TRANSPORT, SERVER_PID, - SERVER_CMD, SERVER_ADDR, - CLIENT_PIDS, - CLIENT_CMDS, ARCH, THREADS, RELEASED, HASH, VINTF, SERVICE_STATUS, + CLIENT_PIDS, + + // Not a real TableColumnType. Used to determine all TableColumnTypes. + LAST, + + // Not included in all TableColumnTypes because they replace *PID(S) when the + // --cmdline option is set. + SERVER_CMD, + CLIENT_CMDS, }; enum : unsigned int { diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp index afe5d63575..9964888233 100644 --- a/cmds/lshal/test.cpp +++ b/cmds/lshal/test.cpp @@ -708,8 +708,8 @@ TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) { TEST_F(ListTest, UnknownHalType) { optind = 1; // mimic Lshal::parseArg() - EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,a"}))); - EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: a")); + EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,r"}))); + EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: r")); } TEST_F(ListTest, Vintf) { @@ -793,6 +793,71 @@ TEST_F(ListTest, Vintf) { EXPECT_EQ("", err.str()); } +TEST_F(ListTest, AllColumns) { + // clang-format off + const std::string expected = + "[fake description 0]\n" + "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n" + "a.h.foo1@1.0::IFoo/1 hwbinder 1 0000000000002711 64 11/21 N 0000000000000000000000000000000000000000000000000000000000000000 X alive 2 4\n" + "a.h.foo2@2.0::IFoo/2 hwbinder 2 0000000000002712 64 12/22 Y 0202020202020202020202020202020202020202020202020202020202020202 X alive 3 5\n" + "\n" + "[fake description 1]\n" + "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n" + "a.h.foo3@3.0::IFoo/3 passthrough N/A N/A 32 N/A ? X N/A 4 6\n" + "a.h.foo4@4.0::IFoo/4 passthrough N/A N/A 32 N/A ? X N/A 5 7\n" + "\n" + "[fake description 2]\n" + "Interface Transport Server PTR Arch Thread Use R Hash VINTF Status Clients\n" + "a.h.foo5@5.0::IFoo/5 passthrough N/A N/A 32 N/A ? X N/A 6 8\n" + "a.h.foo6@6.0::IFoo/6 passthrough N/A N/A 32 N/A ? X N/A 7 9\n" + "\n"; + // clang-format on + + optind = 1; // mimic Lshal::parseArg() + EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--all"}))); + EXPECT_EQ(expected, out.str()); + EXPECT_EQ("", err.str()); +} + +TEST_F(ListTest, AllColumnsWithCmd) { + // clang-format off + const std::string expected = + "[fake description 0]\n" + "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n" + "a.h.foo1@1.0::IFoo/1 hwbinder command_line_1 0000000000002711 64 11/21 N 0000000000000000000000000000000000000000000000000000000000000000 X alive command_line_2;command_line_4\n" + "a.h.foo2@2.0::IFoo/2 hwbinder command_line_2 0000000000002712 64 12/22 Y 0202020202020202020202020202020202020202020202020202020202020202 X alive command_line_3;command_line_5\n" + "\n" + "[fake description 1]\n" + "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n" + "a.h.foo3@3.0::IFoo/3 passthrough N/A 32 N/A ? X N/A command_line_4;command_line_6\n" + "a.h.foo4@4.0::IFoo/4 passthrough N/A 32 N/A ? X N/A command_line_5;command_line_7\n" + "\n" + "[fake description 2]\n" + "Interface Transport Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n" + "a.h.foo5@5.0::IFoo/5 passthrough N/A 32 N/A ? X N/A command_line_6;command_line_8\n" + "a.h.foo6@6.0::IFoo/6 passthrough N/A 32 N/A ? X N/A command_line_7;command_line_9\n" + "\n"; + // clang-format on + + optind = 1; // mimic Lshal::parseArg() + EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Am"}))); + EXPECT_EQ(expected, out.str()); + EXPECT_EQ("", err.str()); +} + +TEST_F(ListTest, AllSections) { + optind = 1; // mimic Lshal::parseArg() + EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=all"}))); + using HalTypeBase = std::underlying_type_t; + for (HalTypeBase i = 0; i < static_cast(HalType::LAST); ++i) { + EXPECT_THAT(out.str(), HasSubstr("[fake description " + std::to_string(i) + "]")); + } + EXPECT_THAT(out.str(), + Not(HasSubstr("[fake description " + + std::to_string(static_cast(HalType::LAST)) + "]"))); + EXPECT_EQ("", err.str()); +} + // Fake service returned by mocked IServiceManager::get for DumpDebug. // The interfaceChain and getHashChain functions returns // foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.