blob: 0b00c2da088a41575b4bdcec4f880d7eebcb7f76 [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
Mike Lockwood94afecf2012-10-24 10:45:23 -070080 while (1) {
Martijn Coenen3def1f22017-04-07 10:46:57 -070081 int ic = getopt(argc, argv, "h?");
Mike Lockwood94afecf2012-10-24 10:45:23 -070082 if (ic < 0)
83 break;
84
85 switch (ic) {
86 case 'h':
87 case '?':
88 wantsUsage = true;
89 break;
90 default:
91 aerr << "service: Unknown option -" << ic << endl;
92 wantsUsage = true;
93 result = 10;
94 break;
95 }
96 }
Martijn Coenen3def1f22017-04-07 10:46:57 -070097#ifdef VENDORSERVICES
98 ProcessState::initWithDriver("/dev/vndbinder");
99#endif
Yifan Hong86cf0532021-06-16 22:56:50 -0700100#ifndef __ANDROID__
101 setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
102#endif
Martijn Coenend6480ca2017-04-05 14:16:12 -0700103 sp<IServiceManager> sm = defaultServiceManager();
104 fflush(stdout);
Yi Kong19d5c002018-07-20 13:39:55 -0700105 if (sm == nullptr) {
Martijn Coenend6480ca2017-04-05 14:16:12 -0700106 aerr << "service: Unable to get default service manager!" << endl;
107 return 20;
108 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700109
Mike Lockwood94afecf2012-10-24 10:45:23 -0700110 if (optind >= argc) {
111 wantsUsage = true;
112 } else if (!wantsUsage) {
113 if (strcmp(argv[optind], "check") == 0) {
114 optind++;
115 if (optind < argc) {
116 sp<IBinder> service = sm->checkService(String16(argv[optind]));
117 aout << "Service " << argv[optind] <<
Yi Kong19d5c002018-07-20 13:39:55 -0700118 (service == nullptr ? ": not found" : ": found") << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700119 } else {
120 aerr << "service: No service specified for check" << endl;
121 wantsUsage = true;
122 result = 10;
123 }
124 }
125 else if (strcmp(argv[optind], "list") == 0) {
126 Vector<String16> services = sm->listServices();
127 aout << "Found " << services.size() << " services:" << endl;
128 for (unsigned i = 0; i < services.size(); i++) {
129 String16 name = services[i];
130 sp<IBinder> service = sm->checkService(name);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700131 aout << i
132 << "\t" << good_old_string(name)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700133 << ": [" << good_old_string(get_interface_name(service)) << "]"
134 << endl;
135 }
136 } else if (strcmp(argv[optind], "call") == 0) {
137 optind++;
138 if (optind+1 < argc) {
139 int serviceArg = optind;
140 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
141 String16 ifName = get_interface_name(service);
142 int32_t code = atoi(argv[optind++]);
Yi Kong19d5c002018-07-20 13:39:55 -0700143 if (service != nullptr && ifName.size() > 0) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700144 Parcel data, reply;
Yifan Hong86cf0532021-06-16 22:56:50 -0700145 data.markForBinder(service);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700146
147 // the interface name is first
148 data.writeInterfaceToken(ifName);
149
150 // then the rest of the call arguments
151 while (optind < argc) {
152 if (strcmp(argv[optind], "i32") == 0) {
153 optind++;
154 if (optind >= argc) {
155 aerr << "service: no integer supplied for 'i32'" << endl;
156 wantsUsage = true;
157 result = 10;
158 break;
159 }
160 data.writeInt32(atoi(argv[optind++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700161 } else if (strcmp(argv[optind], "i64") == 0) {
162 optind++;
163 if (optind >= argc) {
164 aerr << "service: no integer supplied for 'i64'" << endl;
165 wantsUsage = true;
166 result = 10;
167 break;
168 }
169 data.writeInt64(atoll(argv[optind++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700170 } else if (strcmp(argv[optind], "s16") == 0) {
171 optind++;
172 if (optind >= argc) {
173 aerr << "service: no string supplied for 's16'" << endl;
174 wantsUsage = true;
175 result = 10;
176 break;
177 }
178 data.writeString16(String16(argv[optind++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700179 } else if (strcmp(argv[optind], "f") == 0) {
180 optind++;
181 if (optind >= argc) {
182 aerr << "service: no number supplied for 'f'" << endl;
183 wantsUsage = true;
184 result = 10;
185 break;
186 }
187 data.writeFloat(atof(argv[optind++]));
188 } else if (strcmp(argv[optind], "d") == 0) {
189 optind++;
190 if (optind >= argc) {
191 aerr << "service: no number supplied for 'd'" << endl;
192 wantsUsage = true;
193 result = 10;
194 break;
195 }
196 data.writeDouble(atof(argv[optind++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700197 } else if (strcmp(argv[optind], "null") == 0) {
198 optind++;
Yi Kong19d5c002018-07-20 13:39:55 -0700199 data.writeStrongBinder(nullptr);
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700200 } else if (strcmp(argv[optind], "fd") == 0) {
201 optind++;
202 if (optind >= argc) {
203 aerr << "service: no path supplied for 'fd'" << endl;
204 wantsUsage = true;
205 result = 10;
206 break;
207 }
208 const char *path = argv[optind++];
209 int fd = open(path, O_RDONLY);
210 if (fd < 0) {
211 aerr << "service: could not open '" << path << "'" << endl;
212 wantsUsage = true;
213 result = 10;
214 break;
215 }
216 data.writeFileDescriptor(fd, true /* take ownership */);
217 } else if (strcmp(argv[optind], "afd") == 0) {
218 optind++;
219 if (optind >= argc) {
220 aerr << "service: no path supplied for 'afd'" << endl;
221 wantsUsage = true;
222 result = 10;
223 break;
224 }
225 const char *path = argv[optind++];
226 int fd = open(path, O_RDONLY);
227 struct stat statbuf;
228 if (fd < 0 || fstat(fd, &statbuf) != 0) {
229 aerr << "service: could not open or stat '" << path << "'" << endl;
230 wantsUsage = true;
231 result = 10;
232 break;
233 }
234 int afd = ashmem_create_region("test", statbuf.st_size);
235 void* ptr = mmap(NULL, statbuf.st_size,
236 PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
Yifan Hong86cf0532021-06-16 22:56:50 -0700237 (void)read(fd, ptr, statbuf.st_size);
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700238 close(fd);
239 data.writeFileDescriptor(afd, true /* take ownership */);
240 } else if (strcmp(argv[optind], "nfd") == 0) {
241 optind++;
242 if (optind >= argc) {
243 aerr << "service: no file descriptor supplied for 'nfd'" << endl;
244 wantsUsage = true;
245 result = 10;
246 break;
247 }
248 data.writeFileDescriptor(
249 atoi(argv[optind++]), true /* take ownership */);
250
Mike Lockwood94afecf2012-10-24 10:45:23 -0700251 } else if (strcmp(argv[optind], "intent") == 0) {
Marco Nelissen07e95a82019-07-16 08:50:21 -0700252
253 char* action = nullptr;
254 char* dataArg = nullptr;
255 char* type = nullptr;
256 int launchFlags = 0;
257 char* component = nullptr;
258 int categoryCount = 0;
259 char* categories[16];
260
261 char* context1 = nullptr;
262
Mike Lockwood94afecf2012-10-24 10:45:23 -0700263 optind++;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700264
265 while (optind < argc)
266 {
267 char* key = strtok_r(argv[optind], "=", &context1);
268 char* value = strtok_r(nullptr, "=", &context1);
269
Mike Lockwood94afecf2012-10-24 10:45:23 -0700270 // we have reached the end of the XXX=XXX args.
Yi Kong19d5c002018-07-20 13:39:55 -0700271 if (key == nullptr) break;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700272
273 if (strcmp(key, "action") == 0)
274 {
275 action = value;
276 }
277 else if (strcmp(key, "data") == 0)
278 {
279 dataArg = value;
280 }
281 else if (strcmp(key, "type") == 0)
282 {
283 type = value;
284 }
285 else if (strcmp(key, "launchFlags") == 0)
286 {
287 launchFlags = atoi(value);
288 }
289 else if (strcmp(key, "component") == 0)
290 {
291 component = value;
292 }
293 else if (strcmp(key, "categories") == 0)
294 {
295 char* context2 = nullptr;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700296 categories[categoryCount] = strtok_r(value, ",", &context2);
297
298 while (categories[categoryCount] != nullptr)
299 {
300 categoryCount++;
301 categories[categoryCount] = strtok_r(nullptr, ",", &context2);
302 }
303 }
304
Mike Lockwood94afecf2012-10-24 10:45:23 -0700305 optind++;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700306 }
307
Mike Lockwood94afecf2012-10-24 10:45:23 -0700308 writeString16(data, action);
309 writeString16(data, dataArg);
310 writeString16(data, type);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700311 data.writeInt32(launchFlags);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700312 writeString16(data, component);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700313
Mike Lockwood94afecf2012-10-24 10:45:23 -0700314 if (categoryCount > 0)
315 {
316 data.writeInt32(categoryCount);
317 for (int i = 0 ; i < categoryCount ; i++)
318 {
319 writeString16(data, categories[i]);
320 }
321 }
322 else
323 {
324 data.writeInt32(0);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700325 }
326
Mike Lockwood94afecf2012-10-24 10:45:23 -0700327 // for now just set the extra field to be null.
Marco Nelissen07e95a82019-07-16 08:50:21 -0700328 data.writeInt32(-1);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700329 } else {
330 aerr << "service: unknown option " << argv[optind] << endl;
331 wantsUsage = true;
332 result = 10;
333 break;
334 }
335 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700336
Mike Lockwood94afecf2012-10-24 10:45:23 -0700337 service->transact(code, data, &reply);
338 aout << "Result: " << reply << endl;
339 } else {
340 aerr << "service: Service " << argv[serviceArg]
341 << " does not exist" << endl;
342 result = 10;
343 }
344 } else {
345 if (optind < argc) {
346 aerr << "service: No service specified for call" << endl;
347 } else {
348 aerr << "service: No code specified for call" << endl;
349 }
350 wantsUsage = true;
351 result = 10;
352 }
353 } else {
354 aerr << "service: Unknown command " << argv[optind] << endl;
355 wantsUsage = true;
356 result = 10;
357 }
358 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700359
Mike Lockwood94afecf2012-10-24 10:45:23 -0700360 if (wantsUsage) {
361 aout << "Usage: service [-h|-?]\n"
362 " service list\n"
363 " service check SERVICE\n"
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700364 " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
365 " | fd f | nfd n | afd f ] ...\n"
Mike Lockwood94afecf2012-10-24 10:45:23 -0700366 "Options:\n"
Jeff Brownd46898f2015-04-06 19:42:43 -0700367 " i32: Write the 32-bit integer N into the send parcel.\n"
368 " i64: Write the 64-bit integer N into the send parcel.\n"
369 " f: Write the 32-bit single-precision number N into the send parcel.\n"
370 " d: Write the 64-bit double-precision number N into the send parcel.\n"
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700371 " s16: Write the UTF-16 string STR into the send parcel.\n"
372 " null: Write a null binder into the send parcel.\n"
373 " fd: Write a file descriptor for the file f to the send parcel.\n"
374 " nfd: Write file descriptor n to the send parcel.\n"
375 " afd: Write an ashmem file descriptor for a region containing the data from"
376 " file f to the send parcel.\n";
Mike Lockwood94afecf2012-10-24 10:45:23 -0700377// " intent: Write and Intent int the send parcel. ARGS can be\n"
378// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
379 return result;
380 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700381
Mike Lockwood94afecf2012-10-24 10:45:23 -0700382 return result;
383}
384