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