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