blob: 09921e45d3bdc3cd5291c5def3b0b1b881ad8b99 [file] [log] [blame]
Mike Lockwood94afecf2012-10-24 10:45:23 -07001/*
Mathias Agopian002e1e52013-05-06 20:20:50 -07002 * Copyright 2013 The Android Open Source Project
Mike Lockwood94afecf2012-10-24 10:45:23 -07003 *
Mathias Agopian002e1e52013-05-06 20:20:50 -07004 * 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.
Mike Lockwood94afecf2012-10-24 10:45:23 -070015 */
Mathias Agopian002e1e52013-05-06 20:20:50 -070016
Mike Lockwood94afecf2012-10-24 10:45:23 -070017#include <binder/Parcel.h>
18#include <binder/ProcessState.h>
19#include <binder/IServiceManager.h>
Mathias Agopian002e1e52013-05-06 20:20:50 -070020#include <binder/TextOutput.h>
Mike Lockwood94afecf2012-10-24 10:45:23 -070021
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{
Mike Lockwood94afecf2012-10-24 10:45:23 -070071 bool wantsUsage = false;
Martijn Coenend6480ca2017-04-05 14:16:12 -070072 bool wantsVendorServices = false;
Mike Lockwood94afecf2012-10-24 10:45:23 -070073 int result = 0;
74
75 while (1) {
Martijn Coenend6480ca2017-04-05 14:16:12 -070076 int ic = getopt(argc, argv, "vh?");
Mike Lockwood94afecf2012-10-24 10:45:23 -070077 if (ic < 0)
78 break;
79
80 switch (ic) {
81 case 'h':
82 case '?':
83 wantsUsage = true;
84 break;
Martijn Coenend6480ca2017-04-05 14:16:12 -070085 case 'v':
86 wantsVendorServices = true;
87 break;
Mike Lockwood94afecf2012-10-24 10:45:23 -070088 default:
89 aerr << "service: Unknown option -" << ic << endl;
90 wantsUsage = true;
91 result = 10;
92 break;
93 }
94 }
Martijn Coenend6480ca2017-04-05 14:16:12 -070095
96 if (wantsVendorServices) {
97 ProcessState::initWithDriver("/dev/vndbinder");
98 }
99 sp<IServiceManager> sm = defaultServiceManager();
100 fflush(stdout);
101 if (sm == NULL) {
102 aerr << "service: Unable to get default service manager!" << endl;
103 return 20;
104 }
Mike Lockwood94afecf2012-10-24 10:45:23 -0700105
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 == NULL ? ": 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 != NULL && 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++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700156 } 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++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700165 } 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++]));
Jeff Brownd46898f2015-04-06 19:42:43 -0700174 } 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++]));
Mike Lockwood94afecf2012-10-24 10:45:23 -0700192 } else if (strcmp(argv[optind], "null") == 0) {
193 optind++;
194 data.writeStrongBinder(NULL);
195 } else if (strcmp(argv[optind], "intent") == 0) {
196
197 char* action = NULL;
198 char* dataArg = NULL;
199 char* type = NULL;
200 int launchFlags = 0;
201 char* component = NULL;
202 int categoryCount = 0;
203 char* categories[16];
204
205 char* context1 = NULL;
206
207 optind++;
208
209 while (optind < argc)
210 {
211 char* key = strtok_r(argv[optind], "=", &context1);
212 char* value = strtok_r(NULL, "=", &context1);
213
214 // we have reached the end of the XXX=XXX args.
215 if (key == NULL) break;
216
217 if (strcmp(key, "action") == 0)
218 {
219 action = value;
220 }
221 else if (strcmp(key, "data") == 0)
222 {
223 dataArg = value;
224 }
225 else if (strcmp(key, "type") == 0)
226 {
227 type = value;
228 }
229 else if (strcmp(key, "launchFlags") == 0)
230 {
231 launchFlags = atoi(value);
232 }
233 else if (strcmp(key, "component") == 0)
234 {
235 component = value;
236 }
237 else if (strcmp(key, "categories") == 0)
238 {
239 char* context2 = NULL;
240 int categoryCount = 0;
241 categories[categoryCount] = strtok_r(value, ",", &context2);
242
243 while (categories[categoryCount] != NULL)
244 {
245 categoryCount++;
246 categories[categoryCount] = strtok_r(NULL, ",", &context2);
247 }
248 }
249
250 optind++;
251 }
252
253 writeString16(data, action);
254 writeString16(data, dataArg);
255 writeString16(data, type);
256 data.writeInt32(launchFlags);
257 writeString16(data, component);
258
259 if (categoryCount > 0)
260 {
261 data.writeInt32(categoryCount);
262 for (int i = 0 ; i < categoryCount ; i++)
263 {
264 writeString16(data, categories[i]);
265 }
266 }
267 else
268 {
269 data.writeInt32(0);
270 }
271
272 // for now just set the extra field to be null.
273 data.writeInt32(-1);
274 } else {
275 aerr << "service: unknown option " << argv[optind] << endl;
276 wantsUsage = true;
277 result = 10;
278 break;
279 }
280 }
281
282 service->transact(code, data, &reply);
283 aout << "Result: " << reply << endl;
284 } else {
285 aerr << "service: Service " << argv[serviceArg]
286 << " does not exist" << endl;
287 result = 10;
288 }
289 } else {
290 if (optind < argc) {
291 aerr << "service: No service specified for call" << endl;
292 } else {
293 aerr << "service: No code specified for call" << endl;
294 }
295 wantsUsage = true;
296 result = 10;
297 }
298 } else {
299 aerr << "service: Unknown command " << argv[optind] << endl;
300 wantsUsage = true;
301 result = 10;
302 }
303 }
304
305 if (wantsUsage) {
306 aout << "Usage: service [-h|-?]\n"
307 " service list\n"
308 " service check SERVICE\n"
Jeff Brownd46898f2015-04-06 19:42:43 -0700309 " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n"
Mike Lockwood94afecf2012-10-24 10:45:23 -0700310 "Options:\n"
Jeff Brownd46898f2015-04-06 19:42:43 -0700311 " i32: Write the 32-bit integer N into the send parcel.\n"
312 " i64: Write the 64-bit integer N into the send parcel.\n"
313 " f: Write the 32-bit single-precision number N into the send parcel.\n"
314 " d: Write the 64-bit double-precision number N into the send parcel.\n"
Mike Lockwood94afecf2012-10-24 10:45:23 -0700315 " s16: Write the UTF-16 string STR into the send parcel.\n";
316// " intent: Write and Intent int the send parcel. ARGS can be\n"
317// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
318 return result;
319 }
320
321 return result;
322}
323