blob: fdbe85b4a89e55658c58aa921b26ca019c1a27b0 [file] [log] [blame]
Mike Lockwood94afecf2012-10-24 10:45:23 -07001/*
Mathias Agopian002e1e52013-05-06 20:20:50 -07002 * Copyright 2013 The Android Open Source Project
Mike Lockwood94afecf2012-10-24 10:45:23 -07003 *
Mathias Agopian002e1e52013-05-06 20:20:50 -07004 * 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.
Mike Lockwood94afecf2012-10-24 10:45:23 -070015 */
Mathias Agopian002e1e52013-05-06 20:20:50 -070016
Mike Lockwood94afecf2012-10-24 10:45:23 -070017#include <binder/Parcel.h>
18#include <binder/ProcessState.h>
19#include <binder/IServiceManager.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070020#include <binder/TextOutput.h>
Marco Nelissenb9ec70e2018-06-07 11:31:03 -070021#include <cutils/ashmem.h>
Mike Lockwood94afecf2012-10-24 10:45:23 -070022
23#include <getopt.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
Marco Nelissenb9ec70e2018-06-07 11:31:03 -070028#include <sys/mman.h>
Mike Lockwood94afecf2012-10-24 10:45:23 -070029#include <sys/time.h>
Marco Nelissenb9ec70e2018-06-07 11:31:03 -070030#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
Mike Lockwood94afecf2012-10-24 10:45:23 -070033
34using namespace android;
35
36void writeString16(Parcel& parcel, const char* string)
37{
Yi Kong19d5c002018-07-20 13:39:55 -070038 if (string != nullptr)
Mike Lockwood94afecf2012-10-24 10:45:23 -070039 {
40 parcel.writeString16(String16(string));
41 }
42 else
43 {
44 parcel.writeInt32(-1);
45 }
46}
47
48// get the name of the generic interface we hold a reference to
49static String16 get_interface_name(sp<IBinder> service)
50{
Yi Kong19d5c002018-07-20 13:39:55 -070051 if (service != nullptr) {
Mike Lockwood94afecf2012-10-24 10:45:23 -070052 Parcel data, reply;
Yifan Hong86cf0532021-06-16 22:56:50 -070053 data.markForBinder(service);
Mike Lockwood94afecf2012-10-24 10:45:23 -070054 status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
55 if (err == NO_ERROR) {
56 return reply.readString16();
57 }
58 }
59 return String16();
60}
61
62static String8 good_old_string(const String16& src)
63{
64 String8 name8;
65 char ch8[2];
66 ch8[1] = 0;
67 for (unsigned j = 0; j < src.size(); j++) {
68 char16_t ch = src[j];
69 if (ch < 128) ch8[0] = (char)ch;
70 name8.append(ch8);
71 }
72 return name8;
73}
74
75int main(int argc, char* const argv[])
76{
Mike Lockwood94afecf2012-10-24 10:45:23 -070077 bool wantsUsage = false;
78 int result = 0;
Marco Nelissen07e95a82019-07-16 08:50:21 -070079
Tony Guo51cbe7e2021-10-15 14:00:07 +080080 /* Strip path off the program name. */
81 char* prog_name = basename(argv[0]);
82
Mike Lockwood94afecf2012-10-24 10:45:23 -070083 while (1) {
Martijn Coenen3def1f22017-04-07 10:46:57 -070084 int ic = getopt(argc, argv, "h?");
Mike Lockwood94afecf2012-10-24 10:45:23 -070085 if (ic < 0)
86 break;
87
88 switch (ic) {
89 case 'h':
90 case '?':
91 wantsUsage = true;
92 break;
93 default:
Tony Guo51cbe7e2021-10-15 14:00:07 +080094 aerr << prog_name << ": Unknown option -" << ic << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -070095 wantsUsage = true;
96 result = 10;
97 break;
98 }
99 }
Martijn Coenen3def1f22017-04-07 10:46:57 -0700100#ifdef VENDORSERVICES
101 ProcessState::initWithDriver("/dev/vndbinder");
102#endif
Yifan Hong86cf0532021-06-16 22:56:50 -0700103#ifndef __ANDROID__
104 setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
105#endif
Martijn Coenend6480ca2017-04-05 14:16:12 -0700106 sp<IServiceManager> sm = defaultServiceManager();
107 fflush(stdout);
Yi Kong19d5c002018-07-20 13:39:55 -0700108 if (sm == nullptr) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800109 aerr << prog_name << ": Unable to get default service manager!" << endl;
Martijn Coenend6480ca2017-04-05 14:16:12 -0700110 return 20;
111 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700112
Mike Lockwood94afecf2012-10-24 10:45:23 -0700113 if (optind >= argc) {
114 wantsUsage = true;
115 } else if (!wantsUsage) {
116 if (strcmp(argv[optind], "check") == 0) {
117 optind++;
118 if (optind < argc) {
119 sp<IBinder> service = sm->checkService(String16(argv[optind]));
120 aout << "Service " << argv[optind] <<
Yi Kong19d5c002018-07-20 13:39:55 -0700121 (service == nullptr ? ": not found" : ": found") << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700122 } else {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800123 aerr << prog_name << ": No service specified for check" << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700124 wantsUsage = true;
125 result = 10;
126 }
127 }
128 else if (strcmp(argv[optind], "list") == 0) {
129 Vector<String16> services = sm->listServices();
130 aout << "Found " << services.size() << " services:" << endl;
131 for (unsigned i = 0; i < services.size(); i++) {
132 String16 name = services[i];
133 sp<IBinder> service = sm->checkService(name);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700134 aout << i
135 << "\t" << good_old_string(name)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700136 << ": [" << good_old_string(get_interface_name(service)) << "]"
137 << endl;
138 }
139 } else if (strcmp(argv[optind], "call") == 0) {
140 optind++;
141 if (optind+1 < argc) {
142 int serviceArg = optind;
143 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
144 String16 ifName = get_interface_name(service);
145 int32_t code = atoi(argv[optind++]);
Yi Kong19d5c002018-07-20 13:39:55 -0700146 if (service != nullptr && ifName.size() > 0) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700147 Parcel data, reply;
Yifan Hong86cf0532021-06-16 22:56:50 -0700148 data.markForBinder(service);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700149
150 // the interface name is first
151 data.writeInterfaceToken(ifName);
152
153 // then the rest of the call arguments
154 while (optind < argc) {
155 if (strcmp(argv[optind], "i32") == 0) {
156 optind++;
157 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800158 aerr << prog_name << ": no integer supplied for 'i32'" << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700159 wantsUsage = true;
160 result = 10;
161 break;
162 }
163 data.writeInt32(atoi(argv[optind++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700164 } else if (strcmp(argv[optind], "i64") == 0) {
165 optind++;
166 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800167 aerr << prog_name << ": no integer supplied for 'i64'" << endl;
Jeff Brownd46898f2015-04-06 19:42:43 -0700168 wantsUsage = true;
169 result = 10;
170 break;
171 }
172 data.writeInt64(atoll(argv[optind++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700173 } else if (strcmp(argv[optind], "s16") == 0) {
174 optind++;
175 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800176 aerr << prog_name << ": no string supplied for 's16'" << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700177 wantsUsage = true;
178 result = 10;
179 break;
180 }
181 data.writeString16(String16(argv[optind++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700182 } else if (strcmp(argv[optind], "f") == 0) {
183 optind++;
184 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800185 aerr << prog_name << ": no number supplied for 'f'" << endl;
Jeff Brownd46898f2015-04-06 19:42:43 -0700186 wantsUsage = true;
187 result = 10;
188 break;
189 }
190 data.writeFloat(atof(argv[optind++]));
191 } else if (strcmp(argv[optind], "d") == 0) {
192 optind++;
193 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800194 aerr << prog_name << ": no number supplied for 'd'" << endl;
Jeff Brownd46898f2015-04-06 19:42:43 -0700195 wantsUsage = true;
196 result = 10;
197 break;
198 }
199 data.writeDouble(atof(argv[optind++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700200 } else if (strcmp(argv[optind], "null") == 0) {
201 optind++;
Yi Kong19d5c002018-07-20 13:39:55 -0700202 data.writeStrongBinder(nullptr);
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700203 } else if (strcmp(argv[optind], "fd") == 0) {
204 optind++;
205 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800206 aerr << prog_name << ": no path supplied for 'fd'" << endl;
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700207 wantsUsage = true;
208 result = 10;
209 break;
210 }
211 const char *path = argv[optind++];
212 int fd = open(path, O_RDONLY);
213 if (fd < 0) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800214 aerr << prog_name << ": could not open '" << path << "'" << endl;
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700215 wantsUsage = true;
216 result = 10;
217 break;
218 }
219 data.writeFileDescriptor(fd, true /* take ownership */);
220 } else if (strcmp(argv[optind], "afd") == 0) {
221 optind++;
222 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800223 aerr << prog_name << ": no path supplied for 'afd'" << endl;
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700224 wantsUsage = true;
225 result = 10;
226 break;
227 }
228 const char *path = argv[optind++];
229 int fd = open(path, O_RDONLY);
230 struct stat statbuf;
231 if (fd < 0 || fstat(fd, &statbuf) != 0) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800232 aerr << prog_name << ": could not open or stat"
233 << " '" << path << "'" << endl;
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700234 wantsUsage = true;
235 result = 10;
236 break;
237 }
238 int afd = ashmem_create_region("test", statbuf.st_size);
239 void* ptr = mmap(NULL, statbuf.st_size,
240 PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
Yifan Hong86cf0532021-06-16 22:56:50 -0700241 (void)read(fd, ptr, statbuf.st_size);
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700242 close(fd);
243 data.writeFileDescriptor(afd, true /* take ownership */);
244 } else if (strcmp(argv[optind], "nfd") == 0) {
245 optind++;
246 if (optind >= argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800247 aerr << prog_name << ": no file descriptor supplied for"
248 << " 'nfd'" << endl;
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700249 wantsUsage = true;
250 result = 10;
251 break;
252 }
253 data.writeFileDescriptor(
254 atoi(argv[optind++]), true /* take ownership */);
255
Mike Lockwood94afecf2012-10-24 10:45:23 -0700256 } else if (strcmp(argv[optind], "intent") == 0) {
Marco Nelissen07e95a82019-07-16 08:50:21 -0700257
258 char* action = nullptr;
259 char* dataArg = nullptr;
260 char* type = nullptr;
261 int launchFlags = 0;
262 char* component = nullptr;
263 int categoryCount = 0;
264 char* categories[16];
265
266 char* context1 = nullptr;
267
Mike Lockwood94afecf2012-10-24 10:45:23 -0700268 optind++;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700269
270 while (optind < argc)
271 {
272 char* key = strtok_r(argv[optind], "=", &context1);
273 char* value = strtok_r(nullptr, "=", &context1);
274
Mike Lockwood94afecf2012-10-24 10:45:23 -0700275 // we have reached the end of the XXX=XXX args.
Yi Kong19d5c002018-07-20 13:39:55 -0700276 if (key == nullptr) break;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700277
278 if (strcmp(key, "action") == 0)
279 {
280 action = value;
281 }
282 else if (strcmp(key, "data") == 0)
283 {
284 dataArg = value;
285 }
286 else if (strcmp(key, "type") == 0)
287 {
288 type = value;
289 }
290 else if (strcmp(key, "launchFlags") == 0)
291 {
292 launchFlags = atoi(value);
293 }
294 else if (strcmp(key, "component") == 0)
295 {
296 component = value;
297 }
298 else if (strcmp(key, "categories") == 0)
299 {
300 char* context2 = nullptr;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700301 categories[categoryCount] = strtok_r(value, ",", &context2);
302
303 while (categories[categoryCount] != nullptr)
304 {
305 categoryCount++;
306 categories[categoryCount] = strtok_r(nullptr, ",", &context2);
307 }
308 }
309
Mike Lockwood94afecf2012-10-24 10:45:23 -0700310 optind++;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700311 }
312
Mike Lockwood94afecf2012-10-24 10:45:23 -0700313 writeString16(data, action);
314 writeString16(data, dataArg);
315 writeString16(data, type);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700316 data.writeInt32(launchFlags);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700317 writeString16(data, component);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700318
Mike Lockwood94afecf2012-10-24 10:45:23 -0700319 if (categoryCount > 0)
320 {
321 data.writeInt32(categoryCount);
322 for (int i = 0 ; i < categoryCount ; i++)
323 {
324 writeString16(data, categories[i]);
325 }
326 }
327 else
328 {
329 data.writeInt32(0);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700330 }
331
Mike Lockwood94afecf2012-10-24 10:45:23 -0700332 // for now just set the extra field to be null.
Marco Nelissen07e95a82019-07-16 08:50:21 -0700333 data.writeInt32(-1);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700334 } else {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800335 aerr << prog_name << ": unknown option " << argv[optind] << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700336 wantsUsage = true;
337 result = 10;
338 break;
339 }
340 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700341
Mike Lockwood94afecf2012-10-24 10:45:23 -0700342 service->transact(code, data, &reply);
343 aout << "Result: " << reply << endl;
344 } else {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800345 aerr << prog_name << ": Service " << argv[serviceArg]
Mike Lockwood94afecf2012-10-24 10:45:23 -0700346 << " does not exist" << endl;
347 result = 10;
348 }
349 } else {
350 if (optind < argc) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800351 aerr << prog_name << ": No service specified for call" << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700352 } else {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800353 aerr << prog_name << ": No code specified for call" << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700354 }
355 wantsUsage = true;
356 result = 10;
357 }
358 } else {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800359 aerr << prog_name << ": Unknown command " << argv[optind] << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700360 wantsUsage = true;
361 result = 10;
362 }
363 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700364
Mike Lockwood94afecf2012-10-24 10:45:23 -0700365 if (wantsUsage) {
Tony Guo51cbe7e2021-10-15 14:00:07 +0800366 aout << "Usage: " << prog_name << " [-h|-?]\n"
367 " " << prog_name << " list\n"
368 " " << prog_name << " check SERVICE\n"
369 " " << prog_name << " call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR"
370 " | null | fd f | nfd n | afd f ] ...\n"
Mike Lockwood94afecf2012-10-24 10:45:23 -0700371 "Options:\n"
Jeff Brownd46898f2015-04-06 19:42:43 -0700372 " i32: Write the 32-bit integer N into the send parcel.\n"
373 " i64: Write the 64-bit integer N into the send parcel.\n"
Tony Guo51cbe7e2021-10-15 14:00:07 +0800374 " f: Write the 32-bit single-precision number N into the send parcel.\n"
375 " d: Write the 64-bit double-precision number N into the send parcel.\n"
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700376 " s16: Write the UTF-16 string STR into the send parcel.\n"
377 " null: Write a null binder into the send parcel.\n"
Tony Guo51cbe7e2021-10-15 14:00:07 +0800378 " fd: Write a file descriptor for the file f into the send parcel.\n"
379 " nfd: Write the file descriptor n into the send parcel.\n"
380 " afd: Write an ashmem file descriptor for a region containing the data from\n"
381 " file f into the send parcel.\n";
382// " intent: Write an Intent into the send parcel. ARGS can be\n"
Mike Lockwood94afecf2012-10-24 10:45:23 -0700383// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
384 return result;
385 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700386
Mike Lockwood94afecf2012-10-24 10:45:23 -0700387 return result;
388}
389