123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892 |
- /*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #define LOG_TAG "Lshal"
- #include <android-base/logging.h>
- #include <sstream>
- #include <string>
- #include <thread>
- #include <vector>
- #include <gtest/gtest.h>
- #include <gmock/gmock.h>
- #include <android/hardware/tests/baz/1.0/IQuux.h>
- #include <hidl/HidlTransportSupport.h>
- #include <vintf/parse_xml.h>
- #include "ListCommand.h"
- #include "Lshal.h"
- #define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
- using namespace testing;
- 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;
- 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;
- using hidl_hash = hidl_array<uint8_t, 32>;
- namespace android {
- namespace hardware {
- namespace tests {
- namespace baz {
- namespace V1_0 {
- namespace implementation {
- struct Quux : android::hardware::tests::baz::V1_0::IQuux {
- ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
- const native_handle_t *handle = hh.getNativeHandle();
- if (handle->numFds < 1) {
- return Void();
- }
- int fd = handle->data[0];
- std::string content{descriptor};
- for (const auto &option : options) {
- content += "\n";
- content += option.c_str();
- }
- ssize_t written = write(fd, content.c_str(), content.size());
- if (written != (ssize_t)content.size()) {
- LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
- << content.size() << " bytes, errno = " << errno;
- }
- return Void();
- }
- };
- } // namespace implementation
- } // namespace V1_0
- } // namespace baz
- } // namespace tests
- } // namespace hardware
- namespace lshal {
- class MockServiceManager : public IServiceManager {
- public:
- template<typename T>
- using R = ::android::hardware::Return<T>;
- using String = const hidl_string&;
- ~MockServiceManager() = default;
- #define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
- MOCK_METHOD2(get, R<sp<IBase>>(String, String));
- MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
- MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
- MOCK_METHOD_CB(list);
- MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
- MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
- MOCK_METHOD_CB(debugDump);
- MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
- MOCK_METHOD_CB(interfaceChain);
- MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
- MOCK_METHOD_CB(interfaceDescriptor);
- MOCK_METHOD_CB(getHashChain);
- MOCK_METHOD0(setHalInstrumentation, R<void>());
- MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
- MOCK_METHOD0(ping, R<void>());
- MOCK_METHOD_CB(getDebugInfo);
- MOCK_METHOD0(notifySyspropsChanged, R<void>());
- MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
- };
- class DebugTest : public ::testing::Test {
- public:
- void SetUp() override {
- using ::android::hardware::tests::baz::V1_0::IQuux;
- using ::android::hardware::tests::baz::V1_0::implementation::Quux;
- err.str("");
- out.str("");
- serviceManager = new testing::NiceMock<MockServiceManager>();
- ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
- [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
- if (iface == IQuux::descriptor && inst == "default")
- return new Quux();
- return nullptr;
- }));
- lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
- }
- void TearDown() override {}
- std::stringstream err;
- std::stringstream out;
- sp<MockServiceManager> serviceManager;
- std::unique_ptr<Lshal> lshal;
- };
- static Arg createArg(const std::vector<const char*>& args) {
- return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
- }
- template<typename T>
- static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
- return lshal->main(createArg(args));
- }
- TEST_F(DebugTest, Debug) {
- EXPECT_EQ(0u, callMain(lshal, {
- "lshal", "debug", "[email protected]::IQuux/default", "foo", "bar"
- }));
- EXPECT_THAT(out.str(), StrEq("[email protected]::IQuux\nfoo\nbar"));
- EXPECT_THAT(err.str(), IsEmpty());
- }
- TEST_F(DebugTest, Debug2) {
- EXPECT_EQ(0u, callMain(lshal, {
- "lshal", "debug", "[email protected]::IQuux", "baz", "quux"
- }));
- EXPECT_THAT(out.str(), StrEq("[email protected]::IQuux\nbaz\nquux"));
- EXPECT_THAT(err.str(), IsEmpty());
- }
- TEST_F(DebugTest, Debug3) {
- EXPECT_NE(0u, callMain(lshal, {
- "lshal", "debug", "[email protected]::IDoesNotExist",
- }));
- EXPECT_THAT(err.str(), HasSubstr("does not exist"));
- }
- class MockLshal : public Lshal {
- public:
- MockLshal() {}
- ~MockLshal() = default;
- MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
- MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
- };
- // expose protected fields and methods for ListCommand
- class MockListCommand : public ListCommand {
- public:
- explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
- Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
- Status main(const Arg& arg) { return ListCommand::main(arg); }
- void forEachTable(const std::function<void(Table &)> &f) {
- return ListCommand::forEachTable(f);
- }
- void forEachTable(const std::function<void(const Table &)> &f) const {
- return ListCommand::forEachTable(f);
- }
- Status fetch() { return ListCommand::fetch(); }
- void dumpVintf(const NullableOStream<std::ostream>& out) {
- return ListCommand::dumpVintf(out);
- }
- void internalPostprocess() { ListCommand::postprocess(); }
- const PidInfo* getPidInfoCached(pid_t serverPid) {
- return ListCommand::getPidInfoCached(serverPid);
- }
- MOCK_METHOD0(postprocess, void());
- 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 {
- public:
- void SetUp() override {
- mockLshal = std::make_unique<NiceMock<MockLshal>>();
- mockList = std::make_unique<MockListCommand>(mockLshal.get());
- ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
- // ListCommand::parseArgs should parse arguments from the second element
- optind = 1;
- }
- std::unique_ptr<MockLshal> mockLshal;
- std::unique_ptr<MockListCommand> mockList;
- std::stringstream err;
- };
- TEST_F(ListParseArgsTest, Args) {
- EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
- mockList->forEachTable([](const Table& table) {
- EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
- TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
- table.getSelectedColumns());
- });
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListParseArgsTest, Cmds) {
- EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
- mockList->forEachTable([](const Table& table) {
- EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
- << "should not print server PID with -m";
- EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
- << "should not print client PIDs with -m";
- EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
- << "should print server cmd with -m";
- EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
- << "should print client cmds with -m";
- });
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListParseArgsTest, DebugAndNeat) {
- EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
- EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
- }
- /// Fetch Test
- // A set of deterministic functions to generate fake debug infos.
- static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
- static std::vector<pid_t> getClients(pid_t serverId) {
- return {serverId + 1, serverId + 3};
- }
- static PidInfo getPidInfoFromId(pid_t serverId) {
- PidInfo info;
- info.refPids[getPtr(serverId)] = getClients(serverId);
- info.threadUsage = 10 + serverId;
- info.threadCount = 20 + serverId;
- return info;
- }
- static std::string getInterfaceName(pid_t serverId) {
- return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
- }
- static std::string getInstanceName(pid_t serverId) {
- return std::to_string(serverId);
- }
- static pid_t getIdFromInstanceName(const hidl_string& instance) {
- return atoi(instance.c_str());
- }
- static std::string getFqInstanceName(pid_t serverId) {
- return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
- }
- 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:
- explicit TestService(pid_t id) : mId(id) {}
- hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
- 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:
- pid_t mId;
- };
- class ListTest : public ::testing::Test {
- public:
- virtual void SetUp() override {
- initMockServiceManager();
- lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
- initMockList();
- }
- void initMockList() {
- mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
- ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
- [](pid_t serverPid, PidInfo* info) {
- *info = getPidInfoFromId(serverPid);
- return true;
- }));
- ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
- ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
- mockList->internalPostprocess();
- size_t i = 0;
- mockList->forEachTable([&](Table& table) {
- table.setDescription("[fake description " + std::to_string(i++) + "]");
- });
- }));
- ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
- ON_CALL(*mockList, getDeviceManifest())
- .WillByDefault(Return(std::make_shared<HalManifest>()));
- ON_CALL(*mockList, getDeviceMatrix())
- .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
- ON_CALL(*mockList, getFrameworkManifest())
- .WillByDefault(Return(std::make_shared<HalManifest>()));
- ON_CALL(*mockList, getFrameworkMatrix())
- .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
- }
- void initMockServiceManager() {
- serviceManager = new testing::NiceMock<MockServiceManager>();
- passthruManager = new testing::NiceMock<MockServiceManager>();
- using A = DebugInfo::Architecture;
- ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
- [] (IServiceManager::list_cb cb) {
- cb({ getFqInstanceName(1), getFqInstanceName(2) });
- return hardware::Void();
- }));
- ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
- [&](const hidl_string&, const hidl_string& instance) {
- int id = getIdFromInstanceName(instance);
- return sp<IBase>(new TestService(id));
- }));
- ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
- [] (IServiceManager::debugDump_cb cb) {
- cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
- getClients(3), A::IS_32BIT},
- InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
- getClients(4), A::IS_32BIT}});
- return hardware::Void();
- }));
- ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
- [] (IServiceManager::debugDump_cb cb) {
- cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
- getClients(5), A::IS_32BIT},
- InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
- getClients(6), A::IS_32BIT}});
- return hardware::Void();
- }));
- }
- std::stringstream err;
- std::stringstream out;
- std::unique_ptr<Lshal> lshal;
- std::unique_ptr<MockListCommand> mockList;
- sp<MockServiceManager> serviceManager;
- sp<MockServiceManager> passthruManager;
- };
- TEST_F(ListTest, GetPidInfoCached) {
- EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
- EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
- EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
- }
- TEST_F(ListTest, Fetch) {
- optind = 1; // mimic Lshal::parseArg()
- ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
- ASSERT_EQ(0u, mockList->fetch());
- 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 i = 0;
- mockList->forEachTable([&](const Table& table) {
- for (const auto& entry : table) {
- if (i >= transportArchs.size()) {
- break;
- }
- int id = i + 1;
- auto transport = transportArchs.at(i).transport;
- TableEntry expected{
- .interfaceName = getFqInstanceName(id),
- .transport = transport,
- .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 == Transport::HWBINDER ? getPtr(id) : NO_PTR,
- .clientPids = getClients(id),
- .clientCmdlines = {},
- .arch = transportArchs.at(i).arch,
- };
- EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
- ++i;
- }
- });
- EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
- }
- TEST_F(ListTest, DumpVintf) {
- const std::string expected = "<manifest version=\"1.0\" type=\"device\">\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.foo1</name>\n"
- " <transport>hwbinder</transport>\n"
- " <fqname>@1.0::IFoo/1</fqname>\n"
- " </hal>\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.foo2</name>\n"
- " <transport>hwbinder</transport>\n"
- " <fqname>@2.0::IFoo/2</fqname>\n"
- " </hal>\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.foo3</name>\n"
- " <transport arch=\"32\">passthrough</transport>\n"
- " <fqname>@3.0::IFoo/3</fqname>\n"
- " </hal>\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.foo4</name>\n"
- " <transport arch=\"32\">passthrough</transport>\n"
- " <fqname>@4.0::IFoo/4</fqname>\n"
- " </hal>\n"
- "</manifest>";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
- auto output = out.str();
- EXPECT_THAT(output, HasSubstr(expected));
- EXPECT_THAT(output, HasSubstr("[email protected]::IFoo/5"));
- EXPECT_THAT(output, HasSubstr("[email protected]::IFoo/6"));
- EXPECT_EQ("", err.str());
- vintf::HalManifest m;
- EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
- << "--init-vintf does not emit valid HAL manifest: "
- << 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"
- "N [email protected]::IFoo/1 11/21 1 2 4\n"
- "Y [email protected]::IFoo/2 12/22 2 3 5\n"
- "\n"
- "[fake description 1]\n"
- "R Interface Thread Use Server Clients\n"
- "? [email protected]::IFoo/3 N/A N/A 4 6\n"
- "? [email protected]::IFoo/4 N/A N/A 5 7\n"
- "\n"
- "[fake description 2]\n"
- "R Interface Thread Use Server Clients\n"
- "? [email protected]::IFoo/5 N/A N/A 6 8\n"
- "? [email protected]::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"
- "[email protected]::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
- "[email protected]::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
- "\n"
- "[fake description 1]\n"
- "Interface R Hash\n"
- "[email protected]::IFoo/3 ? \n"
- "[email protected]::IFoo/4 ? \n"
- "\n"
- "[fake description 2]\n"
- "Interface R Hash\n"
- "[email protected]::IFoo/5 ? \n"
- "[email protected]::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"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
- "[email protected]::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
- "\n"
- "[fake description 1]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
- "[email protected]::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
- "\n"
- "[fake description 2]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
- "[email protected]::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
- "\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListTest, DumpCmdline) {
- const std::string expected =
- "[fake description 0]\n"
- "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
- "[email protected]::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
- "[email protected]::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
- "\n"
- "[fake description 1]\n"
- "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
- "[email protected]::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
- "[email protected]::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
- "\n"
- "[fake description 2]\n"
- "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
- "[email protected]::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
- "[email protected]::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
- "\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListTest, DumpNeat) {
- const std::string expected =
- "[email protected]::IFoo/1 11/21 1 2 4\n"
- "[email protected]::IFoo/2 12/22 2 3 5\n"
- "[email protected]::IFoo/3 N/A N/A 4 6\n"
- "[email protected]::IFoo/4 N/A N/A 5 7\n"
- "[email protected]::IFoo/5 N/A N/A 6 8\n"
- "[email protected]::IFoo/6 N/A N/A 7 9\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListTest, DumpSingleHalType) {
- const std::string expected =
- "[fake description 0]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
- "[email protected]::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
- "\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListTest, DumpReorderedHalTypes) {
- const std::string expected =
- "[fake description 0]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
- "[email protected]::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
- "\n"
- "[fake description 1]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
- "[email protected]::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
- "\n"
- "[fake description 2]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
- "[email protected]::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
- "\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
- "--types=passthrough_libs", "--types=binderized"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListTest, DumpAbbreviatedHalTypes) {
- const std::string expected =
- "[fake description 0]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
- "[email protected]::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
- "\n"
- "[fake description 1]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
- "[email protected]::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
- "\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
- const std::string expected =
- "[fake description 0]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
- "[email protected]::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
- "\n"
- "[fake description 1]\n"
- "Interface Transport Arch Thread Use Server PTR Clients\n"
- "[email protected]::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
- "[email protected]::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
- "\n";
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
- "--types=passthrough_libs,passthrough_clients"})));
- EXPECT_EQ(expected, out.str());
- EXPECT_EQ("", err.str());
- }
- 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"));
- }
- 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 [email protected]::IFoo/1\n"
- "X [email protected]::IFoo/2\n"
- "DM,FC [email protected]::IFoo/3\n"
- "X [email protected]::IFoo/4\n"
- "DC,FM [email protected]::IFoo/5\n"
- "X [email protected]::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 ListVintfTest : public ListTest {
- public:
- virtual void SetUp() override {
- ListTest::SetUp();
- const std::string mockManifestXml =
- "<manifest version=\"1.0\" type=\"device\">\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.foo1</name>\n"
- " <transport>hwbinder</transport>\n"
- " <fqname>@1.0::IFoo/1</fqname>\n"
- " </hal>\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.bar1</name>\n"
- " <transport>hwbinder</transport>\n"
- " <fqname>@1.0::IBar/1</fqname>\n"
- " </hal>\n"
- " <hal format=\"hidl\">\n"
- " <name>a.h.bar2</name>\n"
- " <transport arch=\"32+64\">passthrough</transport>\n"
- " <fqname>@2.0::IBar/2</fqname>\n"
- " </hal>\n"
- "</manifest>";
- auto manifest = std::make_shared<HalManifest>();
- EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
- EXPECT_CALL(*mockList, getDeviceManifest())
- .Times(AnyNumber())
- .WillRepeatedly(Return(manifest));
- }
- };
- TEST_F(ListVintfTest, ManifestHals) {
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
- EXPECT_THAT(out.str(), HasSubstr("[email protected]::IBar/1 declared hwbinder ?"));
- EXPECT_THAT(out.str(), HasSubstr("[email protected]::IBar/2 declared passthrough 32+64"));
- EXPECT_THAT(out.str(), HasSubstr("[email protected]::IFoo/1 declared hwbinder ?"));
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListVintfTest, Lazy) {
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
- EXPECT_THAT(out.str(), HasSubstr("[email protected]::IBar/1 declared hwbinder ?"));
- EXPECT_THAT(out.str(), HasSubstr("[email protected]::IBar/2 declared passthrough 32+64"));
- EXPECT_EQ("", err.str());
- }
- TEST_F(ListVintfTest, NoLazy) {
- optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
- EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
- EXPECT_EQ("", err.str());
- }
- class HelpTest : public ::testing::Test {
- public:
- void SetUp() override {
- lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
- new MockServiceManager() /* passthruManager */);
- }
- std::stringstream err;
- std::stringstream out;
- std::unique_ptr<Lshal> lshal;
- };
- TEST_F(HelpTest, GlobalUsage) {
- (void)callMain(lshal, {"lshal", "--help"}); // ignore return
- std::string errStr = err.str();
- EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
- << "`lshal --help` does not contain global usage";
- EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
- << "`lshal --help` does not contain usage for 'list' command";
- EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
- << "`lshal --help` does not contain usage for 'debug' command";
- EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
- << "`lshal --help` does not contain usage for 'help' command";
- err.str("");
- (void)callMain(lshal, {"lshal", "help"}); // ignore return
- EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
- err.str("");
- EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
- EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
- EXPECT_THAT(err.str(), EndsWith(errStr))
- << "`lshal --unknown-option` should have the same output as `lshal --help`";
- EXPECT_EQ("", out.str());
- }
- TEST_F(HelpTest, UnknownOptionList1) {
- (void)callMain(lshal, {"lshal", "help", "list"});
- EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
- << "`lshal help list` does not contain usage for 'list' command";
- }
- TEST_F(HelpTest, UnknownOptionList2) {
- EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
- EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
- EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
- << "`lshal list --unknown-option` does not contain usage for 'list' command";
- EXPECT_EQ("", out.str());
- }
- TEST_F(HelpTest, UnknownOptionHelp1) {
- (void)callMain(lshal, {"lshal", "help", "help"});
- EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
- << "`lshal help help` does not contain usage for 'help' command";
- }
- TEST_F(HelpTest, UnknownOptionHelp2) {
- (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
- EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
- << "`lshal help --unknown-option` does not contain usage for 'help' command";
- EXPECT_EQ("", out.str());
- }
- } // namespace lshal
- } // namespace android
- int main(int argc, char **argv) {
- ::testing::InitGoogleMock(&argc, argv);
- return RUN_ALL_TESTS();
- }
|