blob: 18b6b58a9e627a07079f12d06c344ec704408681 [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;
53 status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
54 if (err == NO_ERROR) {
55 return reply.readString16();
56 }
57 }
58 return String16();
59}
60
61static String8 good_old_string(const String16& src)
62{
63 String8 name8;
64 char ch8[2];
65 ch8[1] = 0;
66 for (unsigned j = 0; j < src.size(); j++) {
67 char16_t ch = src[j];
68 if (ch < 128) ch8[0] = (char)ch;
69 name8.append(ch8);
70 }
71 return name8;
72}
73
74int main(int argc, char* const argv[])
75{
Mike Lockwood94afecf2012-10-24 10:45:23 -070076 bool wantsUsage = false;
77 int result = 0;
Marco Nelissen07e95a82019-07-16 08:50:21 -070078
Mike Lockwood94afecf2012-10-24 10:45:23 -070079 while (1) {
Martijn Coenen3def1f22017-04-07 10:46:57 -070080 int ic = getopt(argc, argv, "h?");
Mike Lockwood94afecf2012-10-24 10:45:23 -070081 if (ic < 0)
82 break;
83
84 switch (ic) {
85 case 'h':
86 case '?':
87 wantsUsage = true;
88 break;
89 default:
90 aerr << "service: Unknown option -" << ic << endl;
91 wantsUsage = true;
92 result = 10;
93 break;
94 }
95 }
Martijn Coenen3def1f22017-04-07 10:46:57 -070096#ifdef VENDORSERVICES
97 ProcessState::initWithDriver("/dev/vndbinder");
98#endif
Martijn Coenend6480ca2017-04-05 14:16:12 -070099 sp<IServiceManager> sm = defaultServiceManager();
100 fflush(stdout);
Yi Kong19d5c002018-07-20 13:39:55 -0700101 if (sm == nullptr) {
Martijn Coenend6480ca2017-04-05 14:16:12 -0700102 aerr << "service: Unable to get default service manager!" << endl;
103 return 20;
104 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700105
Mike Lockwood94afecf2012-10-24 10:45:23 -0700106 if (optind >= argc) {
107 wantsUsage = true;
108 } else if (!wantsUsage) {
109 if (strcmp(argv[optind], "check") == 0) {
110 optind++;
111 if (optind < argc) {
112 sp<IBinder> service = sm->checkService(String16(argv[optind]));
113 aout << "Service " << argv[optind] <<
Yi Kong19d5c002018-07-20 13:39:55 -0700114 (service == nullptr ? ": not found" : ": found") << endl;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700115 } else {
116 aerr << "service: No service specified for check" << endl;
117 wantsUsage = true;
118 result = 10;
119 }
120 }
121 else if (strcmp(argv[optind], "list") == 0) {
122 Vector<String16> services = sm->listServices();
123 aout << "Found " << services.size() << " services:" << endl;
124 for (unsigned i = 0; i < services.size(); i++) {
125 String16 name = services[i];
126 sp<IBinder> service = sm->checkService(name);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700127 aout << i
128 << "\t" << good_old_string(name)
Mike Lockwood94afecf2012-10-24 10:45:23 -0700129 << ": [" << good_old_string(get_interface_name(service)) << "]"
130 << endl;
131 }
132 } else if (strcmp(argv[optind], "call") == 0) {
133 optind++;
134 if (optind+1 < argc) {
135 int serviceArg = optind;
136 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
137 String16 ifName = get_interface_name(service);
138 int32_t code = atoi(argv[optind++]);
Yi Kong19d5c002018-07-20 13:39:55 -0700139 if (service != nullptr && ifName.size() > 0) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700140 Parcel data, reply;
141
142 // the interface name is first
143 data.writeInterfaceToken(ifName);
144
145 // then the rest of the call arguments
146 while (optind < argc) {
147 if (strcmp(argv[optind], "i32") == 0) {
148 optind++;
149 if (optind >= argc) {
150 aerr << "service: no integer supplied for 'i32'" << endl;
151 wantsUsage = true;
152 result = 10;
153 break;
154 }
155 data.writeInt32(atoi(argv[optind++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700156 } else if (strcmp(argv[optind], "i64") == 0) {
157 optind++;
158 if (optind >= argc) {
159 aerr << "service: no integer supplied for 'i64'" << endl;
160 wantsUsage = true;
161 result = 10;
162 break;
163 }
164 data.writeInt64(atoll(argv[optind++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700165 } else if (strcmp(argv[optind], "s16") == 0) {
166 optind++;
167 if (optind >= argc) {
168 aerr << "service: no string supplied for 's16'" << endl;
169 wantsUsage = true;
170 result = 10;
171 break;
172 }
173 data.writeString16(String16(argv[optind++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700174 } else if (strcmp(argv[optind], "f") == 0) {
175 optind++;
176 if (optind >= argc) {
177 aerr << "service: no number supplied for 'f'" << endl;
178 wantsUsage = true;
179 result = 10;
180 break;
181 }
182 data.writeFloat(atof(argv[optind++]));
183 } else if (strcmp(argv[optind], "d") == 0) {
184 optind++;
185 if (optind >= argc) {
186 aerr << "service: no number supplied for 'd'" << endl;
187 wantsUsage = true;
188 result = 10;
189 break;
190 }
191 data.writeDouble(atof(argv[optind++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700192 } else if (strcmp(argv[optind], "null") == 0) {
193 optind++;
Yi Kong19d5c002018-07-20 13:39:55 -0700194 data.writeStrongBinder(nullptr);
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700195 } else if (strcmp(argv[optind], "fd") == 0) {
196 optind++;
197 if (optind >= argc) {
198 aerr << "service: no path supplied for 'fd'" << endl;
199 wantsUsage = true;
200 result = 10;
201 break;
202 }
203 const char *path = argv[optind++];
204 int fd = open(path, O_RDONLY);
205 if (fd < 0) {
206 aerr << "service: could not open '" << path << "'" << endl;
207 wantsUsage = true;
208 result = 10;
209 break;
210 }
211 data.writeFileDescriptor(fd, true /* take ownership */);
212 } else if (strcmp(argv[optind], "afd") == 0) {
213 optind++;
214 if (optind >= argc) {
215 aerr << "service: no path supplied for 'afd'" << endl;
216 wantsUsage = true;
217 result = 10;
218 break;
219 }
220 const char *path = argv[optind++];
221 int fd = open(path, O_RDONLY);
222 struct stat statbuf;
223 if (fd < 0 || fstat(fd, &statbuf) != 0) {
224 aerr << "service: could not open or stat '" << path << "'" << endl;
225 wantsUsage = true;
226 result = 10;
227 break;
228 }
229 int afd = ashmem_create_region("test", statbuf.st_size);
230 void* ptr = mmap(NULL, statbuf.st_size,
231 PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
232 read(fd, ptr, statbuf.st_size);
233 close(fd);
234 data.writeFileDescriptor(afd, true /* take ownership */);
235 } else if (strcmp(argv[optind], "nfd") == 0) {
236 optind++;
237 if (optind >= argc) {
238 aerr << "service: no file descriptor supplied for 'nfd'" << endl;
239 wantsUsage = true;
240 result = 10;
241 break;
242 }
243 data.writeFileDescriptor(
244 atoi(argv[optind++]), true /* take ownership */);
245
Mike Lockwood94afecf2012-10-24 10:45:23 -0700246 } else if (strcmp(argv[optind], "intent") == 0) {
Marco Nelissen07e95a82019-07-16 08:50:21 -0700247
248 char* action = nullptr;
249 char* dataArg = nullptr;
250 char* type = nullptr;
251 int launchFlags = 0;
252 char* component = nullptr;
253 int categoryCount = 0;
254 char* categories[16];
255
256 char* context1 = nullptr;
257
Mike Lockwood94afecf2012-10-24 10:45:23 -0700258 optind++;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700259
260 while (optind < argc)
261 {
262 char* key = strtok_r(argv[optind], "=", &context1);
263 char* value = strtok_r(nullptr, "=", &context1);
264
Mike Lockwood94afecf2012-10-24 10:45:23 -0700265 // we have reached the end of the XXX=XXX args.
Yi Kong19d5c002018-07-20 13:39:55 -0700266 if (key == nullptr) break;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700267
268 if (strcmp(key, "action") == 0)
269 {
270 action = value;
271 }
272 else if (strcmp(key, "data") == 0)
273 {
274 dataArg = value;
275 }
276 else if (strcmp(key, "type") == 0)
277 {
278 type = value;
279 }
280 else if (strcmp(key, "launchFlags") == 0)
281 {
282 launchFlags = atoi(value);
283 }
284 else if (strcmp(key, "component") == 0)
285 {
286 component = value;
287 }
288 else if (strcmp(key, "categories") == 0)
289 {
290 char* context2 = nullptr;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700291 categories[categoryCount] = strtok_r(value, ",", &context2);
292
293 while (categories[categoryCount] != nullptr)
294 {
295 categoryCount++;
296 categories[categoryCount] = strtok_r(nullptr, ",", &context2);
297 }
298 }
299
Mike Lockwood94afecf2012-10-24 10:45:23 -0700300 optind++;
Marco Nelissen07e95a82019-07-16 08:50:21 -0700301 }
302
Mike Lockwood94afecf2012-10-24 10:45:23 -0700303 writeString16(data, action);
304 writeString16(data, dataArg);
305 writeString16(data, type);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700306 data.writeInt32(launchFlags);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700307 writeString16(data, component);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700308
Mike Lockwood94afecf2012-10-24 10:45:23 -0700309 if (categoryCount > 0)
310 {
311 data.writeInt32(categoryCount);
312 for (int i = 0 ; i < categoryCount ; i++)
313 {
314 writeString16(data, categories[i]);
315 }
316 }
317 else
318 {
319 data.writeInt32(0);
Marco Nelissen07e95a82019-07-16 08:50:21 -0700320 }
321
Mike Lockwood94afecf2012-10-24 10:45:23 -0700322 // for now just set the extra field to be null.
Marco Nelissen07e95a82019-07-16 08:50:21 -0700323 data.writeInt32(-1);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700324 } else {
325 aerr << "service: unknown option " << argv[optind] << endl;
326 wantsUsage = true;
327 result = 10;
328 break;
329 }
330 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700331
Mike Lockwood94afecf2012-10-24 10:45:23 -0700332 service->transact(code, data, &reply);
333 aout << "Result: " << reply << endl;
334 } else {
335 aerr << "service: Service " << argv[serviceArg]
336 << " does not exist" << endl;
337 result = 10;
338 }
339 } else {
340 if (optind < argc) {
341 aerr << "service: No service specified for call" << endl;
342 } else {
343 aerr << "service: No code specified for call" << endl;
344 }
345 wantsUsage = true;
346 result = 10;
347 }
348 } else {
349 aerr << "service: Unknown command " << argv[optind] << endl;
350 wantsUsage = true;
351 result = 10;
352 }
353 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700354
Mike Lockwood94afecf2012-10-24 10:45:23 -0700355 if (wantsUsage) {
356 aout << "Usage: service [-h|-?]\n"
357 " service list\n"
358 " service check SERVICE\n"
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700359 " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
360 " | fd f | nfd n | afd f ] ...\n"
Mike Lockwood94afecf2012-10-24 10:45:23 -0700361 "Options:\n"
Jeff Brownd46898f2015-04-06 19:42:43 -0700362 " i32: Write the 32-bit integer N into the send parcel.\n"
363 " i64: Write the 64-bit integer N into the send parcel.\n"
364 " f: Write the 32-bit single-precision number N into the send parcel.\n"
365 " d: Write the 64-bit double-precision number N into the send parcel.\n"
Marco Nelissenb9ec70e2018-06-07 11:31:03 -0700366 " s16: Write the UTF-16 string STR into the send parcel.\n"
367 " null: Write a null binder into the send parcel.\n"
368 " fd: Write a file descriptor for the file f to the send parcel.\n"
369 " nfd: Write file descriptor n to the send parcel.\n"
370 " afd: Write an ashmem file descriptor for a region containing the data from"
371 " file f to the send parcel.\n";
Mike Lockwood94afecf2012-10-24 10:45:23 -0700372// " intent: Write and Intent int the send parcel. ARGS can be\n"
373// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
374 return result;
375 }
Marco Nelissen07e95a82019-07-16 08:50:21 -0700376
Mike Lockwood94afecf2012-10-24 10:45:23 -0700377 return result;
378}
379