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 != nullptr) 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 != nullptr) { 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 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 == nullptr) { 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 == nullptr ? ": 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 != nullptr && 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(nullptr); 190 } else if (strcmp(argv[optind], "intent") == 0) { 191 192 char* action = nullptr; 193 char* dataArg = nullptr; 194 char* type = nullptr; 195 int launchFlags = 0; 196 char* component = nullptr; 197 int categoryCount = 0; 198 char* categories[16]; 199 200 char* context1 = nullptr; 201 202 optind++; 203 204 while (optind < argc) 205 { 206 char* key = strtok_r(argv[optind], "=", &context1); 207 char* value = strtok_r(nullptr, "=", &context1); 208 209 // we have reached the end of the XXX=XXX args. 210 if (key == nullptr) 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 = nullptr; 235 categories[categoryCount] = strtok_r(value, ",", &context2); 236 237 while (categories[categoryCount] != nullptr) 238 { 239 categoryCount++; 240 categories[categoryCount] = strtok_r(nullptr, ",", &context2); 241 } 242 } 243 244 optind++; 245 } 246 247 writeString16(data, action); 248 writeString16(data, dataArg); 249 writeString16(data, type); 250 data.writeInt32(launchFlags); 251 writeString16(data, component); 252 253 if (categoryCount > 0) 254 { 255 data.writeInt32(categoryCount); 256 for (int i = 0 ; i < categoryCount ; i++) 257 { 258 writeString16(data, categories[i]); 259 } 260 } 261 else 262 { 263 data.writeInt32(0); 264 } 265 266 // for now just set the extra field to be null. 267 data.writeInt32(-1); 268 } else { 269 aerr << "service: unknown option " << argv[optind] << endl; 270 wantsUsage = true; 271 result = 10; 272 break; 273 } 274 } 275 276 service->transact(code, data, &reply); 277 aout << "Result: " << reply << endl; 278 } else { 279 aerr << "service: Service " << argv[serviceArg] 280 << " does not exist" << endl; 281 result = 10; 282 } 283 } else { 284 if (optind < argc) { 285 aerr << "service: No service specified for call" << endl; 286 } else { 287 aerr << "service: No code specified for call" << endl; 288 } 289 wantsUsage = true; 290 result = 10; 291 } 292 } else { 293 aerr << "service: Unknown command " << argv[optind] << endl; 294 wantsUsage = true; 295 result = 10; 296 } 297 } 298 299 if (wantsUsage) { 300 aout << "Usage: service [-h|-?]\n" 301 " service list\n" 302 " service check SERVICE\n" 303 " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n" 304 "Options:\n" 305 " i32: Write the 32-bit integer N into the send parcel.\n" 306 " i64: Write the 64-bit integer N into the send parcel.\n" 307 " f: Write the 32-bit single-precision number N into the send parcel.\n" 308 " d: Write the 64-bit double-precision number N into the send parcel.\n" 309 " s16: Write the UTF-16 string STR into the send parcel.\n"; 310 // " intent: Write and Intent int the send parcel. ARGS can be\n" 311 // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; 312 return result; 313 } 314 315 return result; 316 } 317 318