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