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
22#include <getopt.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <unistd.h>
27#include <sys/time.h>
28
29using namespace android;
30
31void writeString16(Parcel& parcel, const char* string)
32{
33    if (string != NULL)
34    {
35        parcel.writeString16(String16(string));
36    }
37    else
38    {
39        parcel.writeInt32(-1);
40    }
41}
42
43// get the name of the generic interface we hold a reference to
44static String16 get_interface_name(sp<IBinder> service)
45{
46    if (service != NULL) {
47        Parcel data, reply;
48        status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
49        if (err == NO_ERROR) {
50            return reply.readString16();
51        }
52    }
53    return String16();
54}
55
56static String8 good_old_string(const String16& src)
57{
58    String8 name8;
59    char ch8[2];
60    ch8[1] = 0;
61    for (unsigned j = 0; j < src.size(); j++) {
62        char16_t ch = src[j];
63        if (ch < 128) ch8[0] = (char)ch;
64        name8.append(ch8);
65    }
66    return name8;
67}
68
69int main(int argc, char* const argv[])
70{
71    bool wantsUsage = false;
72    int result = 0;
73
74    while (1) {
75        int ic = getopt(argc, argv, "h?");
76        if (ic < 0)
77            break;
78
79        switch (ic) {
80        case 'h':
81        case '?':
82            wantsUsage = true;
83            break;
84        default:
85            aerr << "service: Unknown option -" << ic << endl;
86            wantsUsage = true;
87            result = 10;
88            break;
89        }
90    }
91#ifdef VENDORSERVICES
92    ProcessState::initWithDriver("/dev/vndbinder");
93#endif
94    sp<IServiceManager> sm = defaultServiceManager();
95    fflush(stdout);
96    if (sm == NULL) {
97        aerr << "service: Unable to get default service manager!" << endl;
98        return 20;
99    }
100
101    if (optind >= argc) {
102        wantsUsage = true;
103    } else if (!wantsUsage) {
104        if (strcmp(argv[optind], "check") == 0) {
105            optind++;
106            if (optind < argc) {
107                sp<IBinder> service = sm->checkService(String16(argv[optind]));
108                aout << "Service " << argv[optind] <<
109                    (service == NULL ? ": not found" : ": found") << endl;
110            } else {
111                aerr << "service: No service specified for check" << endl;
112                wantsUsage = true;
113                result = 10;
114            }
115        }
116        else if (strcmp(argv[optind], "list") == 0) {
117            Vector<String16> services = sm->listServices();
118            aout << "Found " << services.size() << " services:" << endl;
119            for (unsigned i = 0; i < services.size(); i++) {
120                String16 name = services[i];
121                sp<IBinder> service = sm->checkService(name);
122                aout << i
123                     << "\t" << good_old_string(name)
124                     << ": [" << good_old_string(get_interface_name(service)) << "]"
125                     << endl;
126            }
127        } else if (strcmp(argv[optind], "call") == 0) {
128            optind++;
129            if (optind+1 < argc) {
130                int serviceArg = optind;
131                sp<IBinder> service = sm->checkService(String16(argv[optind++]));
132                String16 ifName = get_interface_name(service);
133                int32_t code = atoi(argv[optind++]);
134                if (service != NULL && ifName.size() > 0) {
135                    Parcel data, reply;
136
137                    // the interface name is first
138                    data.writeInterfaceToken(ifName);
139
140                    // then the rest of the call arguments
141                    while (optind < argc) {
142                        if (strcmp(argv[optind], "i32") == 0) {
143                            optind++;
144                            if (optind >= argc) {
145                                aerr << "service: no integer supplied for 'i32'" << endl;
146                                wantsUsage = true;
147                                result = 10;
148                                break;
149                            }
150                            data.writeInt32(atoi(argv[optind++]));
151                        } else if (strcmp(argv[optind], "i64") == 0) {
152                            optind++;
153                            if (optind >= argc) {
154                                aerr << "service: no integer supplied for 'i64'" << endl;
155                                wantsUsage = true;
156                                result = 10;
157                                break;
158                            }
159                            data.writeInt64(atoll(argv[optind++]));
160                        } else if (strcmp(argv[optind], "s16") == 0) {
161                            optind++;
162                            if (optind >= argc) {
163                                aerr << "service: no string supplied for 's16'" << endl;
164                                wantsUsage = true;
165                                result = 10;
166                                break;
167                            }
168                            data.writeString16(String16(argv[optind++]));
169                        } else if (strcmp(argv[optind], "f") == 0) {
170                            optind++;
171                            if (optind >= argc) {
172                                aerr << "service: no number supplied for 'f'" << endl;
173                                wantsUsage = true;
174                                result = 10;
175                                break;
176                            }
177                            data.writeFloat(atof(argv[optind++]));
178                        } else if (strcmp(argv[optind], "d") == 0) {
179                            optind++;
180                            if (optind >= argc) {
181                                aerr << "service: no number supplied for 'd'" << endl;
182                                wantsUsage = true;
183                                result = 10;
184                                break;
185                            }
186                            data.writeDouble(atof(argv[optind++]));
187                        } else if (strcmp(argv[optind], "null") == 0) {
188                            optind++;
189                            data.writeStrongBinder(NULL);
190                        } else if (strcmp(argv[optind], "intent") == 0) {
191
192                        	char* action = NULL;
193                        	char* dataArg = NULL;
194                        	char* type = NULL;
195                        	int launchFlags = 0;
196                        	char* component = NULL;
197                        	int categoryCount = 0;
198                        	char* categories[16];
199
200                        	char* context1 = NULL;
201
202                            optind++;
203
204                        	while (optind < argc)
205                        	{
206                        		char* key = strtok_r(argv[optind], "=", &context1);
207                        		char* value = strtok_r(NULL, "=", &context1);
208
209                                // we have reached the end of the XXX=XXX args.
210                                if (key == NULL) break;
211
212                        		if (strcmp(key, "action") == 0)
213                        		{
214                        			action = value;
215                        		}
216                        		else if (strcmp(key, "data") == 0)
217                        		{
218                        			dataArg = value;
219                        		}
220                        		else if (strcmp(key, "type") == 0)
221                        		{
222                        			type = value;
223                        		}
224                        		else if (strcmp(key, "launchFlags") == 0)
225                        		{
226                        			launchFlags = atoi(value);
227                        		}
228                        		else if (strcmp(key, "component") == 0)
229                        		{
230                        			component = value;
231                        		}
232                        		else if (strcmp(key, "categories") == 0)
233                        		{
234                        			char* context2 = NULL;
235                        			int categoryCount = 0;
236                        			categories[categoryCount] = strtok_r(value, ",", &context2);
237
238                        			while (categories[categoryCount] != NULL)
239                        			{
240                        				categoryCount++;
241                        				categories[categoryCount] = strtok_r(NULL, ",", &context2);
242                        			}
243                        		}
244
245                                optind++;
246                        	}
247
248                            writeString16(data, action);
249                            writeString16(data, dataArg);
250                            writeString16(data, type);
251                       		data.writeInt32(launchFlags);
252                            writeString16(data, component);
253
254                            if (categoryCount > 0)
255                            {
256                                data.writeInt32(categoryCount);
257                                for (int i = 0 ; i < categoryCount ; i++)
258                                {
259                                    writeString16(data, categories[i]);
260                                }
261                            }
262                            else
263                            {
264                                data.writeInt32(0);
265                            }
266
267                            // for now just set the extra field to be null.
268                       		data.writeInt32(-1);
269                        } else {
270                            aerr << "service: unknown option " << argv[optind] << endl;
271                            wantsUsage = true;
272                            result = 10;
273                            break;
274                        }
275                    }
276
277                    service->transact(code, data, &reply);
278                    aout << "Result: " << reply << endl;
279                } else {
280                    aerr << "service: Service " << argv[serviceArg]
281                        << " does not exist" << endl;
282                    result = 10;
283                }
284            } else {
285                if (optind < argc) {
286                    aerr << "service: No service specified for call" << endl;
287                } else {
288                    aerr << "service: No code specified for call" << endl;
289                }
290                wantsUsage = true;
291                result = 10;
292            }
293        } else {
294            aerr << "service: Unknown command " << argv[optind] << endl;
295            wantsUsage = true;
296            result = 10;
297        }
298    }
299
300    if (wantsUsage) {
301        aout << "Usage: service [-h|-?]\n"
302                "       service list\n"
303                "       service check SERVICE\n"
304                "       service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n"
305                "Options:\n"
306                "   i32: Write the 32-bit integer N into the send parcel.\n"
307                "   i64: Write the 64-bit integer N into the send parcel.\n"
308                "   f:   Write the 32-bit single-precision number N into the send parcel.\n"
309                "   d:   Write the 64-bit double-precision number N into the send parcel.\n"
310                "   s16: Write the UTF-16 string STR into the send parcel.\n";
311//                "   intent: Write and Intent int the send parcel. ARGS can be\n"
312//                "       action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
313        return result;
314    }
315
316    return result;
317}
318
319