blob: a5cac158f0a2c16b54d6b8f1830519119b7fc322 [file] [log] [blame]
Yifan Hongb0dde932017-02-10 17:49:58 -08001/*
2 * Copyright (C) 2016 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 "Lshal.h"
18
19#include <getopt.h>
20
21#include <fstream>
22#include <iomanip>
23#include <iostream>
24#include <map>
25#include <sstream>
26#include <regex>
27
28#include <android-base/parseint.h>
29#include <android/hidl/manager/1.0/IServiceManager.h>
30#include <hidl/ServiceManagement.h>
Yifan Hong4b865492017-02-28 19:38:24 -080031#include <hidl-util/FQName.h>
32#include <vintf/HalManifest.h>
33#include <vintf/parse_xml.h>
Yifan Hongb0dde932017-02-10 17:49:58 -080034
Yifan Honge2dadf02017-02-14 15:43:31 -080035#include "Timeout.h"
36
Yifan Hongb0dde932017-02-10 17:49:58 -080037using ::android::hardware::hidl_string;
38using ::android::hidl::manager::V1_0::IServiceManager;
39
40namespace android {
41namespace lshal {
42
Yifan Hongb0dde932017-02-10 17:49:58 -080043template <typename A>
44std::string join(const A &components, const std::string &separator) {
45 std::stringstream out;
46 bool first = true;
47 for (const auto &component : components) {
48 if (!first) {
49 out << separator;
50 }
51 out << component;
52
53 first = false;
54 }
55 return out.str();
56}
57
58static std::string toHexString(uint64_t t) {
59 std::ostringstream os;
60 os << std::hex << std::setfill('0') << std::setw(16) << t;
61 return os.str();
62}
63
Yifan Hong4b865492017-02-28 19:38:24 -080064template<typename String>
65static std::pair<String, String> splitFirst(const String &s, char c) {
Yifan Hongb0dde932017-02-10 17:49:58 -080066 const char *pos = strchr(s.c_str(), c);
67 if (pos == nullptr) {
68 return {s, {}};
69 }
Yifan Hong4b865492017-02-28 19:38:24 -080070 return {String(s.c_str(), pos - s.c_str()), String(pos + 1)};
Yifan Hongb0dde932017-02-10 17:49:58 -080071}
72
73static std::vector<std::string> split(const std::string &s, char c) {
74 std::vector<std::string> components{};
75 size_t startPos = 0;
76 size_t matchPos;
77 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
78 components.push_back(s.substr(startPos, matchPos - startPos));
79 startPos = matchPos + 1;
80 }
81
82 if (startPos <= s.length()) {
83 components.push_back(s.substr(startPos));
84 }
85 return components;
86}
87
Yifan Hong4b865492017-02-28 19:38:24 -080088static void replaceAll(std::string *s, char from, char to) {
89 for (size_t i = 0; i < s->size(); ++i) {
90 if (s->at(i) == from) {
91 s->at(i) = to;
92 }
93 }
94}
95
Yifan Hongae09a3d2017-02-14 17:33:50 -080096std::string getCmdline(pid_t pid) {
97 std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
98 std::string cmdline;
99 if (!ifs.is_open()) {
100 return "";
101 }
102 ifs >> cmdline;
103 return cmdline;
104}
105
106const std::string &Lshal::getCmdline(pid_t pid) {
107 auto pair = mCmdlines.find(pid);
108 if (pair != mCmdlines.end()) {
109 return pair->second;
110 }
111 mCmdlines[pid] = ::android::lshal::getCmdline(pid);
112 return mCmdlines[pid];
113}
114
115void Lshal::removeDeadProcesses(Pids *pids) {
116 static const pid_t myPid = getpid();
117 std::remove_if(pids->begin(), pids->end(), [this](auto pid) {
118 return pid == myPid || this->getCmdline(pid).empty();
119 });
120}
121
Yifan Hongb0dde932017-02-10 17:49:58 -0800122bool Lshal::getReferencedPids(
123 pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
124
125 std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
126 if (!ifs.is_open()) {
127 return false;
128 }
129
130 static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
131
132 std::string line;
133 std::smatch match;
134 while(getline(ifs, line)) {
135 if (!std::regex_search(line, match, prefix)) {
136 // the line doesn't start with the correct prefix
137 continue;
138 }
139 std::string ptrString = "0x" + match.str(2); // use number after c
140 uint64_t ptr;
141 if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
142 // Should not reach here, but just be tolerant.
143 mErr << "Could not parse number " << ptrString << std::endl;
144 continue;
145 }
146 const std::string proc = " proc ";
147 auto pos = line.rfind(proc);
148 if (pos != std::string::npos) {
149 for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
150 int32_t pid;
151 if (!::android::base::ParseInt(pidStr, &pid)) {
152 mErr << "Could not parse number " << pidStr << std::endl;
153 continue;
154 }
155 (*objects)[ptr].push_back(pid);
156 }
157 }
158 }
159 return true;
160}
161
Yifan Honga3b87092017-03-02 19:19:29 -0800162void Lshal::forEachTable(const std::function<void(Table &)> &f) {
Yifan Hong8ab3bee2017-03-08 14:01:11 -0800163 f(mServicesTable);
164 f(mPassthroughRefTable);
165 f(mImplementationsTable);
Yifan Honga3b87092017-03-02 19:19:29 -0800166}
167void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
Yifan Hong8ab3bee2017-03-08 14:01:11 -0800168 f(mServicesTable);
169 f(mPassthroughRefTable);
170 f(mImplementationsTable);
Yifan Honga3b87092017-03-02 19:19:29 -0800171}
172
Yifan Hong38d53e02017-02-13 17:51:59 -0800173void Lshal::postprocess() {
Yifan Honga3b87092017-03-02 19:19:29 -0800174 forEachTable([this](Table &table) {
175 if (mSortColumn) {
176 std::sort(table.begin(), table.end(), mSortColumn);
Yifan Hongae09a3d2017-02-14 17:33:50 -0800177 }
Yifan Honga3b87092017-03-02 19:19:29 -0800178 for (TableEntry &entry : table) {
179 entry.serverCmdline = getCmdline(entry.serverPid);
180 removeDeadProcesses(&entry.clientPids);
181 for (auto pid : entry.clientPids) {
182 entry.clientCmdlines.push_back(this->getCmdline(pid));
183 }
184 }
185 });
Yifan Hong3fdbd9f2017-03-08 14:01:58 -0800186 // use a double for loop here because lshal doesn't care about efficiency.
187 for (TableEntry &packageEntry : mImplementationsTable) {
188 std::string packageName = packageEntry.interfaceName;
189 FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
190 if (!fqPackageName.isValid()) {
191 continue;
192 }
193 for (TableEntry &interfaceEntry : mPassthroughRefTable) {
194 if (interfaceEntry.arch != ARCH_UNKNOWN) {
195 continue;
196 }
197 FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
198 if (!interfaceName.isValid()) {
199 continue;
200 }
201 if (interfaceName.getPackageAndVersion() == fqPackageName) {
202 interfaceEntry.arch = packageEntry.arch;
203 }
204 }
205 }
Yifan Hong38d53e02017-02-13 17:51:59 -0800206}
207
208void Lshal::printLine(
209 const std::string &interfaceName,
Yifan Hongb4479022017-03-02 16:54:11 -0800210 const std::string &transport,
211 const std::string &arch,
212 const std::string &server,
Yifan Hongae09a3d2017-02-14 17:33:50 -0800213 const std::string &serverCmdline,
214 const std::string &address, const std::string &clients,
215 const std::string &clientCmdlines) const {
Yifan Hong38d53e02017-02-13 17:51:59 -0800216 if (mSelectedColumns & ENABLE_INTERFACE_NAME)
217 mOut << std::setw(80) << interfaceName << "\t";
218 if (mSelectedColumns & ENABLE_TRANSPORT)
219 mOut << std::setw(10) << transport << "\t";
Yifan Hongb4479022017-03-02 16:54:11 -0800220 if (mSelectedColumns & ENABLE_ARCH)
221 mOut << std::setw(5) << arch << "\t";
Yifan Hongae09a3d2017-02-14 17:33:50 -0800222 if (mSelectedColumns & ENABLE_SERVER_PID) {
223 if (mEnableCmdlines) {
224 mOut << std::setw(15) << serverCmdline << "\t";
225 } else {
226 mOut << std::setw(5) << server << "\t";
227 }
228 }
Yifan Hong38d53e02017-02-13 17:51:59 -0800229 if (mSelectedColumns & ENABLE_SERVER_ADDR)
230 mOut << std::setw(16) << address << "\t";
Yifan Hongae09a3d2017-02-14 17:33:50 -0800231 if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
232 if (mEnableCmdlines) {
233 mOut << std::setw(0) << clientCmdlines;
234 } else {
235 mOut << std::setw(0) << clients;
236 }
237 }
Yifan Hong38d53e02017-02-13 17:51:59 -0800238 mOut << std::endl;
239}
240
Yifan Hong4b865492017-02-28 19:38:24 -0800241void Lshal::dumpVintf() const {
242 vintf::HalManifest manifest;
Yifan Honga3b87092017-03-02 19:19:29 -0800243 forEachTable([this, &manifest] (const Table &table) {
244 for (const TableEntry &entry : table) {
Yifan Hong4b865492017-02-28 19:38:24 -0800245
Yifan Honga3b87092017-03-02 19:19:29 -0800246 std::string fqInstanceName = entry.interfaceName;
Yifan Hong4b865492017-02-28 19:38:24 -0800247
Yifan Honga3b87092017-03-02 19:19:29 -0800248 if (&table == &mImplementationsTable) {
249 // Quick hack to work around *'s
250 replaceAll(&fqInstanceName, '*', 'D');
251 }
252 auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
253 FQName fqName(splittedFqInstanceName.first);
254 if (!fqName.isValid()) {
255 mErr << "Warning: '" << splittedFqInstanceName.first
256 << "' is not a valid FQName." << std::endl;
Yifan Hong4b865492017-02-28 19:38:24 -0800257 continue;
258 }
Yifan Honga3b87092017-03-02 19:19:29 -0800259 // Strip out system libs.
Steven Moreland9b6cd602017-03-22 14:22:55 -0700260 if (fqName.inPackage("android.hidl") ||
261 fqName.inPackage("android.frameworks") ||
262 fqName.inPackage("android.system")) {
Yifan Honga3b87092017-03-02 19:19:29 -0800263 continue;
264 }
265 std::string interfaceName =
266 &table == &mImplementationsTable ? "" : fqName.name();
267 std::string instanceName =
268 &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
269
270 vintf::Transport transport;
Yifan Hong3fdbd9f2017-03-08 14:01:58 -0800271 vintf::Arch arch;
Yifan Honga3b87092017-03-02 19:19:29 -0800272 if (entry.transport == "hwbinder") {
273 transport = vintf::Transport::HWBINDER;
Yifan Hong3fdbd9f2017-03-08 14:01:58 -0800274 arch = vintf::Arch::ARCH_EMPTY;
Yifan Honga3b87092017-03-02 19:19:29 -0800275 } else if (entry.transport == "passthrough") {
276 transport = vintf::Transport::PASSTHROUGH;
Yifan Hong3fdbd9f2017-03-08 14:01:58 -0800277 switch (entry.arch) {
278 case lshal::ARCH32:
279 arch = vintf::Arch::ARCH_32; break;
280 case lshal::ARCH64:
281 arch = vintf::Arch::ARCH_64; break;
282 case lshal::ARCH_BOTH:
283 arch = vintf::Arch::ARCH_32_64; break;
284 case lshal::ARCH_UNKNOWN: // fallthrough
285 default:
286 mErr << "Warning: '" << fqName.package()
287 << "' doesn't have bitness info, assuming 32+64." << std::endl;
288 arch = vintf::Arch::ARCH_32_64;
289 }
Yifan Hong4b865492017-02-28 19:38:24 -0800290 } else {
Yifan Honga3b87092017-03-02 19:19:29 -0800291 mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
292 continue;
293 }
294
295 vintf::ManifestHal *hal = manifest.getHal(fqName.package());
296 if (hal == nullptr) {
297 if (!manifest.add(vintf::ManifestHal{
298 .format = vintf::HalFormat::HIDL,
299 .name = fqName.package(),
300 .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
Yifan Hong3fdbd9f2017-03-08 14:01:58 -0800301 .transportArch = {transport, arch}
Yifan Honga3b87092017-03-02 19:19:29 -0800302 })) {
303 mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
304 continue;
305 }
306 hal = manifest.getHal(fqName.package());
307 }
308 if (hal == nullptr) {
309 mErr << "Warning: cannot get hal '" << fqInstanceName
310 << "' after adding it" << std::endl;
311 continue;
312 }
313 vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()};
314 if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) {
315 hal->versions.push_back(version);
316 }
317 if (&table != &mImplementationsTable) {
318 auto it = hal->interfaces.find(interfaceName);
319 if (it == hal->interfaces.end()) {
320 hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}});
321 } else {
322 it->second.instances.insert(instanceName);
323 }
Yifan Hong4b865492017-02-28 19:38:24 -0800324 }
325 }
Yifan Honga3b87092017-03-02 19:19:29 -0800326 });
Yifan Hong4b865492017-02-28 19:38:24 -0800327 mOut << vintf::gHalManifestConverter(manifest);
328}
329
Yifan Hongb4479022017-03-02 16:54:11 -0800330static const std::string &getArchString(Architecture arch) {
331 static const std::string sStr64 = "64";
332 static const std::string sStr32 = "32";
Yifan Hong1071c1b2017-03-03 10:57:43 -0800333 static const std::string sStrBoth = "32+64";
Yifan Hongb4479022017-03-02 16:54:11 -0800334 static const std::string sStrUnknown = "";
335 switch (arch) {
336 case ARCH64:
337 return sStr64;
338 case ARCH32:
339 return sStr32;
340 case ARCH_BOTH:
341 return sStrBoth;
342 case ARCH_UNKNOWN: // fall through
343 default:
344 return sStrUnknown;
345 }
346}
347
348static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
349 switch (a) {
350 case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
351 return ARCH64;
352 case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
353 return ARCH32;
354 case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
355 default:
356 return ARCH_UNKNOWN;
357 }
358}
359
Yifan Honga3b87092017-03-02 19:19:29 -0800360void Lshal::dumpTable() {
361 mServicesTable.description =
362 "All binderized services (registered services through hwservicemanager)";
363 mPassthroughRefTable.description =
Yifan Hong1071c1b2017-03-03 10:57:43 -0800364 "All interfaces that getService() has ever return as a passthrough interface;\n"
Yifan Honga3b87092017-03-02 19:19:29 -0800365 "PIDs / processes shown below might be inaccurate because the process\n"
Yifan Hong1071c1b2017-03-03 10:57:43 -0800366 "might have relinquished the interface or might have died.\n"
Yifan Honga3b87092017-03-02 19:19:29 -0800367 "The Server / Server CMD column can be ignored.\n"
Yifan Hong1071c1b2017-03-03 10:57:43 -0800368 "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
369 "the library and successfully fetched the passthrough implementation.";
Yifan Honga3b87092017-03-02 19:19:29 -0800370 mImplementationsTable.description =
371 "All available passthrough implementations (all -impl.so files)";
372 forEachTable([this] (const Table &table) {
373 mOut << table.description << std::endl;
374 mOut << std::left;
375 printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
376 "PTR", "Clients", "Clients CMD");
377 for (const auto &entry : table) {
378 printLine(entry.interfaceName,
379 entry.transport,
380 getArchString(entry.arch),
381 entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
382 entry.serverCmdline,
383 entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
384 join(entry.clientPids, " "),
385 join(entry.clientCmdlines, ";"));
386 }
387 mOut << std::endl;
388 });
389
Yifan Hongb0dde932017-02-10 17:49:58 -0800390}
391
Yifan Hong4b865492017-02-28 19:38:24 -0800392void Lshal::dump() {
393 if (mVintf) {
394 dumpVintf();
395 if (!!mFileOutput) {
396 mFileOutput.buf().close();
397 delete &mFileOutput.buf();
398 mFileOutput = nullptr;
399 }
400 mOut = std::cout;
401 } else {
402 dumpTable();
403 }
404}
405
Yifan Honga3b87092017-03-02 19:19:29 -0800406void Lshal::putEntry(TableEntrySource source, TableEntry &&entry) {
407 Table *table = nullptr;
408 switch (source) {
409 case HWSERVICEMANAGER_LIST :
410 table = &mServicesTable; break;
411 case PTSERVICEMANAGER_REG_CLIENT :
412 table = &mPassthroughRefTable; break;
413 case LIST_DLLIB :
414 table = &mImplementationsTable; break;
415 default:
416 mErr << "Error: Unknown source of entry " << source << std::endl;
417 }
418 if (table) {
419 table->entries.push_back(std::forward<TableEntry>(entry));
420 }
Yifan Hongb0dde932017-02-10 17:49:58 -0800421}
422
423Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {
424 using namespace ::android::hardware;
425 using namespace ::android::hidl::manager::V1_0;
426 using namespace ::android::hidl::base::V1_0;
Yifan Hongb4479022017-03-02 16:54:11 -0800427 auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
428 std::map<std::string, TableEntry> entries;
429 for (const auto &info : infos) {
430 std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
431 std::string{info.instanceName.c_str()};
Yifan Hong1071c1b2017-03-03 10:57:43 -0800432 entries.emplace(interfaceName, TableEntry{
Yifan Hongb4479022017-03-02 16:54:11 -0800433 .interfaceName = interfaceName,
Yifan Hongb0dde932017-02-10 17:49:58 -0800434 .transport = "passthrough",
435 .serverPid = NO_PID,
436 .serverObjectAddress = NO_PTR,
Yifan Hong4b865492017-02-28 19:38:24 -0800437 .clientPids = {},
Yifan Honga3b87092017-03-02 19:19:29 -0800438 .arch = ARCH_UNKNOWN
Yifan Hongb4479022017-03-02 16:54:11 -0800439 }).first->second.arch |= fromBaseArchitecture(info.arch);
440 }
441 for (auto &&pair : entries) {
Yifan Honga3b87092017-03-02 19:19:29 -0800442 putEntry(LIST_DLLIB, std::move(pair.second));
Yifan Hongb0dde932017-02-10 17:49:58 -0800443 }
444 });
445 if (!ret.isOk()) {
446 mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
447 << ret.description() << std::endl;
448 return DUMP_ALL_LIBS_ERROR;
449 }
450 return OK;
451}
452
453Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
454 using namespace ::android::hardware;
Yifan Hongb4479022017-03-02 16:54:11 -0800455 using namespace ::android::hardware::details;
Yifan Hongb0dde932017-02-10 17:49:58 -0800456 using namespace ::android::hidl::manager::V1_0;
457 using namespace ::android::hidl::base::V1_0;
Yifan Honge2dadf02017-02-14 15:43:31 -0800458 auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
Yifan Hongb0dde932017-02-10 17:49:58 -0800459 for (const auto &info : infos) {
Steven Moreland56d2d512017-03-21 12:17:55 -0700460 if (info.clientPids.size() <= 0) {
461 continue;
462 }
Yifan Honga3b87092017-03-02 19:19:29 -0800463 putEntry(PTSERVICEMANAGER_REG_CLIENT, {
Yifan Hongb0dde932017-02-10 17:49:58 -0800464 .interfaceName =
465 std::string{info.interfaceName.c_str()} + "/" +
466 std::string{info.instanceName.c_str()},
467 .transport = "passthrough",
468 .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
469 .serverObjectAddress = NO_PTR,
Yifan Hong4b865492017-02-28 19:38:24 -0800470 .clientPids = info.clientPids,
Yifan Honga3b87092017-03-02 19:19:29 -0800471 .arch = fromBaseArchitecture(info.arch)
Yifan Hongb0dde932017-02-10 17:49:58 -0800472 });
473 }
474 });
475 if (!ret.isOk()) {
476 mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
477 << ret.description() << std::endl;
478 return DUMP_PASSTHROUGH_ERROR;
479 }
480 return OK;
481}
482
483Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) {
484 using namespace ::std;
485 using namespace ::android::hardware;
486 using namespace ::android::hidl::manager::V1_0;
487 using namespace ::android::hidl::base::V1_0;
488 const std::string mode = "hwbinder";
Yifan Hongb0dde932017-02-10 17:49:58 -0800489
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800490 hidl_vec<hidl_string> fqInstanceNames;
491 // copying out for timeoutIPC
492 auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
493 fqInstanceNames = names;
Yifan Hongb0dde932017-02-10 17:49:58 -0800494 });
495 if (!listRet.isOk()) {
496 mErr << "Error: Failed to list services for " << mode << ": "
497 << listRet.description() << std::endl;
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800498 return DUMP_BINDERIZED_ERROR;
499 }
500
501 Status status = OK;
502 // server pid, .ptr value of binder object, child pids
503 std::map<std::string, DebugInfo> allDebugInfos;
504 std::map<pid_t, std::map<uint64_t, Pids>> allPids;
505 for (const auto &fqInstanceName : fqInstanceNames) {
Yifan Hong4b865492017-02-28 19:38:24 -0800506 const auto pair = splitFirst(fqInstanceName, '/');
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800507 const auto &serviceName = pair.first;
508 const auto &instanceName = pair.second;
509 auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
510 if (!getRet.isOk()) {
511 mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
512 << "cannot be fetched from service manager:"
513 << getRet.description() << std::endl;
514 status |= DUMP_BINDERIZED_ERROR;
515 continue;
516 }
517 sp<IBase> service = getRet;
518 if (service == nullptr) {
519 mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
520 << "cannot be fetched from service manager (null)";
521 status |= DUMP_BINDERIZED_ERROR;
522 continue;
523 }
524 auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
525 allDebugInfos[fqInstanceName] = debugInfo;
526 if (debugInfo.pid >= 0) {
527 allPids[static_cast<pid_t>(debugInfo.pid)].clear();
528 }
529 });
530 if (!debugRet.isOk()) {
531 mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
532 << "debugging information cannot be retrieved:"
533 << debugRet.description() << std::endl;
534 status |= DUMP_BINDERIZED_ERROR;
535 }
536 }
537 for (auto &pair : allPids) {
538 pid_t serverPid = pair.first;
539 if (!getReferencedPids(serverPid, &allPids[serverPid])) {
540 mErr << "Warning: no information for PID " << serverPid
541 << ", are you root?" << std::endl;
542 status |= DUMP_BINDERIZED_ERROR;
543 }
544 }
545 for (const auto &fqInstanceName : fqInstanceNames) {
546 auto it = allDebugInfos.find(fqInstanceName);
547 if (it == allDebugInfos.end()) {
Yifan Honga3b87092017-03-02 19:19:29 -0800548 putEntry(HWSERVICEMANAGER_LIST, {
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800549 .interfaceName = fqInstanceName,
550 .transport = mode,
551 .serverPid = NO_PID,
552 .serverObjectAddress = NO_PTR,
Yifan Hong4b865492017-02-28 19:38:24 -0800553 .clientPids = {},
Yifan Honga3b87092017-03-02 19:19:29 -0800554 .arch = ARCH_UNKNOWN
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800555 });
556 continue;
557 }
558 const DebugInfo &info = it->second;
Yifan Honga3b87092017-03-02 19:19:29 -0800559 putEntry(HWSERVICEMANAGER_LIST, {
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800560 .interfaceName = fqInstanceName,
561 .transport = mode,
562 .serverPid = info.pid,
563 .serverObjectAddress = info.ptr,
564 .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
Yifan Hong4b865492017-02-28 19:38:24 -0800565 ? Pids{} : allPids[info.pid][info.ptr],
Yifan Hongb4479022017-03-02 16:54:11 -0800566 .arch = fromBaseArchitecture(info.arch),
Steven Moreland9b5c15d2017-02-28 17:52:58 -0800567 });
Yifan Hongb0dde932017-02-10 17:49:58 -0800568 }
569 return status;
570}
571
572Status Lshal::fetch() {
573 Status status = OK;
574 auto bManager = ::android::hardware::defaultServiceManager();
575 if (bManager == nullptr) {
576 mErr << "Failed to get defaultServiceManager()!" << std::endl;
577 status |= NO_BINDERIZED_MANAGER;
578 } else {
579 status |= fetchBinderized(bManager);
580 // Passthrough PIDs are registered to the binderized manager as well.
581 status |= fetchPassthrough(bManager);
582 }
583
584 auto pManager = ::android::hardware::getPassthroughServiceManager();
585 if (pManager == nullptr) {
586 mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
587 status |= NO_PASSTHROUGH_MANAGER;
588 } else {
589 status |= fetchAllLibraries(pManager);
590 }
591 return status;
592}
593
594void Lshal::usage() const {
595 mErr
596 << "usage: lshal" << std::endl
Yifan Honga3b87092017-03-02 19:19:29 -0800597 << " Dump all hals with default ordering and columns [-ipc]." << std::endl
Yifan Hongb4479022017-03-02 16:54:11 -0800598 << " lshal [--interface|-i] [--transport|-t] [-r|--arch]" << std::endl
Yifan Hong38d53e02017-02-13 17:51:59 -0800599 << " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl
Yifan Hong4b865492017-02-28 19:38:24 -0800600 << " [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << std::endl
Yifan Hong38d53e02017-02-13 17:51:59 -0800601 << " -i, --interface: print the interface name column" << std::endl
602 << " -n, --instance: print the instance name column" << std::endl
603 << " -t, --transport: print the transport mode column" << std::endl
Yifan Hongb4479022017-03-02 16:54:11 -0800604 << " -r, --arch: print if the HAL is in 64-bit or 32-bit" << std::endl
Yifan Hongae09a3d2017-02-14 17:33:50 -0800605 << " -p, --pid: print the server PID, or server cmdline if -m is set" << std::endl
Yifan Hong38d53e02017-02-13 17:51:59 -0800606 << " -a, --address: print the server object address column" << std::endl
Yifan Hongae09a3d2017-02-14 17:33:50 -0800607 << " -c, --clients: print the client PIDs, or client cmdlines if -m is set"
608 << std::endl
609 << " -m, --cmdline: print cmdline instead of PIDs" << std::endl
Yifan Hong38d53e02017-02-13 17:51:59 -0800610 << " --sort=i, --sort=interface: sort by interface name" << std::endl
611 << " --sort=p, --sort=pid: sort by server pid" << std::endl
Yifan Hong4b865492017-02-28 19:38:24 -0800612 << " --init-vintf=path: form a skeleton HAL manifest to specified file " << std::endl
613 << " (stdout if no file specified)" << std::endl
Yifan Hongb0dde932017-02-10 17:49:58 -0800614 << " lshal [-h|--help]" << std::endl
615 << " -h, --help: show this help information." << std::endl;
616}
617
618Status Lshal::parseArgs(int argc, char **argv) {
619 static struct option longOptions[] = {
Yifan Hong38d53e02017-02-13 17:51:59 -0800620 // long options with short alternatives
621 {"help", no_argument, 0, 'h' },
622 {"interface", no_argument, 0, 'i' },
623 {"transport", no_argument, 0, 't' },
Yifan Hongb4479022017-03-02 16:54:11 -0800624 {"arch", no_argument, 0, 'r' },
Yifan Hong38d53e02017-02-13 17:51:59 -0800625 {"pid", no_argument, 0, 'p' },
626 {"address", no_argument, 0, 'a' },
627 {"clients", no_argument, 0, 'c' },
Yifan Hongae09a3d2017-02-14 17:33:50 -0800628 {"cmdline", no_argument, 0, 'm' },
Yifan Hong38d53e02017-02-13 17:51:59 -0800629
630 // long options without short alternatives
631 {"sort", required_argument, 0, 's' },
Yifan Hong4b865492017-02-28 19:38:24 -0800632 {"init-vintf",optional_argument, 0, 'v' },
Yifan Hong38d53e02017-02-13 17:51:59 -0800633 { 0, 0, 0, 0 }
Yifan Hongb0dde932017-02-10 17:49:58 -0800634 };
635
636 int optionIndex;
637 int c;
638 optind = 1;
639 for (;;) {
640 // using getopt_long in case we want to add other options in the future
Yifan Hongb4479022017-03-02 16:54:11 -0800641 c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
Yifan Hongb0dde932017-02-10 17:49:58 -0800642 if (c == -1) {
643 break;
644 }
645 switch (c) {
Yifan Hong38d53e02017-02-13 17:51:59 -0800646 case 's': {
647 if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
648 mSortColumn = TableEntry::sortByInterfaceName;
649 } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
650 mSortColumn = TableEntry::sortByServerPid;
651 } else {
652 mErr << "Unrecognized sorting column: " << optarg << std::endl;
653 usage();
654 return USAGE;
655 }
656 break;
657 }
Yifan Hong4b865492017-02-28 19:38:24 -0800658 case 'v': {
659 if (optarg) {
660 mFileOutput = new std::ofstream{optarg};
661 mOut = mFileOutput;
662 if (!mFileOutput.buf().is_open()) {
663 mErr << "Could not open file '" << optarg << "'." << std::endl;
664 return IO_ERROR;
665 }
666 }
667 mVintf = true;
668 }
Yifan Hong38d53e02017-02-13 17:51:59 -0800669 case 'i': {
670 mSelectedColumns |= ENABLE_INTERFACE_NAME;
671 break;
672 }
673 case 't': {
674 mSelectedColumns |= ENABLE_TRANSPORT;
675 break;
676 }
Yifan Hongb4479022017-03-02 16:54:11 -0800677 case 'r': {
678 mSelectedColumns |= ENABLE_ARCH;
679 break;
680 }
Yifan Hong38d53e02017-02-13 17:51:59 -0800681 case 'p': {
682 mSelectedColumns |= ENABLE_SERVER_PID;
683 break;
684 }
685 case 'a': {
686 mSelectedColumns |= ENABLE_SERVER_ADDR;
687 break;
688 }
689 case 'c': {
690 mSelectedColumns |= ENABLE_CLIENT_PIDS;
691 break;
692 }
Yifan Hongae09a3d2017-02-14 17:33:50 -0800693 case 'm': {
694 mEnableCmdlines = true;
695 break;
696 }
Yifan Hongb0dde932017-02-10 17:49:58 -0800697 case 'h': // falls through
698 default: // see unrecognized options
699 usage();
700 return USAGE;
701 }
702 }
Yifan Hong38d53e02017-02-13 17:51:59 -0800703
704 if (mSelectedColumns == 0) {
Yifan Honga3b87092017-03-02 19:19:29 -0800705 mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
Yifan Hong38d53e02017-02-13 17:51:59 -0800706 }
Yifan Hongb0dde932017-02-10 17:49:58 -0800707 return OK;
708}
709
710int Lshal::main(int argc, char **argv) {
711 Status status = parseArgs(argc, argv);
712 if (status != OK) {
713 return status;
714 }
715 status = fetch();
Yifan Hong38d53e02017-02-13 17:51:59 -0800716 postprocess();
Yifan Hongb0dde932017-02-10 17:49:58 -0800717 dump();
718 return status;
719}
720
Yifan Honga57dffb2017-02-21 14:59:00 -0800721void signalHandler(int sig) {
722 if (sig == SIGINT) {
723 int retVal;
724 pthread_exit(&retVal);
725 }
726}
727
Yifan Hongb0dde932017-02-10 17:49:58 -0800728} // namespace lshal
729} // namespace android
730
731int main(int argc, char **argv) {
Yifan Honga57dffb2017-02-21 14:59:00 -0800732 signal(SIGINT, ::android::lshal::signalHandler);
Yifan Hongb0dde932017-02-10 17:49:58 -0800733 return ::android::lshal::Lshal{}.main(argc, argv);
734}