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 29 using namespace android; 30 31 void 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 44 static 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 56 static 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 69 int 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], "i64") == 0) { 150 optind++; 151 if (optind >= argc) { 152 aerr << "service: no integer supplied for 'i64'" << endl; 153 wantsUsage = true; 154 result = 10; 155 break; 156 } 157 data.writeInt64(atoll(argv[optind++])); 158 } else if (strcmp(argv[optind], "s16") == 0) { 159 optind++; 160 if (optind >= argc) { 161 aerr << "service: no string supplied for 's16'" << endl; 162 wantsUsage = true; 163 result = 10; 164 break; 165 } 166 data.writeString16(String16(argv[optind++])); 167 } else if (strcmp(argv[optind], "f") == 0) { 168 optind++; 169 if (optind >= argc) { 170 aerr << "service: no number supplied for 'f'" << endl; 171 wantsUsage = true; 172 result = 10; 173 break; 174 } 175 data.writeFloat(atof(argv[optind++])); 176 } else if (strcmp(argv[optind], "d") == 0) { 177 optind++; 178 if (optind >= argc) { 179 aerr << "service: no number supplied for 'd'" << endl; 180 wantsUsage = true; 181 result = 10; 182 break; 183 } 184 data.writeDouble(atof(argv[optind++])); 185 } else if (strcmp(argv[optind], "null") == 0) { 186 optind++; 187 data.writeStrongBinder(NULL); 188 } else if (strcmp(argv[optind], "intent") == 0) { 189 190 char* action = NULL; 191 char* dataArg = NULL; 192 char* type = NULL; 193 int launchFlags = 0; 194 char* component = NULL; 195 int categoryCount = 0; 196 char* categories[16]; 197 198 char* context1 = NULL; 199 200 optind++; 201 202 while (optind < argc) 203 { 204 char* key = strtok_r(argv[optind], "=", &context1); 205 char* value = strtok_r(NULL, "=", &context1); 206 207 // we have reached the end of the XXX=XXX args. 208 if (key == NULL) break; 209 210 if (strcmp(key, "action") == 0) 211 { 212 action = value; 213 } 214 else if (strcmp(key, "data") == 0) 215 { 216 dataArg = value; 217 } 218 else if (strcmp(key, "type") == 0) 219 { 220 type = value; 221 } 222 else if (strcmp(key, "launchFlags") == 0) 223 { 224 launchFlags = atoi(value); 225 } 226 else if (strcmp(key, "component") == 0) 227 { 228 component = value; 229 } 230 else if (strcmp(key, "categories") == 0) 231 { 232 char* context2 = NULL; 233 int categoryCount = 0; 234 categories[categoryCount] = strtok_r(value, ",", &context2); 235 236 while (categories[categoryCount] != NULL) 237 { 238 categoryCount++; 239 categories[categoryCount] = strtok_r(NULL, ",", &context2); 240 } 241 } 242 243 optind++; 244 } 245 246 writeString16(data, action); 247 writeString16(data, dataArg); 248 writeString16(data, type); 249 data.writeInt32(launchFlags); 250 writeString16(data, component); 251 252 if (categoryCount > 0) 253 { 254 data.writeInt32(categoryCount); 255 for (int i = 0 ; i < categoryCount ; i++) 256 { 257 writeString16(data, categories[i]); 258 } 259 } 260 else 261 { 262 data.writeInt32(0); 263 } 264 265 // for now just set the extra field to be null. 266 data.writeInt32(-1); 267 } else { 268 aerr << "service: unknown option " << argv[optind] << endl; 269 wantsUsage = true; 270 result = 10; 271 break; 272 } 273 } 274 275 service->transact(code, data, &reply); 276 aout << "Result: " << reply << endl; 277 } else { 278 aerr << "service: Service " << argv[serviceArg] 279 << " does not exist" << endl; 280 result = 10; 281 } 282 } else { 283 if (optind < argc) { 284 aerr << "service: No service specified for call" << endl; 285 } else { 286 aerr << "service: No code specified for call" << endl; 287 } 288 wantsUsage = true; 289 result = 10; 290 } 291 } else { 292 aerr << "service: Unknown command " << argv[optind] << endl; 293 wantsUsage = true; 294 result = 10; 295 } 296 } 297 298 if (wantsUsage) { 299 aout << "Usage: service [-h|-?]\n" 300 " service list\n" 301 " service check SERVICE\n" 302 " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n" 303 "Options:\n" 304 " i32: Write the 32-bit integer N into the send parcel.\n" 305 " i64: Write the 64-bit integer N into the send parcel.\n" 306 " f: Write the 32-bit single-precision number N into the send parcel.\n" 307 " d: Write the 64-bit double-precision number N into the send parcel.\n" 308 " s16: Write the UTF-16 string STR into the send parcel.\n"; 309 // " intent: Write and Intent int the send parcel. ARGS can be\n" 310 // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; 311 return result; 312 } 313 314 return result; 315 } 316 317