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