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