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    sp<IServiceManager> sm = defaultServiceManager();
72    fflush(stdout);
73    if (sm == NULL) {
74        aerr << "service: Unable to get default service manager!" << endl;
75        return 20;
76    }
77
78    bool wantsUsage = false;
79    int result = 0;
80
81    while (1) {
82        int ic = getopt(argc, argv, "h?");
83        if (ic < 0)
84            break;
85
86        switch (ic) {
87        case 'h':
88        case '?':
89            wantsUsage = true;
90            break;
91        default:
92            aerr << "service: Unknown option -" << ic << endl;
93            wantsUsage = true;
94            result = 10;
95            break;
96        }
97    }
98
99    if (optind >= argc) {
100        wantsUsage = true;
101    } else if (!wantsUsage) {
102        if (strcmp(argv[optind], "check") == 0) {
103            optind++;
104            if (optind < argc) {
105                sp<IBinder> service = sm->checkService(String16(argv[optind]));
106                aout << "Service " << argv[optind] <<
107                    (service == NULL ? ": not found" : ": found") << endl;
108            } else {
109                aerr << "service: No service specified for check" << endl;
110                wantsUsage = true;
111                result = 10;
112            }
113        }
114        else if (strcmp(argv[optind], "list") == 0) {
115            Vector<String16> services = sm->listServices();
116            aout << "Found " << services.size() << " services:" << endl;
117            for (unsigned i = 0; i < services.size(); i++) {
118                String16 name = services[i];
119                sp<IBinder> service = sm->checkService(name);
120                aout << i
121                     << "\t" << good_old_string(name)
122                     << ": [" << good_old_string(get_interface_name(service)) << "]"
123                     << endl;
124            }
125        } else if (strcmp(argv[optind], "call") == 0) {
126            optind++;
127            if (optind+1 < argc) {
128                int serviceArg = optind;
129                sp<IBinder> service = sm->checkService(String16(argv[optind++]));
130                String16 ifName = get_interface_name(service);
131                int32_t code = atoi(argv[optind++]);
132                if (service != NULL && ifName.size() > 0) {
133                    Parcel data, reply;
134
135                    // the interface name is first
136                    data.writeInterfaceToken(ifName);
137
138                    // then the rest of the call arguments
139                    while (optind < argc) {
140                        if (strcmp(argv[optind], "i32") == 0) {
141                            optind++;
142                            if (optind >= argc) {
143                                aerr << "service: no integer supplied for 'i32'" << endl;
144                                wantsUsage = true;
145                                result = 10;
146                                break;
147                            }
148                            data.writeInt32(atoi(argv[optind++]));
149                        } else if (strcmp(argv[optind], "s16") == 0) {
150                            optind++;
151                            if (optind >= argc) {
152                                aerr << "service: no string supplied for 's16'" << endl;
153                                wantsUsage = true;
154                                result = 10;
155                                break;
156                            }
157                            data.writeString16(String16(argv[optind++]));
158                        } else if (strcmp(argv[optind], "null") == 0) {
159                            optind++;
160                            data.writeStrongBinder(NULL);
161                        } else if (strcmp(argv[optind], "intent") == 0) {
162
163                        	char* action = NULL;
164                        	char* dataArg = NULL;
165                        	char* type = NULL;
166                        	int launchFlags = 0;
167                        	char* component = NULL;
168                        	int categoryCount = 0;
169                        	char* categories[16];
170
171                        	char* context1 = NULL;
172
173                            optind++;
174
175                        	while (optind < argc)
176                        	{
177                        		char* key = strtok_r(argv[optind], "=", &context1);
178                        		char* value = strtok_r(NULL, "=", &context1);
179
180                                // we have reached the end of the XXX=XXX args.
181                                if (key == NULL) break;
182
183                        		if (strcmp(key, "action") == 0)
184                        		{
185                        			action = value;
186                        		}
187                        		else if (strcmp(key, "data") == 0)
188                        		{
189                        			dataArg = value;
190                        		}
191                        		else if (strcmp(key, "type") == 0)
192                        		{
193                        			type = value;
194                        		}
195                        		else if (strcmp(key, "launchFlags") == 0)
196                        		{
197                        			launchFlags = atoi(value);
198                        		}
199                        		else if (strcmp(key, "component") == 0)
200                        		{
201                        			component = value;
202                        		}
203                        		else if (strcmp(key, "categories") == 0)
204                        		{
205                        			char* context2 = NULL;
206                        			int categoryCount = 0;
207                        			categories[categoryCount] = strtok_r(value, ",", &context2);
208
209                        			while (categories[categoryCount] != NULL)
210                        			{
211                        				categoryCount++;
212                        				categories[categoryCount] = strtok_r(NULL, ",", &context2);
213                        			}
214                        		}
215
216                                optind++;
217                        	}
218
219                            writeString16(data, action);
220                            writeString16(data, dataArg);
221                            writeString16(data, type);
222                       		data.writeInt32(launchFlags);
223                            writeString16(data, component);
224
225                            if (categoryCount > 0)
226                            {
227                                data.writeInt32(categoryCount);
228                                for (int i = 0 ; i < categoryCount ; i++)
229                                {
230                                    writeString16(data, categories[i]);
231                                }
232                            }
233                            else
234                            {
235                                data.writeInt32(0);
236                            }
237
238                            // for now just set the extra field to be null.
239                       		data.writeInt32(-1);
240                        } else {
241                            aerr << "service: unknown option " << argv[optind] << endl;
242                            wantsUsage = true;
243                            result = 10;
244                            break;
245                        }
246                    }
247
248                    service->transact(code, data, &reply);
249                    aout << "Result: " << reply << endl;
250                } else {
251                    aerr << "service: Service " << argv[serviceArg]
252                        << " does not exist" << endl;
253                    result = 10;
254                }
255            } else {
256                if (optind < argc) {
257                    aerr << "service: No service specified for call" << endl;
258                } else {
259                    aerr << "service: No code specified for call" << endl;
260                }
261                wantsUsage = true;
262                result = 10;
263            }
264        } else {
265            aerr << "service: Unknown command " << argv[optind] << endl;
266            wantsUsage = true;
267            result = 10;
268        }
269    }
270
271    if (wantsUsage) {
272        aout << "Usage: service [-h|-?]\n"
273                "       service list\n"
274                "       service check SERVICE\n"
275                "       service call SERVICE CODE [i32 INT | s16 STR] ...\n"
276                "Options:\n"
277                "   i32: Write the integer INT into the send parcel.\n"
278                "   s16: Write the UTF-16 string STR into the send parcel.\n";
279//                "   intent: Write and Intent int the send parcel. ARGS can be\n"
280//                "       action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
281        return result;
282    }
283
284    return result;
285}
286
287