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