• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <libgen.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/mman.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 
35 using namespace android;
36 
writeString16(Parcel & parcel,const char * string)37 void writeString16(Parcel& parcel, const char* string)
38 {
39     if (string != nullptr)
40     {
41         parcel.writeString16(String16(string));
42     }
43     else
44     {
45         parcel.writeInt32(-1);
46     }
47 }
48 
main(int argc,char * const argv[])49 int main(int argc, char* const argv[])
50 {
51     bool wantsUsage = false;
52     int result = 0;
53 
54     /* Strip path off the program name. */
55     char* prog_name = basename(argv[0]);
56 
57     while (1) {
58         int ic = getopt(argc, argv, "h?");
59         if (ic < 0)
60             break;
61 
62         switch (ic) {
63         case 'h':
64         case '?':
65             wantsUsage = true;
66             break;
67         default:
68             aerr << prog_name << ": Unknown option -" << ic << endl;
69             wantsUsage = true;
70             result = 10;
71             break;
72         }
73     }
74 #ifdef VENDORSERVICES
75     ProcessState::initWithDriver("/dev/vndbinder");
76 #endif
77 #ifndef __ANDROID__
78     setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingConnections = 1}));
79 #endif
80     sp<IServiceManager> sm = defaultServiceManager();
81     fflush(stdout);
82     if (sm == nullptr) {
83         aerr << prog_name << ": Unable to get default service manager!" << endl;
84         return 20;
85     }
86 
87     if (optind >= argc) {
88         wantsUsage = true;
89     } else if (!wantsUsage) {
90         if (strcmp(argv[optind], "check") == 0) {
91             optind++;
92             if (optind < argc) {
93                 sp<IBinder> service = sm->checkService(String16(argv[optind]));
94                 aout << "Service " << argv[optind] <<
95                     (service == nullptr ? ": not found" : ": found") << endl;
96             } else {
97                 aerr << prog_name << ": No service specified for check" << endl;
98                 wantsUsage = true;
99                 result = 10;
100             }
101         }
102         else if (strcmp(argv[optind], "list") == 0) {
103             Vector<String16> services = sm->listServices();
104             aout << "Found " << services.size() << " services:" << endl;
105             for (unsigned i = 0; i < services.size(); i++) {
106                 String16 name = services[i];
107                 sp<IBinder> service = sm->checkService(name);
108                 aout << i
109                      << "\t" << name
110                      << ": [" << (service ? service->getInterfaceDescriptor() : String16()) << "]"
111                      << endl;
112             }
113         } else if (strcmp(argv[optind], "call") == 0) {
114             optind++;
115             if (optind+1 < argc) {
116                 int serviceArg = optind;
117                 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
118                 String16 ifName = (service ? service->getInterfaceDescriptor() : String16());
119                 int32_t code = atoi(argv[optind++]);
120                 if (service != nullptr && ifName.size() > 0) {
121                     Parcel data, reply;
122                     data.markForBinder(service);
123 
124                     // the interface name is first
125                     data.writeInterfaceToken(ifName);
126 
127                     // then the rest of the call arguments
128                     while (optind < argc) {
129                         if (strcmp(argv[optind], "i32") == 0) {
130                             optind++;
131                             if (optind >= argc) {
132                                 aerr << prog_name << ": no integer supplied for 'i32'" << endl;
133                                 wantsUsage = true;
134                                 result = 10;
135                                 break;
136                             }
137                             data.writeInt32(atoi(argv[optind++]));
138                         } else if (strcmp(argv[optind], "i64") == 0) {
139                             optind++;
140                             if (optind >= argc) {
141                                 aerr << prog_name << ": no integer supplied for 'i64'" << endl;
142                                 wantsUsage = true;
143                                 result = 10;
144                                 break;
145                             }
146                             data.writeInt64(atoll(argv[optind++]));
147                         } else if (strcmp(argv[optind], "s16") == 0) {
148                             optind++;
149                             if (optind >= argc) {
150                                 aerr << prog_name << ": no string supplied for 's16'" << endl;
151                                 wantsUsage = true;
152                                 result = 10;
153                                 break;
154                             }
155                             data.writeString16(String16(argv[optind++]));
156                         } else if (strcmp(argv[optind], "f") == 0) {
157                             optind++;
158                             if (optind >= argc) {
159                                 aerr << prog_name << ": no number supplied for 'f'" << endl;
160                                 wantsUsage = true;
161                                 result = 10;
162                                 break;
163                             }
164                             data.writeFloat(atof(argv[optind++]));
165                         } else if (strcmp(argv[optind], "d") == 0) {
166                             optind++;
167                             if (optind >= argc) {
168                                 aerr << prog_name << ": no number supplied for 'd'" << endl;
169                                 wantsUsage = true;
170                                 result = 10;
171                                 break;
172                             }
173                             data.writeDouble(atof(argv[optind++]));
174                         } else if (strcmp(argv[optind], "null") == 0) {
175                             optind++;
176                             data.writeStrongBinder(nullptr);
177                         } else if (strcmp(argv[optind], "fd") == 0) {
178                             optind++;
179                             if (optind >= argc) {
180                                 aerr << prog_name << ": no path supplied for 'fd'" << endl;
181                                 wantsUsage = true;
182                                 result = 10;
183                                 break;
184                             }
185                             const char *path = argv[optind++];
186                             int fd = open(path, O_RDONLY);
187                             if (fd < 0) {
188                                 aerr << prog_name << ": could not open '" << path << "'" << endl;
189                                 wantsUsage = true;
190                                 result = 10;
191                                 break;
192                             }
193                             data.writeFileDescriptor(fd, true /* take ownership */);
194                         } else if (strcmp(argv[optind], "afd") == 0) {
195                             optind++;
196                             if (optind >= argc) {
197                                 aerr << prog_name << ": no path supplied for 'afd'" << endl;
198                                 wantsUsage = true;
199                                 result = 10;
200                                 break;
201                             }
202                             const char *path = argv[optind++];
203                             int fd = open(path, O_RDONLY);
204                             struct stat statbuf;
205                             if (fd < 0 || fstat(fd, &statbuf) != 0) {
206                                 aerr << prog_name << ": could not open or stat"
207                                     << " '" << path << "'" << endl;
208                                 wantsUsage = true;
209                                 result = 10;
210                                 break;
211                             }
212                             int afd = ashmem_create_region("test", statbuf.st_size);
213                             void* ptr = mmap(NULL, statbuf.st_size,
214                                    PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
215                             (void)read(fd, ptr, statbuf.st_size);
216                             close(fd);
217                             data.writeFileDescriptor(afd, true /* take ownership */);
218                         } else if (strcmp(argv[optind], "nfd") == 0) {
219                             optind++;
220                             if (optind >= argc) {
221                                 aerr << prog_name << ": no file descriptor supplied for"
222                                     << " 'nfd'" << endl;
223                                 wantsUsage = true;
224                                 result = 10;
225                                 break;
226                             }
227                             data.writeFileDescriptor(
228                                     atoi(argv[optind++]), true /* take ownership */);
229 
230                         } else if (strcmp(argv[optind], "intent") == 0) {
231 
232                             char* action = nullptr;
233                             char* dataArg = nullptr;
234                             char* type = nullptr;
235                             int launchFlags = 0;
236                             char* component = nullptr;
237                             int categoryCount = 0;
238                             char* categories[16];
239 
240                             char* context1 = nullptr;
241 
242                             optind++;
243 
244                             while (optind < argc)
245                             {
246                                 char* key = strtok_r(argv[optind], "=", &context1);
247                                 char* value = strtok_r(nullptr, "=", &context1);
248 
249                                 // we have reached the end of the XXX=XXX args.
250                                 if (key == nullptr) break;
251 
252                                 if (strcmp(key, "action") == 0)
253                                 {
254                                     action = value;
255                                 }
256                                 else if (strcmp(key, "data") == 0)
257                                 {
258                                     dataArg = value;
259                                 }
260                                 else if (strcmp(key, "type") == 0)
261                                 {
262                                     type = value;
263                                 }
264                                 else if (strcmp(key, "launchFlags") == 0)
265                                 {
266                                     launchFlags = atoi(value);
267                                 }
268                                 else if (strcmp(key, "component") == 0)
269                                 {
270                                     component = value;
271                                 }
272                                 else if (strcmp(key, "categories") == 0)
273                                 {
274                                     char* context2 = nullptr;
275                                     categories[categoryCount] = strtok_r(value, ",", &context2);
276 
277                                     while (categories[categoryCount] != nullptr)
278                                     {
279                                         categoryCount++;
280                                         categories[categoryCount] = strtok_r(nullptr, ",", &context2);
281                                     }
282                                 }
283 
284                                 optind++;
285                             }
286 
287                             writeString16(data, action);
288                             writeString16(data, dataArg);
289                             writeString16(data, type);
290                             data.writeInt32(launchFlags);
291                             writeString16(data, component);
292 
293                             if (categoryCount > 0)
294                             {
295                                 data.writeInt32(categoryCount);
296                                 for (int i = 0 ; i < categoryCount ; i++)
297                                 {
298                                     writeString16(data, categories[i]);
299                                 }
300                             }
301                             else
302                             {
303                                 data.writeInt32(0);
304                             }
305 
306                             // for now just set the extra field to be null.
307                             data.writeInt32(-1);
308                         } else {
309                             aerr << prog_name << ": unknown option " << argv[optind] << endl;
310                             wantsUsage = true;
311                             result = 10;
312                             break;
313                         }
314                     }
315 
316                     service->transact(code, data, &reply);
317                     aout << "Result: " << reply << endl;
318                 } else {
319                     aerr << prog_name << ": Service " << argv[serviceArg]
320                         << " does not exist" << endl;
321                     result = 10;
322                 }
323             } else {
324                 if (optind < argc) {
325                     aerr << prog_name << ": No service specified for call" << endl;
326                 } else {
327                     aerr << prog_name << ": No code specified for call" << endl;
328                 }
329                 wantsUsage = true;
330                 result = 10;
331             }
332         } else {
333             aerr << prog_name << ": Unknown command " << argv[optind] << endl;
334             wantsUsage = true;
335             result = 10;
336         }
337     }
338 
339     if (wantsUsage) {
340         aout << "Usage: " << prog_name << " [-h|-?]\n"
341                 "       " << prog_name << " list\n"
342                 "       " << prog_name << " check SERVICE\n"
343                 "       " << prog_name << " call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR"
344                 " | null | fd f | nfd n | afd f ] ...\n"
345                 "Options:\n"
346                 "   i32: Write the 32-bit integer N into the send parcel.\n"
347                 "   i64: Write the 64-bit integer N into the send parcel.\n"
348                 "     f: Write the 32-bit single-precision number N into the send parcel.\n"
349                 "     d: Write the 64-bit double-precision number N into the send parcel.\n"
350                 "   s16: Write the UTF-16 string STR into the send parcel.\n"
351                 "  null: Write a null binder into the send parcel.\n"
352                 "    fd: Write a file descriptor for the file f into the send parcel.\n"
353                 "   nfd: Write the file descriptor n into the send parcel.\n"
354                 "   afd: Write an ashmem file descriptor for a region containing the data from\n"
355                 "          file f into the send parcel.\n";
356 //                "   intent: Write an Intent into the send parcel. ARGS can be\n"
357 //                "       action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
358         return result;
359     }
360 
361     return result;
362 }
363 
364