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