1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "Lshal"
18 #include <android-base/logging.h>
19 
20 #include <sstream>
21 #include <string>
22 #include <thread>
23 #include <vector>
24 
25 #include <gtest/gtest.h>
26 #include <gmock/gmock.h>
27 #include <android/hardware/tests/inheritance/1.0/IChild.h>
28 #include <hidl/HidlTransportSupport.h>
29 #include <vintf/parse_xml.h>
30 
31 #include "ListCommand.h"
32 #include "Lshal.h"
33 
34 #define NELEMS(array)   static_cast<int>(sizeof(array) / sizeof(array[0]))
35 
36 using namespace testing;
37 
38 using ::android::hidl::base::V1_0::DebugInfo;
39 using ::android::hidl::base::V1_0::IBase;
40 using ::android::hidl::manager::V1_0::IServiceManager;
41 using ::android::hidl::manager::V1_0::IServiceNotification;
42 using ::android::hardware::hidl_array;
43 using ::android::hardware::hidl_death_recipient;
44 using ::android::hardware::hidl_handle;
45 using ::android::hardware::hidl_string;
46 using ::android::hardware::hidl_vec;
47 using ::android::hardware::Void;
48 using android::vintf::Arch;
49 using android::vintf::CompatibilityMatrix;
50 using android::vintf::HalManifest;
51 using android::vintf::Transport;
52 using android::vintf::VintfObject;
53 
54 using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
55 
56 using hidl_hash = hidl_array<uint8_t, 32>;
57 
58 namespace android {
59 namespace hardware {
60 namespace tests {
61 namespace inheritance {
62 namespace V1_0 {
63 namespace implementation {
64 struct Child : android::hardware::tests::inheritance::V1_0::IChild {
doChildandroid::hardware::tests::inheritance::V1_0::implementation::Child65     ::android::hardware::Return<void> doChild() override { return Void(); }
doParentandroid::hardware::tests::inheritance::V1_0::implementation::Child66     ::android::hardware::Return<void> doParent() override { return Void(); }
doGrandparentandroid::hardware::tests::inheritance::V1_0::implementation::Child67     ::android::hardware::Return<void> doGrandparent() override { return Void(); }
68 
debugandroid::hardware::tests::inheritance::V1_0::implementation::Child69     ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
70         const native_handle_t *handle = hh.getNativeHandle();
71         if (handle->numFds < 1) {
72             return Void();
73         }
74         int fd = handle->data[0];
75         std::string content{descriptor};
76         for (const auto &option : options) {
77             content += "\n";
78             content += option.c_str();
79         }
80         ssize_t written = write(fd, content.c_str(), content.size());
81         if (written != (ssize_t)content.size()) {
82             LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
83                     << content.size() << " bytes, errno = " << errno;
84         }
85         return Void();
86     }
87 };
88 
89 } // namespace implementation
90 } // namespace V1_0
91 } // namespace inheritance
92 } // namespace tests
93 } // namespace hardware
94 
95 namespace lshal {
96 
97 class MockServiceManager : public IServiceManager {
98 public:
99     template<typename T>
100     using R = ::android::hardware::Return<T>;
101     using String = const hidl_string&;
102     ~MockServiceManager() = default;
103 
104 #define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
105 
106     MOCK_METHOD2(get, R<sp<IBase>>(String, String));
107     MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
108     MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
109     MOCK_METHOD_CB(list);
110     MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
111     MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
112     MOCK_METHOD_CB(debugDump);
113     MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
114     MOCK_METHOD_CB(interfaceChain);
115     MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
116     MOCK_METHOD_CB(interfaceDescriptor);
117     MOCK_METHOD_CB(getHashChain);
118     MOCK_METHOD0(setHalInstrumentation, R<void>());
119     MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
120     MOCK_METHOD0(ping, R<void>());
121     MOCK_METHOD_CB(getDebugInfo);
122     MOCK_METHOD0(notifySyspropsChanged, R<void>());
123     MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
124 
125 };
126 
127 class DebugTest : public ::testing::Test {
128 public:
SetUp()129     void SetUp() override {
130         using ::android::hardware::tests::inheritance::V1_0::IChild;
131         using ::android::hardware::tests::inheritance::V1_0::IParent;
132         using ::android::hardware::tests::inheritance::V1_0::IGrandparent;
133         using ::android::hardware::tests::inheritance::V1_0::implementation::Child;
134 
135         err.str("");
136         out.str("");
137         serviceManager = new testing::NiceMock<MockServiceManager>();
138         ON_CALL(*serviceManager, get(_, _))
139                 .WillByDefault(
140                         Invoke([](const auto& iface,
141                                   const auto& inst) -> ::android::hardware::Return<sp<IBase>> {
142                             if (inst != "default") return nullptr;
143                             if (iface == IChild::descriptor || iface == IParent::descriptor ||
144                                 iface == IGrandparent::descriptor)
145                                 return new Child();
146                             return nullptr;
147                         }));
148 
149         lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
150     }
TearDown()151     void TearDown() override {}
152 
153     std::stringstream err;
154     std::stringstream out;
155     sp<MockServiceManager> serviceManager;
156 
157     std::unique_ptr<Lshal> lshal;
158 };
159 
createArg(const std::vector<const char * > & args)160 static Arg createArg(const std::vector<const char*>& args) {
161     return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
162 }
163 
164 template<typename T>
callMain(const std::unique_ptr<T> & lshal,const std::vector<const char * > & args)165 static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
166     return lshal->main(createArg(args));
167 }
168 
TEST_F(DebugTest,Debug)169 TEST_F(DebugTest, Debug) {
170     EXPECT_EQ(0u, callMain(lshal, {
171         "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "foo", "bar"
172     }));
173     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nfoo\nbar"));
174     EXPECT_THAT(err.str(), IsEmpty());
175 }
176 
TEST_F(DebugTest,Debug2)177 TEST_F(DebugTest, Debug2) {
178     EXPECT_EQ(0u, callMain(lshal, {
179         "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild", "baz", "quux"
180     }));
181     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nbaz\nquux"));
182     EXPECT_THAT(err.str(), IsEmpty());
183 }
184 
TEST_F(DebugTest,Debug3)185 TEST_F(DebugTest, Debug3) {
186     EXPECT_NE(0u, callMain(lshal, {
187         "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
188     }));
189     EXPECT_THAT(err.str(), HasSubstr("does not exist"));
190 }
191 
TEST_F(DebugTest,DebugParent)192 TEST_F(DebugTest, DebugParent) {
193     EXPECT_EQ(0u, callMain(lshal, {
194         "lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
195     }));
196     EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\ncalling parent"));
197     EXPECT_THAT(err.str(), IsEmpty());
198 }
199 
TEST_F(DebugTest,DebugParentExclude)200 TEST_F(DebugTest, DebugParentExclude) {
201     EXPECT_EQ(0u, callMain(lshal, {
202         "lshal", "debug", "-E", "android.hardware.tests.inheritance@1.0::IParent", "excluding"
203     }));
204     EXPECT_THAT(out.str(), IsEmpty());
205     EXPECT_THAT(err.str(), IsEmpty());
206 }
207 
208 class MockLshal : public Lshal {
209 public:
MockLshal()210     MockLshal() {}
211     ~MockLshal() = default;
212     MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
213     MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
214 };
215 
216 // expose protected fields and methods for ListCommand
217 class MockListCommand : public ListCommand {
218 public:
MockListCommand(Lshal * lshal)219     explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
220 
parseArgs(const Arg & arg)221     Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
main(const Arg & arg)222     Status main(const Arg& arg) { return ListCommand::main(arg); }
forEachTable(const std::function<void (Table &)> & f)223     void forEachTable(const std::function<void(Table &)> &f) {
224         return ListCommand::forEachTable(f);
225     }
forEachTable(const std::function<void (const Table &)> & f) const226     void forEachTable(const std::function<void(const Table &)> &f) const {
227         return ListCommand::forEachTable(f);
228     }
fetch()229     Status fetch() { return ListCommand::fetch(); }
dumpVintf(const NullableOStream<std::ostream> & out)230     void dumpVintf(const NullableOStream<std::ostream>& out) {
231         return ListCommand::dumpVintf(out);
232     }
internalPostprocess()233     void internalPostprocess() { ListCommand::postprocess(); }
getPidInfoCached(pid_t serverPid)234     const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
235         return ListCommand::getPidInfoCached(serverPid);
236     }
237 
238     MOCK_METHOD0(postprocess, void());
239     MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
240     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
241     MOCK_METHOD1(getPartition, Partition(pid_t));
242 
243     MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
244     MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
245     MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
246     MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
247 };
248 
249 class ListParseArgsTest : public ::testing::Test {
250 public:
SetUp()251     void SetUp() override {
252         mockLshal = std::make_unique<NiceMock<MockLshal>>();
253         mockList = std::make_unique<MockListCommand>(mockLshal.get());
254         ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
255         // ListCommand::parseArgs should parse arguments from the second element
256         optind = 1;
257     }
258     std::unique_ptr<MockLshal> mockLshal;
259     std::unique_ptr<MockListCommand> mockList;
260     std::stringstream err;
261 };
262 
TEST_F(ListParseArgsTest,Args)263 TEST_F(ListParseArgsTest, Args) {
264     EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
265     mockList->forEachTable([](const Table& table) {
266         EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
267                                    TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
268                   table.getSelectedColumns());
269     });
270     EXPECT_EQ("", err.str());
271 }
272 
TEST_F(ListParseArgsTest,Cmds)273 TEST_F(ListParseArgsTest, Cmds) {
274     EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
275     mockList->forEachTable([](const Table& table) {
276         EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
277                 << "should not print server PID with -m";
278         EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
279                 << "should not print client PIDs with -m";
280         EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
281                 << "should print server cmd with -m";
282         EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
283                 << "should print client cmds with -m";
284     });
285     EXPECT_EQ("", err.str());
286 }
287 
TEST_F(ListParseArgsTest,DebugAndNeat)288 TEST_F(ListParseArgsTest, DebugAndNeat) {
289     EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
290     EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
291 }
292 
293 /// Fetch Test
294 
295 // A set of deterministic functions to generate fake debug infos.
getPtr(pid_t serverId)296 static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
getClients(pid_t serverId)297 static std::vector<pid_t> getClients(pid_t serverId) {
298     return {serverId + 1, serverId + 3};
299 }
getPidInfoFromId(pid_t serverId)300 static BinderPidInfo getPidInfoFromId(pid_t serverId) {
301     BinderPidInfo info;
302     info.refPids[getPtr(serverId)] = getClients(serverId);
303     info.threadUsage = 10 + serverId;
304     info.threadCount = 20 + serverId;
305     return info;
306 }
getInterfaceName(pid_t serverId)307 static std::string getInterfaceName(pid_t serverId) {
308     return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
309 }
getInstanceName(pid_t serverId)310 static std::string getInstanceName(pid_t serverId) {
311     return std::to_string(serverId);
312 }
getIdFromInstanceName(const hidl_string & instance)313 static pid_t getIdFromInstanceName(const hidl_string& instance) {
314     return atoi(instance.c_str());
315 }
getFqInstanceName(pid_t serverId)316 static std::string getFqInstanceName(pid_t serverId) {
317     return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
318 }
getCmdlineFromId(pid_t serverId)319 static std::string getCmdlineFromId(pid_t serverId) {
320     if (serverId == NO_PID) return "";
321     return "command_line_" + std::to_string(serverId);
322 }
getIsReleasedFromId(pid_t p)323 static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
getHashFromId(pid_t serverId)324 static hidl_hash getHashFromId(pid_t serverId) {
325     hidl_hash hash;
326     bool isReleased = getIsReleasedFromId(serverId);
327     for (size_t i = 0; i < hash.size(); ++i) {
328         hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
329     }
330     return hash;
331 }
332 
333 // Fake service returned by mocked IServiceManager::get.
334 class TestService : public IBase {
335 public:
TestService(pid_t id)336     explicit TestService(pid_t id) : mId(id) {}
getDebugInfo(getDebugInfo_cb cb)337     hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
338         cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
339         return hardware::Void();
340     }
interfaceChain(interfaceChain_cb cb)341     hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
342         cb({getInterfaceName(mId), IBase::descriptor});
343         return hardware::Void();
344     }
getHashChain(getHashChain_cb cb)345     hardware::Return<void> getHashChain(getHashChain_cb cb) override {
346         cb({getHashFromId(mId), getHashFromId(0xff)});
347         return hardware::Void();
348     }
349 private:
350     pid_t mId;
351 };
352 
353 class ListTest : public ::testing::Test {
354 public:
SetUp()355     virtual void SetUp() override {
356         initMockServiceManager();
357         lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
358         initMockList();
359     }
360 
initMockList()361     void initMockList() {
362         mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
363         ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
364             [](pid_t serverPid, BinderPidInfo* info) {
365                 *info = getPidInfoFromId(serverPid);
366                 return true;
367             }));
368         ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
369         ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
370             mockList->internalPostprocess();
371             size_t i = 0;
372             mockList->forEachTable([&](Table& table) {
373                 table.setDescription("[fake description " + std::to_string(i++) + "]");
374             });
375         }));
376         ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
377 
378         ON_CALL(*mockList, getDeviceManifest())
379                 .WillByDefault(Return(std::make_shared<HalManifest>()));
380         ON_CALL(*mockList, getDeviceMatrix())
381                 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
382         ON_CALL(*mockList, getFrameworkManifest())
383                 .WillByDefault(Return(std::make_shared<HalManifest>()));
384         ON_CALL(*mockList, getFrameworkMatrix())
385                 .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
386     }
387 
initMockServiceManager()388     void initMockServiceManager() {
389         serviceManager = new testing::NiceMock<MockServiceManager>();
390         passthruManager = new testing::NiceMock<MockServiceManager>();
391         using A = DebugInfo::Architecture;
392         ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
393             [] (IServiceManager::list_cb cb) {
394                 cb({ getFqInstanceName(1), getFqInstanceName(2) });
395                 return hardware::Void();
396             }));
397 
398         ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
399             [&](const hidl_string&, const hidl_string& instance) {
400                 int id = getIdFromInstanceName(instance);
401                 return sp<IBase>(new TestService(id));
402             }));
403 
404         ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
405             [] (IServiceManager::debugDump_cb cb) {
406                 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
407                                       getClients(3), A::IS_32BIT},
408                     InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
409                                       getClients(4), A::IS_32BIT}});
410                 return hardware::Void();
411             }));
412 
413         ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
414             [] (IServiceManager::debugDump_cb cb) {
415                 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
416                                       getClients(5), A::IS_32BIT},
417                     InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
418                                       getClients(6), A::IS_32BIT}});
419                 return hardware::Void();
420             }));
421     }
422 
423     std::stringstream err;
424     std::stringstream out;
425     std::unique_ptr<Lshal> lshal;
426     std::unique_ptr<MockListCommand> mockList;
427     sp<MockServiceManager> serviceManager;
428     sp<MockServiceManager> passthruManager;
429 };
430 
TEST_F(ListTest,GetPidInfoCached)431 TEST_F(ListTest, GetPidInfoCached) {
432     EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
433 
434     EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
435     EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
436 }
437 
TEST_F(ListTest,Fetch)438 TEST_F(ListTest, Fetch) {
439     optind = 1; // mimic Lshal::parseArg()
440     ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
441     ASSERT_EQ(0u, mockList->fetch());
442     vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
443     vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
444     std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
445                                                         passthrough, passthrough, passthrough}};
446     int i = 0;
447     mockList->forEachTable([&](const Table& table) {
448         for (const auto& entry : table) {
449             if (i >= transportArchs.size()) {
450                 break;
451             }
452 
453             int id = i + 1;
454             auto transport = transportArchs.at(i).transport;
455             TableEntry expected{
456                 .interfaceName = getFqInstanceName(id),
457                 .transport = transport,
458                 .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
459                 .threadUsage =
460                         transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
461                 .threadCount =
462                         transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
463                 .serverCmdline = {},
464                 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
465                 .clientPids = getClients(id),
466                 .clientCmdlines = {},
467                 .arch = transportArchs.at(i).arch,
468             };
469             EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
470 
471             ++i;
472         }
473     });
474 
475     EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
476 
477 }
478 
TEST_F(ListTest,DumpVintf)479 TEST_F(ListTest, DumpVintf) {
480     const std::string expected = "    <hal format=\"hidl\">\n"
481                                  "        <name>a.h.foo1</name>\n"
482                                  "        <transport>hwbinder</transport>\n"
483                                  "        <fqname>@1.0::IFoo/1</fqname>\n"
484                                  "    </hal>\n"
485                                  "    <hal format=\"hidl\">\n"
486                                  "        <name>a.h.foo2</name>\n"
487                                  "        <transport>hwbinder</transport>\n"
488                                  "        <fqname>@2.0::IFoo/2</fqname>\n"
489                                  "    </hal>\n"
490                                  "    <hal format=\"hidl\">\n"
491                                  "        <name>a.h.foo3</name>\n"
492                                  "        <transport arch=\"32\">passthrough</transport>\n"
493                                  "        <fqname>@3.0::IFoo/3</fqname>\n"
494                                  "    </hal>\n"
495                                  "    <hal format=\"hidl\">\n"
496                                  "        <name>a.h.foo4</name>\n"
497                                  "        <transport arch=\"32\">passthrough</transport>\n"
498                                  "        <fqname>@4.0::IFoo/4</fqname>\n"
499                                  "    </hal>\n";
500 
501     optind = 1; // mimic Lshal::parseArg()
502     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
503     auto output = out.str();
504     EXPECT_THAT(output, HasSubstr(expected));
505     EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
506     EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
507     EXPECT_EQ("", err.str());
508 
509     std::string error;
510     vintf::HalManifest m;
511     EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error))
512         << "--init-vintf does not emit valid HAL manifest: " << error;
513 }
514 
515 // test default columns
TEST_F(ListTest,DumpDefault)516 TEST_F(ListTest, DumpDefault) {
517     const std::string expected =
518         "[fake description 0]\n"
519         "VINTF R Interface            Thread Use Server Clients\n"
520         "X     N a.h.foo1@1.0::IFoo/1 11/21      1      2 4\n"
521         "X     Y a.h.foo2@2.0::IFoo/2 12/22      2      3 5\n"
522         "\n"
523         "[fake description 1]\n"
524         "VINTF R Interface            Thread Use Server Clients\n"
525         "X     ? a.h.foo3@3.0::IFoo/3 N/A        N/A    4 6\n"
526         "X     ? a.h.foo4@4.0::IFoo/4 N/A        N/A    5 7\n"
527         "\n"
528         "[fake description 2]\n"
529         "VINTF R Interface            Thread Use Server Clients\n"
530         "X     ? a.h.foo5@5.0::IFoo/5 N/A        N/A    6 8\n"
531         "X     ? a.h.foo6@6.0::IFoo/6 N/A        N/A    7 9\n"
532         "\n";
533 
534     optind = 1; // mimic Lshal::parseArg()
535     EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
536     EXPECT_EQ(expected, out.str());
537     EXPECT_EQ("", err.str());
538 }
539 
TEST_F(ListTest,DumpHash)540 TEST_F(ListTest, DumpHash) {
541     const std::string expected =
542         "[fake description 0]\n"
543         "Interface            R Hash\n"
544         "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
545         "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
546         "\n"
547         "[fake description 1]\n"
548         "Interface            R Hash\n"
549         "a.h.foo3@3.0::IFoo/3 ? \n"
550         "a.h.foo4@4.0::IFoo/4 ? \n"
551         "\n"
552         "[fake description 2]\n"
553         "Interface            R Hash\n"
554         "a.h.foo5@5.0::IFoo/5 ? \n"
555         "a.h.foo6@6.0::IFoo/6 ? \n"
556         "\n";
557 
558     optind = 1; // mimic Lshal::parseArg()
559     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
560     EXPECT_EQ(expected, out.str());
561     EXPECT_EQ("", err.str());
562 }
563 
TEST_F(ListTest,Dump)564 TEST_F(ListTest, Dump) {
565     const std::string expected =
566         "[fake description 0]\n"
567         "Interface            Transport Arch Thread Use Server PTR              Clients\n"
568         "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
569         "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
570         "\n"
571         "[fake description 1]\n"
572         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
573         "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
574         "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
575         "\n"
576         "[fake description 2]\n"
577         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
578         "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
579         "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
580         "\n";
581 
582     optind = 1; // mimic Lshal::parseArg()
583     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
584     EXPECT_EQ(expected, out.str());
585     EXPECT_EQ("", err.str());
586 }
587 
TEST_F(ListTest,DumpCmdline)588 TEST_F(ListTest, DumpCmdline) {
589     const std::string expected =
590         "[fake description 0]\n"
591         "Interface            Transport Arch Thread Use Server CMD     PTR              Clients CMD\n"
592         "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      command_line_1 0000000000002711 command_line_2;command_line_4\n"
593         "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      command_line_2 0000000000002712 command_line_3;command_line_5\n"
594         "\n"
595         "[fake description 1]\n"
596         "Interface            Transport   Arch Thread Use Server CMD PTR Clients CMD\n"
597         "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A                   N/A command_line_4;command_line_6\n"
598         "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A                   N/A command_line_5;command_line_7\n"
599         "\n"
600         "[fake description 2]\n"
601         "Interface            Transport   Arch Thread Use Server CMD PTR Clients CMD\n"
602         "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A                   N/A command_line_6;command_line_8\n"
603         "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A                   N/A command_line_7;command_line_9\n"
604         "\n";
605 
606     optind = 1; // mimic Lshal::parseArg()
607     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
608     EXPECT_EQ(expected, out.str());
609     EXPECT_EQ("", err.str());
610 }
611 
TEST_F(ListTest,DumpNeat)612 TEST_F(ListTest, DumpNeat) {
613     const std::string expected =
614         "a.h.foo1@1.0::IFoo/1 11/21 1   2 4\n"
615         "a.h.foo2@2.0::IFoo/2 12/22 2   3 5\n"
616         "a.h.foo3@3.0::IFoo/3 N/A   N/A 4 6\n"
617         "a.h.foo4@4.0::IFoo/4 N/A   N/A 5 7\n"
618         "a.h.foo5@5.0::IFoo/5 N/A   N/A 6 8\n"
619         "a.h.foo6@6.0::IFoo/6 N/A   N/A 7 9\n";
620 
621     optind = 1; // mimic Lshal::parseArg()
622     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
623     EXPECT_EQ(expected, out.str());
624     EXPECT_EQ("", err.str());
625 }
626 
TEST_F(ListTest,DumpSingleHalType)627 TEST_F(ListTest, DumpSingleHalType) {
628     const std::string expected =
629         "[fake description 0]\n"
630         "Interface            Transport Arch Thread Use Server PTR              Clients\n"
631         "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
632         "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
633         "\n";
634 
635     optind = 1; // mimic Lshal::parseArg()
636     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
637     EXPECT_EQ(expected, out.str());
638     EXPECT_EQ("", err.str());
639 }
640 
TEST_F(ListTest,DumpReorderedHalTypes)641 TEST_F(ListTest, DumpReorderedHalTypes) {
642     const std::string expected =
643         "[fake description 0]\n"
644         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
645         "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
646         "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
647         "\n"
648         "[fake description 1]\n"
649         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
650         "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
651         "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
652         "\n"
653         "[fake description 2]\n"
654         "Interface            Transport Arch Thread Use Server PTR              Clients\n"
655         "a.h.foo1@1.0::IFoo/1 hwbinder  64   11/21      1      0000000000002711 2 4\n"
656         "a.h.foo2@2.0::IFoo/2 hwbinder  64   12/22      2      0000000000002712 3 5\n"
657         "\n";
658 
659     optind = 1; // mimic Lshal::parseArg()
660     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
661                                             "--types=passthrough_libs", "--types=binderized"})));
662     EXPECT_EQ(expected, out.str());
663     EXPECT_EQ("", err.str());
664 }
665 
TEST_F(ListTest,DumpAbbreviatedHalTypes)666 TEST_F(ListTest, DumpAbbreviatedHalTypes) {
667     const std::string expected =
668         "[fake description 0]\n"
669         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
670         "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
671         "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
672         "\n"
673         "[fake description 1]\n"
674         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
675         "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
676         "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
677         "\n";
678 
679     optind = 1; // mimic Lshal::parseArg()
680     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
681     EXPECT_EQ(expected, out.str());
682     EXPECT_EQ("", err.str());
683 }
684 
TEST_F(ListTest,DumpEmptyAndDuplicateHalTypes)685 TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
686     const std::string expected =
687         "[fake description 0]\n"
688         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
689         "a.h.foo3@3.0::IFoo/3 passthrough 32   N/A        N/A    N/A 4 6\n"
690         "a.h.foo4@4.0::IFoo/4 passthrough 32   N/A        N/A    N/A 5 7\n"
691         "\n"
692         "[fake description 1]\n"
693         "Interface            Transport   Arch Thread Use Server PTR Clients\n"
694         "a.h.foo5@5.0::IFoo/5 passthrough 32   N/A        N/A    N/A 6 8\n"
695         "a.h.foo6@6.0::IFoo/6 passthrough 32   N/A        N/A    N/A 7 9\n"
696         "\n";
697 
698     optind = 1; // mimic Lshal::parseArg()
699     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
700                                             "--types=passthrough_libs,passthrough_clients"})));
701     EXPECT_EQ(expected, out.str());
702     EXPECT_EQ("", err.str());
703 }
704 
TEST_F(ListTest,UnknownHalType)705 TEST_F(ListTest, UnknownHalType) {
706     optind = 1; // mimic Lshal::parseArg()
707     EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,r"})));
708     EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: r"));
709 }
710 
TEST_F(ListTest,Vintf)711 TEST_F(ListTest, Vintf) {
712     std::string deviceManifestXml =
713             "<manifest version=\"1.0\" type=\"device\">\n"
714             "    <hal>\n"
715             "        <name>a.h.foo1</name>\n"
716             "        <transport>hwbinder</transport>\n"
717             "        <fqname>@1.0::IFoo/1</fqname>\n"
718             "    </hal>\n"
719             "    <hal>\n"
720             "        <name>a.h.foo3</name>\n"
721             "        <transport arch=\"32+64\">passthrough</transport>\n"
722             "        <fqname>@3.0::IFoo/3</fqname>\n"
723             "    </hal>\n"
724             "</manifest>\n";
725     std::string frameworkManifestXml =
726             "<manifest version=\"1.0\" type=\"framework\">\n"
727             "    <hal>\n"
728             "        <name>a.h.foo5</name>\n"
729             "        <transport arch=\"32\">passthrough</transport>\n"
730             "        <fqname>@5.0::IFoo/5</fqname>\n"
731             "    </hal>\n"
732             "</manifest>\n";
733     std::string deviceMatrixXml =
734             "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
735             "    <hal>\n"
736             "        <name>a.h.foo5</name>\n"
737             "        <version>5.0</version>\n"
738             "        <interface>\n"
739             "            <name>IFoo</name>\n"
740             "            <instance>5</instance>\n"
741             "        </interface>\n"
742             "    </hal>\n"
743             "</compatibility-matrix>\n";
744     std::string frameworkMatrixXml =
745             "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
746             "    <hal>\n"
747             "        <name>a.h.foo1</name>\n"
748             "        <version>1.0</version>\n"
749             "        <interface>\n"
750             "            <name>IFoo</name>\n"
751             "            <instance>1</instance>\n"
752             "        </interface>\n"
753             "    </hal>\n"
754             "    <hal>\n"
755             "        <name>a.h.foo3</name>\n"
756             "        <version>3.0</version>\n"
757             "        <interface>\n"
758             "            <name>IFoo</name>\n"
759             "            <instance>3</instance>\n"
760             "        </interface>\n"
761             "    </hal>\n"
762             "</compatibility-matrix>\n";
763 
764     std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
765                            "X     a.h.foo2@2.0::IFoo/2\n"
766                            "DM,FC a.h.foo3@3.0::IFoo/3\n"
767                            "X     a.h.foo4@4.0::IFoo/4\n"
768                            "DC,FM a.h.foo5@5.0::IFoo/5\n"
769                            "X     a.h.foo6@6.0::IFoo/6\n";
770 
771     auto deviceManifest = std::make_shared<HalManifest>();
772     auto frameworkManifest = std::make_shared<HalManifest>();
773     auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
774     auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
775 
776     ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml));
777     ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml));
778     ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml));
779     ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml));
780 
781     ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
782     ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
783     ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
784     ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
785 
786     optind = 1; // mimic Lshal::parseArg()
787     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
788     EXPECT_THAT(out.str(), HasSubstr(expected));
789     EXPECT_EQ("", err.str());
790 }
791 
TEST_F(ListTest,AllColumns)792 TEST_F(ListTest, AllColumns) {
793     // clang-format off
794     const std::string expected =
795         "[fake description 0]\n"
796         "Interface            Transport Server PTR              Arch Thread Use R Hash                                                             VINTF Status Clients\n"
797         "a.h.foo1@1.0::IFoo/1 hwbinder  1      0000000000002711 64   11/21      N 0000000000000000000000000000000000000000000000000000000000000000 X     alive  2 4\n"
798         "a.h.foo2@2.0::IFoo/2 hwbinder  2      0000000000002712 64   12/22      Y 0202020202020202020202020202020202020202020202020202020202020202 X     alive  3 5\n"
799         "\n"
800         "[fake description 1]\n"
801         "Interface            Transport   Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
802         "a.h.foo3@3.0::IFoo/3 passthrough N/A    N/A 32   N/A        ?      X     N/A    4 6\n"
803         "a.h.foo4@4.0::IFoo/4 passthrough N/A    N/A 32   N/A        ?      X     N/A    5 7\n"
804         "\n"
805         "[fake description 2]\n"
806         "Interface            Transport   Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
807         "a.h.foo5@5.0::IFoo/5 passthrough N/A    N/A 32   N/A        ?      X     N/A    6 8\n"
808         "a.h.foo6@6.0::IFoo/6 passthrough N/A    N/A 32   N/A        ?      X     N/A    7 9\n"
809         "\n";
810     // clang-format on
811 
812     optind = 1; // mimic Lshal::parseArg()
813     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--all"})));
814     EXPECT_EQ(expected, out.str());
815     EXPECT_EQ("", err.str());
816 }
817 
TEST_F(ListTest,AllColumnsWithCmd)818 TEST_F(ListTest, AllColumnsWithCmd) {
819     // clang-format off
820     const std::string expected =
821         "[fake description 0]\n"
822         "Interface            Transport Server CMD     PTR              Arch Thread Use R Hash                                                             VINTF Status Clients CMD\n"
823         "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"
824         "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"
825         "\n"
826         "[fake description 1]\n"
827         "Interface            Transport   Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
828         "a.h.foo3@3.0::IFoo/3 passthrough            N/A 32   N/A        ?      X     N/A    command_line_4;command_line_6\n"
829         "a.h.foo4@4.0::IFoo/4 passthrough            N/A 32   N/A        ?      X     N/A    command_line_5;command_line_7\n"
830         "\n"
831         "[fake description 2]\n"
832         "Interface            Transport   Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
833         "a.h.foo5@5.0::IFoo/5 passthrough            N/A 32   N/A        ?      X     N/A    command_line_6;command_line_8\n"
834         "a.h.foo6@6.0::IFoo/6 passthrough            N/A 32   N/A        ?      X     N/A    command_line_7;command_line_9\n"
835         "\n";
836     // clang-format on
837 
838     optind = 1; // mimic Lshal::parseArg()
839     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Am"})));
840     EXPECT_EQ(expected, out.str());
841     EXPECT_EQ("", err.str());
842 }
843 
TEST_F(ListTest,AllSections)844 TEST_F(ListTest, AllSections) {
845     optind = 1; // mimic Lshal::parseArg()
846     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=all"})));
847     using HalTypeBase = std::underlying_type_t<HalType>;
848     for (HalTypeBase i = 0; i < static_cast<HalTypeBase>(HalType::LAST); ++i) {
849         EXPECT_THAT(out.str(), HasSubstr("[fake description " + std::to_string(i) + "]"));
850     }
851     EXPECT_THAT(out.str(),
852                 Not(HasSubstr("[fake description " +
853                               std::to_string(static_cast<HalTypeBase>(HalType::LAST)) + "]")));
854     EXPECT_EQ("", err.str());
855 }
856 
857 // Fake service returned by mocked IServiceManager::get for DumpDebug.
858 // The interfaceChain and getHashChain functions returns
859 // foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.
860 class InheritingService : public IBase {
861 public:
InheritingService(pid_t id)862     explicit InheritingService(pid_t id) : mId(id) {}
interfaceDescriptor(interfaceDescriptor_cb cb)863     android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
864         cb(getInterfaceName(mId));
865         return hardware::Void();
866     }
interfaceChain(interfaceChain_cb cb)867     android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
868         std::vector<hidl_string> ret;
869         for (auto i = mId; i > 0; --i) {
870             ret.push_back(getInterfaceName(i));
871         }
872         ret.push_back(IBase::descriptor);
873         cb(ret);
874         return hardware::Void();
875     }
getHashChain(getHashChain_cb cb)876     android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
877         std::vector<hidl_hash> ret;
878         for (auto i = mId; i > 0; --i) {
879             ret.push_back(getHashFromId(i));
880         }
881         ret.push_back(getHashFromId(0xff));
882         cb(ret);
883         return hardware::Void();
884     }
debug(const hidl_handle & hh,const hidl_vec<hidl_string> &)885     android::hardware::Return<void> debug(const hidl_handle& hh,
886                                           const hidl_vec<hidl_string>&) override {
887         const native_handle_t* handle = hh.getNativeHandle();
888         if (handle->numFds < 1) {
889             return Void();
890         }
891         int fd = handle->data[0];
892         std::string content = "debug info for ";
893         content += getInterfaceName(mId);
894         ssize_t written = write(fd, content.c_str(), content.size());
895         if (written != (ssize_t)content.size()) {
896             LOG(WARNING) << "SERVER(" << descriptor << ") debug writes " << written << " bytes < "
897                          << content.size() << " bytes, errno = " << errno;
898         }
899         return Void();
900     }
901 
902 private:
903     pid_t mId;
904 };
905 
TEST_F(ListTest,DumpDebug)906 TEST_F(ListTest, DumpDebug) {
907     size_t inheritanceLevel = 3;
908     sp<IBase> service = new InheritingService(inheritanceLevel);
909 
910     EXPECT_CALL(*serviceManager, list(_)).WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
911         std::vector<hidl_string> ret;
912         for (auto i = 1; i <= inheritanceLevel; ++i) {
913             ret.push_back(getInterfaceName(i) + "/default");
914         }
915         cb(ret);
916         return hardware::Void();
917     }));
918     EXPECT_CALL(*serviceManager, get(_, _))
919             .WillRepeatedly(
920                     Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
921                         int id = getIdFromInstanceName(instance);
922                         if (id > inheritanceLevel) return nullptr;
923                         return sp<IBase>(service);
924                     }));
925 
926     const std::string expected = "[fake description 0]\n"
927                                  "Interface\n"
928                                  "a.h.foo1@1.0::IFoo/default\n"
929                                  "[See a.h.foo3@3.0::IFoo/default]\n"
930                                  "a.h.foo2@2.0::IFoo/default\n"
931                                  "[See a.h.foo3@3.0::IFoo/default]\n"
932                                  "a.h.foo3@3.0::IFoo/default\n"
933                                  "debug info for a.h.foo3@3.0::IFoo\n"
934                                  "\n";
935 
936     optind = 1; // mimic Lshal::parseArg()
937     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=b", "-id"})));
938     EXPECT_EQ(expected, out.str());
939     EXPECT_EQ("", err.str());
940 }
941 
942 class ListVintfTest : public ListTest {
943 public:
SetUp()944     virtual void SetUp() override {
945         ListTest::SetUp();
946         const std::string mockManifestXml =
947                 "<manifest version=\"1.0\" type=\"device\">\n"
948                 "    <hal format=\"hidl\">\n"
949                 "        <name>a.h.foo1</name>\n"
950                 "        <transport>hwbinder</transport>\n"
951                 "        <fqname>@1.0::IFoo/1</fqname>\n"
952                 "    </hal>\n"
953                 "    <hal format=\"hidl\">\n"
954                 "        <name>a.h.bar1</name>\n"
955                 "        <transport>hwbinder</transport>\n"
956                 "        <fqname>@1.0::IBar/1</fqname>\n"
957                 "    </hal>\n"
958                 "    <hal format=\"hidl\">\n"
959                 "        <name>a.h.bar2</name>\n"
960                 "        <transport arch=\"32+64\">passthrough</transport>\n"
961                 "        <fqname>@2.0::IBar/2</fqname>\n"
962                 "    </hal>\n"
963                 "</manifest>";
964         auto manifest = std::make_shared<HalManifest>();
965         EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml));
966         EXPECT_CALL(*mockList, getDeviceManifest())
967             .Times(AnyNumber())
968             .WillRepeatedly(Return(manifest));
969     }
970 };
971 
TEST_F(ListVintfTest,ManifestHals)972 TEST_F(ListVintfTest, ManifestHals) {
973     optind = 1; // mimic Lshal::parseArg()
974     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
975     EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder    ?"));
976     EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
977     EXPECT_THAT(out.str(), HasSubstr("a.h.foo1@1.0::IFoo/1 declared hwbinder    ?"));
978     EXPECT_EQ("", err.str());
979 }
980 
TEST_F(ListVintfTest,Lazy)981 TEST_F(ListVintfTest, Lazy) {
982     optind = 1; // mimic Lshal::parseArg()
983     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
984     EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder    ?"));
985     EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
986     EXPECT_EQ("", err.str());
987 }
988 
TEST_F(ListVintfTest,NoLazy)989 TEST_F(ListVintfTest, NoLazy) {
990     optind = 1; // mimic Lshal::parseArg()
991     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
992     EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
993     EXPECT_EQ("", err.str());
994 }
995 
996 class HelpTest : public ::testing::Test {
997 public:
SetUp()998     void SetUp() override {
999         lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
1000                                         new MockServiceManager() /* passthruManager */);
1001     }
1002 
1003     std::stringstream err;
1004     std::stringstream out;
1005     std::unique_ptr<Lshal> lshal;
1006 };
1007 
TEST_F(HelpTest,GlobalUsage)1008 TEST_F(HelpTest, GlobalUsage) {
1009     (void)callMain(lshal, {"lshal", "--help"}); // ignore return
1010     std::string errStr = err.str();
1011     EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
1012         << "`lshal --help` does not contain global usage";
1013     EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
1014         << "`lshal --help` does not contain usage for 'list' command";
1015     EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
1016         << "`lshal --help` does not contain usage for 'debug' command";
1017     EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
1018         << "`lshal --help` does not contain usage for 'help' command";
1019 
1020     err.str("");
1021     (void)callMain(lshal, {"lshal", "help"}); // ignore return
1022     EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
1023 
1024     err.str("");
1025     EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
1026     EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1027     EXPECT_THAT(err.str(), EndsWith(errStr))
1028             << "`lshal --unknown-option` should have the same output as `lshal --help`";
1029     EXPECT_EQ("", out.str());
1030 }
1031 
TEST_F(HelpTest,UnknownOptionList1)1032 TEST_F(HelpTest, UnknownOptionList1) {
1033     (void)callMain(lshal, {"lshal", "help", "list"});
1034     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1035         << "`lshal help list` does not contain usage for 'list' command";
1036 }
1037 
TEST_F(HelpTest,UnknownOptionList2)1038 TEST_F(HelpTest, UnknownOptionList2) {
1039     EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
1040     EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
1041     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
1042         << "`lshal list --unknown-option` does not contain usage for 'list' command";
1043     EXPECT_EQ("", out.str());
1044 }
1045 
TEST_F(HelpTest,UnknownOptionHelp1)1046 TEST_F(HelpTest, UnknownOptionHelp1) {
1047     (void)callMain(lshal, {"lshal", "help", "help"});
1048     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1049         << "`lshal help help` does not contain usage for 'help' command";
1050 }
1051 
TEST_F(HelpTest,UnknownOptionHelp2)1052 TEST_F(HelpTest, UnknownOptionHelp2) {
1053     (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
1054     EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
1055         << "`lshal help --unknown-option` does not contain usage for 'help' command";
1056     EXPECT_EQ("", out.str());
1057 }
1058 
1059 } // namespace lshal
1060 } // namespace android
1061 
main(int argc,char ** argv)1062 int main(int argc, char **argv) {
1063     ::testing::InitGoogleMock(&argc, argv);
1064     return RUN_ALL_TESTS();
1065 }
1066