blob: 9998a462a36229bc9ca0b610184f57f203896025 [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 Hongb7ddc9e2017-02-03 15:23:47 -080031using ::android::sp;
Yifan Hongb24760f2017-02-03 13:40:04 -080032using ::android::hardware::hidl_string;
Yifan Hongb7ddc9e2017-02-03 15:23:47 -080033using ::android::hidl::manager::V1_0::IServiceManager;
Yifan Hongb24760f2017-02-03 13:40:04 -080034
35template <typename A, typename B, typename C, typename D, typename E, typename F>
Yifan Hong85dd3ad2017-01-25 14:20:34 -080036void printColumn(std::stringstream &stream,
Yifan Hongb24760f2017-02-03 13:40:04 -080037 const A &a, const B &b, const C &c, const D &d, const E &, const F &f) {
Yifan Hong85dd3ad2017-01-25 14:20:34 -080038 using namespace ::std;
39 stream << left
40 << setw(70) << a << "\t"
41 << setw(20) << b << "\t"
42 << setw(10) << c << "\t"
43 << setw(5) << d << "\t"
Yifan Hongb24760f2017-02-03 13:40:04 -080044 // TODO(b/34984175): enable selecting columns
45 // << setw(16) << e << "\t"
46 << setw(0) << f
Yifan Hong85dd3ad2017-01-25 14:20:34 -080047 << endl;
48}
49
Yifan Hongb7ddc9e2017-02-03 15:23:47 -080050template <typename A>
51std::string join(const A &components, const std::string &separator) {
52 std::stringstream out;
53 bool first = true;
54 for (const auto &component : components) {
55 if (!first) {
56 out << separator;
57 }
58 out << component;
59
60 first = false;
61 }
62 return out.str();
63}
64
Yifan Hongf4bee842017-02-01 15:54:01 -080065std::string toHexString(uint64_t t) {
66 std::ostringstream os;
67 os << std::hex << std::setfill('0') << std::setw(16) << t;
68 return os.str();
69}
70
Yifan Hongb24760f2017-02-03 13:40:04 -080071std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) {
72 const char *pos = strchr(s.c_str(), c);
73 if (pos == nullptr) {
74 return {s, {}};
75 }
76 return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)};
77}
78
79bool getReferencedPids(
Yifan Hongf4bee842017-02-01 15:54:01 -080080 pid_t serverPid, std::map<uint64_t, std::string> *objects) {
81
82 std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
83 if (!ifs.is_open()) {
Yifan Hongb24760f2017-02-03 13:40:04 -080084 return false;
Yifan Hongf4bee842017-02-01 15:54:01 -080085 }
86
87 static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
88
89 std::string line;
90 std::smatch match;
91 while(getline(ifs, line)) {
92 if (!std::regex_search(line, match, prefix)) {
93 // the line doesn't start with the correct prefix
94 continue;
95 }
96 std::string ptrString = "0x" + match.str(2); // use number after c
97 uint64_t ptr;
98 if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
99 // Should not reach here, but just be tolerant.
100 std::cerr << "Could not parse number " << ptrString << std::endl;
101 continue;
102 }
103 const std::string proc = " proc ";
104 auto pos = line.rfind(proc);
105 if (pos != std::string::npos) {
106 (*objects)[ptr] += line.substr(pos + proc.size());
107 }
108 }
Yifan Hongb24760f2017-02-03 13:40:04 -0800109 return true;
Yifan Hongf4bee842017-02-01 15:54:01 -0800110}
111
Yifan Hongb7ddc9e2017-02-03 15:23:47 -0800112void dumpAllLibraries(std::stringstream &stream, const std::string &mode,
113 const sp<IServiceManager> &manager) {
114 using namespace ::std;
115 using namespace ::android::hardware;
116 using namespace ::android::hidl::manager::V1_0;
117 using namespace ::android::hidl::base::V1_0;
118 auto ret = manager->list([&] (const auto &fqInstanceNames) {
119 for (const auto &fqInstanceName : fqInstanceNames) {
120 const auto pair = split(fqInstanceName, '/');
121 const auto &serviceName = pair.first;
122 const auto &instanceName = pair.second;
123 printColumn(stream,
124 serviceName,
125 instanceName,
126 mode,
127 "N/A",
128 "N/A",
129 "N/A");
130 }
131 });
132 if (!ret.isOk()) {
133 cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
134 << ret.description() << endl;
135 }
136}
137
138void dumpPassthrough(std::stringstream &stream, const std::string &mode,
139 const sp<IServiceManager> &manager) {
140 using namespace ::std;
141 using namespace ::android::hardware;
142 using namespace ::android::hidl::manager::V1_0;
143 using namespace ::android::hidl::base::V1_0;
144 auto ret = manager->debugDump([&] (const auto &infos) {
145 for (const auto &info : infos) {
146
147 printColumn(stream,
148 info.interfaceName,
149 info.instanceName,
150 mode,
151 info.clientPids.size() == 1 ? std::to_string(info.clientPids[0]) : "N/A",
152 "N/A",
153 join(info.clientPids, " "));
154 }
155 });
156 if (!ret.isOk()) {
157 cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
158 << ret.description() << endl;
159 }
160}
161
Yifan Hongb24760f2017-02-03 13:40:04 -0800162void dumpBinderized(std::stringstream &stream, const std::string &mode,
163 const sp<IServiceManager> &manager) {
164 using namespace ::std;
165 using namespace ::android::hardware;
166 using namespace ::android::hidl::manager::V1_0;
167 using namespace ::android::hidl::base::V1_0;
168 auto listRet = manager->list([&] (const auto &fqInstanceNames) {
169 // server pid, .ptr value of binder object, child pids
170 std::map<std::string, DebugInfo> allDebugInfos;
171 std::map<pid_t, std::map<uint64_t, std::string>> allPids;
172 for (const auto &fqInstanceName : fqInstanceNames) {
173 const auto pair = split(fqInstanceName, '/');
174 const auto &serviceName = pair.first;
175 const auto &instanceName = pair.second;
176 auto getRet = manager->get(serviceName, instanceName);
177 if (!getRet.isOk()) {
178 cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
179 << "cannot be fetched from service manager:"
180 << getRet.description() << endl;
181 continue;
182 }
183 sp<IBase> service = getRet;
184 if (service == nullptr) {
185 cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
186 << "cannot be fetched from service manager (null)";
187 continue;
188 }
189 auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) {
190 allDebugInfos[fqInstanceName] = debugInfo;
191 if (debugInfo.pid >= 0) {
192 allPids[static_cast<pid_t>(debugInfo.pid)].clear();
193 }
194 });
195 if (!debugRet.isOk()) {
196 cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
197 << "debugging information cannot be retrieved:"
198 << debugRet.description() << endl;
199 }
200 }
201 for (auto &pair : allPids) {
202 pid_t serverPid = pair.first;
203 if (!getReferencedPids(serverPid, &allPids[serverPid])) {
204 std::cerr << "Warning: no information for PID " << serverPid
205 << ", are you root?" << std::endl;
206 }
207 }
208 for (const auto &fqInstanceName : fqInstanceNames) {
209 const auto pair = split(fqInstanceName, '/');
210 const auto &serviceName = pair.first;
211 const auto &instanceName = pair.second;
212 auto it = allDebugInfos.find(fqInstanceName);
213 if (it == allDebugInfos.end()) {
214 printColumn(stream,
215 serviceName,
216 instanceName,
217 mode,
218 "N/A",
219 "N/A",
220 ""
221 );
222 continue;
223 }
224 const DebugInfo &info = it->second;
225 printColumn(stream,
226 serviceName,
227 instanceName,
228 mode,
229 info.pid < 0 ? "N/A" : std::to_string(info.pid),
230 info.ptr == 0 ? "N/A" : toHexString(info.ptr),
231 info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]
232 );
233 }
234
235 });
236 if (!listRet.isOk()) {
237 cerr << "Error: Failed to list services for " << mode << ": "
238 << listRet.description() << endl;
239 }
240}
Yifan Hongf4bee842017-02-01 15:54:01 -0800241
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800242int dump() {
243 using namespace ::std;
244 using namespace ::android::hardware;
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800245
246 std::stringstream stream;
247
248 stream << "All services:" << endl;
249 stream << left;
Yifan Hongb24760f2017-02-03 13:40:04 -0800250 printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients");
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800251
Yifan Hongb24760f2017-02-03 13:40:04 -0800252 auto bManager = defaultServiceManager();
253 if (bManager == nullptr) {
254 cerr << "Failed to get defaultServiceManager()!" << endl;
255 } else {
256 dumpBinderized(stream, "hwbinder", bManager);
Yifan Hongb7ddc9e2017-02-03 15:23:47 -0800257 // Passthrough PIDs are registered to the binderized manager as well.
258 dumpPassthrough(stream, "passthrough", bManager);
259 }
260
261 auto pManager = getPassthroughServiceManager();
262 if (pManager == nullptr) {
263 cerr << "Failed to get getPassthroughServiceManager()!" << endl;
264 } else {
265 dumpAllLibraries(stream, "passthrough", pManager);
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800266 }
Yifan Hongb24760f2017-02-03 13:40:04 -0800267
Yifan Hong85dd3ad2017-01-25 14:20:34 -0800268 cout << stream.rdbuf();
269 return 0;
270}
271
272int usage() {
273 using namespace ::std;
274 cerr
275 << "usage: lshal" << endl
276 << " To dump all hals." << endl
277 << "or:" << endl
278 << " lshal [-h|--help]" << endl
279 << " -h, --help: show this help information." << endl;
280 return -1;
281}
282
283int main(int argc, char **argv) {
284 static struct option longOptions[] = {
285 {"help", no_argument, 0, 'h' },
286 { 0, 0, 0, 0 }
287 };
288
289 int optionIndex;
290 int c;
291 optind = 1;
292 for (;;) {
293 // using getopt_long in case we want to add other options in the future
294 c = getopt_long(argc, argv, "h", longOptions, &optionIndex);
295 if (c == -1) {
296 break;
297 }
298 switch (c) {
299 case 'h': // falls through
300 default: // see unrecognized options
301 return usage();
302 }
303 }
304 return dump();
305
306}