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], "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