1 /*
2 * Copyright 2013 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 #include <binder/Parcel.h>
18 #include <binder/ProcessState.h>
19 #include <binder/IServiceManager.h>
20 #include <binder/TextOutput.h>
21 #include <cutils/ashmem.h>
22
23 #include <getopt.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/mman.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33
34 using namespace android;
35
writeString16(Parcel & parcel,const char * string)36 void writeString16(Parcel& parcel, const char* string)
37 {
38 if (string != nullptr)
39 {
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
get_interface_name(sp<IBinder> service)49 static String16 get_interface_name(sp<IBinder> service)
50 {
51 if (service != nullptr) {
52 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
good_old_string(const String16 & src)61 static 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
main(int argc,char * const argv[])74 int main(int argc, char* const argv[])
75 {
76 bool wantsUsage = false;
77 int result = 0;
78
79 while (1) {
80 int ic = getopt(argc, argv, "h?");
81 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 }
96 #ifdef VENDORSERVICES
97 ProcessState::initWithDriver("/dev/vndbinder");
98 #endif
99 sp<IServiceManager> sm = defaultServiceManager();
100 fflush(stdout);
101 if (sm == nullptr) {
102 aerr << "service: Unable to get default service manager!" << endl;
103 return 20;
104 }
105
106 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] <<
114 (service == nullptr ? ": not found" : ": found") << endl;
115 } 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);
127 aout << i
128 << "\t" << good_old_string(name)
129 << ": [" << 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++]);
139 if (service != nullptr && ifName.size() > 0) {
140 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++]));
156 } 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++]));
165 } 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++]));
174 } 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++]));
192 } else if (strcmp(argv[optind], "null") == 0) {
193 optind++;
194 data.writeStrongBinder(nullptr);
195 } 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
246 } else if (strcmp(argv[optind], "intent") == 0) {
247
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
258 optind++;
259
260 while (optind < argc)
261 {
262 char* key = strtok_r(argv[optind], "=", &context1);
263 char* value = strtok_r(nullptr, "=", &context1);
264
265 // we have reached the end of the XXX=XXX args.
266 if (key == nullptr) break;
267
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;
291 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
300 optind++;
301 }
302
303 writeString16(data, action);
304 writeString16(data, dataArg);
305 writeString16(data, type);
306 data.writeInt32(launchFlags);
307 writeString16(data, component);
308
309 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);
320 }
321
322 // for now just set the extra field to be null.
323 data.writeInt32(-1);
324 } else {
325 aerr << "service: unknown option " << argv[optind] << endl;
326 wantsUsage = true;
327 result = 10;
328 break;
329 }
330 }
331
332 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 }
354
355 if (wantsUsage) {
356 aout << "Usage: service [-h|-?]\n"
357 " service list\n"
358 " service check SERVICE\n"
359 " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
360 " | fd f | nfd n | afd f ] ...\n"
361 "Options:\n"
362 " 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"
366 " 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";
372 // " 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 }
376
377 return result;
378 }
379
380