blob: 07cd9f44a6adc6fc18bbae94f25e0b66033804c1 [file] [log] [blame]
Yifan Hong85dd3ad2017-01-25 14:20:34 -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
18#include <getopt.h>
19
20#include <map>
Yifan Hongf4bee842017-02-01 15:54:01 -080021#include <fstream>
Yifan Hong85dd3ad2017-01-25 14:20:34 -080022#include <iomanip>
23#include <iostream>
24#include <sstream>
Yifan Hongf4bee842017-02-01 15:54:01 -080025#include <regex>
Yifan Hong85dd3ad2017-01-25 14:20:34 -080026
Yifan Hongf4bee842017-02-01 15:54:01 -080027#include <android-base/parseint.h>
Yifan Hong85dd3ad2017-01-25 14:20:34 -080028#include <android/hidl/manager/1.0/IServiceManager.h>
29#include <hidl/ServiceManagement.h>
30
Yifan Hongb24760f2017-02-03 13:40:04 -080031using ::android::hardware::hidl_string;
32
33template <typename A, typename B, typename C, typename D, typename E, typename F>
Yifan Hong85dd3ad2017-01-25 14:20:34 -080034void printColumn(std::stringstream &stream,
Yifan Hongb24760f2017-02-03 13:40:04 -080035 const A &a, const B &b, const C &c, const D &d, const E &, const F &f) {
Yifan Hong85dd3ad2017-01-25 14:20:34 -080036 using namespace ::std;
37 stream << left
38 << setw(70) << a << "\t"
39 << setw(20) << b << "\t"
40 << setw(10) << c << "\t"
41 << setw(5) << d << "\t"
Yifan Hongb24760f2017-02-03 13:40:04 -080042 // TODO(b/34984175): enable selecting columns
43 // << setw(16) << e << "\t"
44 << setw(0) << f
Yifan Hong85dd3ad2017-01-25 14:20:34 -080045 << endl;
46}
47
Yifan Hongf4bee842017-02-01 15:54:01 -080048std::string toHexString(uint64_t t) {
49 std::ostringstream os;
50 os << std::hex << std::setfill('0') << std::setw(16) << t;
51 return os.str();
52}
53
Yifan Hongb24760f2017-02-03 13:40:04 -080054std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) {
55 const char *pos = strchr(s.c_str(), c);
56 if (pos == nullptr) {
57 return {s, {}};
58 }
59 return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)};
60}
61
62bool getReferencedPids(
Yifan Hongf4bee842017-02-01 15:54:01 -080063 pid_t serverPid, std::map<uint64_t, std::string> *objects) {
64
65 std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
66 if (!ifs.is_open()) {
Yifan Hongb24760f2017-02-03 13:40:04 -080067 return false;
Yifan Hongf4bee842017-02-01 15:54:01 -080068 }
69
70 static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
71
72 std::string line;
73 std::smatch match;
74 while(getline(ifs, line)) {
75 if (!std::regex_search(line, match, prefix)) {
76 // the line doesn't start with the correct prefix
77 continue;
78 }
79 std::string ptrString = "0x" + match.str(2); // use number after c
80 uint64_t ptr;
81 if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
82 // Should not reach here, but just be tolerant.
83 std::cerr << "Could not parse number " << ptrString << std::endl;
84 continue;
85 }
86 const std::string proc = " proc ";
87 auto pos = line.rfind(proc);
88 if (pos != std::string::npos) {
89 (*objects)[ptr] += line.substr(pos + proc.size());
90 }
91 }
Yifan Hongb24760f2017-02-03 13:40:04 -080092 return true;
Yifan Hongf4bee842017-02-01 15:54:01 -080093}
94
Yifan Hongb24760f2017-02-03 13:40:04 -080095void dumpBinderized(std::stringstream &stream, const std::string &mode,
96 const sp<IServiceManager> &manager) {
97 using namespace ::std;
98 using namespace ::android::hardware;
99 using namespace ::android::hidl::manager::V1_0;
100 using namespace ::android::hidl::base::V1_0;
101 auto listRet = manager->list([&] (const auto &fqInstanceNames) {
102 // server pid, .ptr value of binder object, child pids
103 std::map<std::string, DebugInfo> allDebugInfos;
104 std::map<pid_t, std::map<uint64_t, std::string>> allPids;
105 for (const auto &fqInstanceName : fqInstanceNames) {
106 const auto pair = split(fqInstanceName, '/');
107 const auto &serviceName = pair.first;
108 const auto &instanceName = pair.second;
109 auto getRet = manager->get(serviceName, instanceName);
110 if (!getRet.isOk()) {
111 cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
112 << "cannot be fetched from service manager:"
113 << getRet.description() << endl;
114 continue;
115 }
116 sp<IBase> service = getRet;
117 if (service == nullptr) {
118 cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
119 << "cannot be fetched from service manager (null)";
120 continue;
121 }
122 auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) {
123 allDebugInfos[fqInstanceName] = debugInfo;
124 if (debugInfo.pid >= 0) {
125 allPids[static_cast<pid_t>(debugInfo.pid)].clear();
126 }
127 });
128 if (!debugRet.isOk()) {
129 cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
130 << "debugging information cannot be retrieved:"
131 << debugRet.description() << endl;
132 }
133 }
134 for (auto &pair : allPids) {
135 pid_t serverPid = pair.first;
136 if (!getReferencedPids(serverPid, &allPids[serverPid])) {
137 std::cerr << "Warning: no information for PID " << serverPid
138 << ", are you root?" << std::endl;
139 }
140 }
141 for (const auto &fqInstanceName : fqInstanceNames) {
142 const auto pair = split(fqInstanceName, '/');
143 const auto &serviceName = pair.first;
144 const auto &instanceName = pair.second;
145 auto it = allDebugInfos.find(fqInstanceName);
146 if (it == allDebugInfos.end()) {
147 printColumn(stream,
148 serviceName,
149 instanceName,
150 mode,
151 "N/A",
152 "N/A",
153 ""
154 );
155 continue;
156 }
157 const DebugInfo &info = it->second;
158 printColumn(stream,
159 serviceName,
160 instanceName,
161 mode,
162 info.pid < 0 ? "N/A" : std::to_string(info.pid),
163 info.ptr == 0 ? "N/A" : toHexString(info.ptr),
164 info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]
165 );
166 }
167
168 });
169 if (!listRet.isOk()) {
170 cerr << "Error: Failed to list services for " << mode << ": "
171 << listRet.description() << endl;
172 }
173}
Yifan Hongf4bee842017-02-01 15:54:01 -0800174
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800175int dump() {
176 using namespace ::std;
177 using namespace ::android::hardware;
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800178
179 std::stringstream stream;
180
181 stream << "All services:" << endl;
182 stream << left;
Yifan Hongb24760f2017-02-03 13:40:04 -0800183 printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients");
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800184
Yifan Hongb24760f2017-02-03 13:40:04 -0800185 auto bManager = defaultServiceManager();
186 if (bManager == nullptr) {
187 cerr << "Failed to get defaultServiceManager()!" << endl;
188 } else {
189 dumpBinderized(stream, "hwbinder", bManager);
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800190 }
Yifan Hongb24760f2017-02-03 13:40:04 -0800191
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800192 cout << stream.rdbuf();
193 return 0;
194}
195
196int usage() {
197 using namespace ::std;
198 cerr
199 << "usage: lshal" << endl
200 << " To dump all hals." << endl
201 << "or:" << endl
202 << " lshal [-h|--help]" << endl
203 << " -h, --help: show this help information." << endl;
204 return -1;
205}
206
207int main(int argc, char **argv) {
208 static struct option longOptions[] = {
209 {"help", no_argument, 0, 'h' },
210 { 0, 0, 0, 0 }
211 };
212
213 int optionIndex;
214 int c;
215 optind = 1;
216 for (;;) {
217 // using getopt_long in case we want to add other options in the future
218 c = getopt_long(argc, argv, "h", longOptions, &optionIndex);
219 if (c == -1) {
220 break;
221 }
222 switch (c) {
223 case 'h': // falls through
224 default: // see unrecognized options
225 return usage();
226 }
227 }
228 return dump();
229
230}