1 /* 2 * Copyright (C) 2009 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 /* 18 * The "AVD Manager" is for Windows only. 19 * This simple .exe will sit at the root of the Windows SDK 20 * and currently simply executes tools\android.bat. 21 * Eventually it should simply replace the batch file. 22 * 23 * TODO: replace by a jar-exe wrapper. 24 */ 25 26 #ifdef _WIN32 27 28 #include <stdio.h> 29 #include <stdarg.h> 30 #include <string.h> 31 #include <windows.h> 32 33 34 int _enable_dprintf = 0; 35 36 void dprintf(char *msg, ...) { 37 va_list ap; 38 va_start(ap, msg); 39 40 if (_enable_dprintf) { 41 vfprintf(stderr, msg, ap); 42 } 43 44 va_end(ap); 45 } 46 47 void display_error(LPSTR description) { 48 DWORD err = GetLastError(); 49 LPSTR s, s2; 50 51 fprintf(stderr, "%s, error %ld\n", description, err); 52 53 if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */ 54 FORMAT_MESSAGE_FROM_SYSTEM, 55 NULL, /* lpSource */ 56 err, /* dwMessageId */ 57 0, /* dwLanguageId */ 58 (LPSTR)&s, /* lpBuffer */ 59 0, /* nSize */ 60 NULL) != 0) { /* va_list args */ 61 fprintf(stderr, "%s", s); 62 63 s2 = (LPSTR) malloc(strlen(description) + strlen(s) + 5); 64 sprintf(s2, "%s\r\n%s", description, s); 65 MessageBox(NULL, s2, "Android AVD Manager - Error", MB_OK); 66 free(s2); 67 LocalFree(s); 68 } 69 } 70 71 72 HANDLE create_temp_file(LPSTR temp_filename) { 73 74 HANDLE file_handle = INVALID_HANDLE_VALUE; 75 LPSTR temp_path = (LPSTR) malloc(MAX_PATH); 76 77 /* Get the temp directory path using GetTempPath. 78 GetTempFilename indicates that the temp path dir should not be larger than MAX_PATH-14. 79 */ 80 int ret = GetTempPath(MAX_PATH - 14, temp_path); 81 if (ret > MAX_PATH || ret == 0) { 82 display_error("GetTempPath failed"); 83 free(temp_path); 84 return INVALID_HANDLE_VALUE; 85 } 86 87 /* Now get a temp filename in the temp directory. */ 88 if (!GetTempFileName(temp_path, "txt", 0, temp_filename)) { 89 display_error("GetTempFileName failed"); 90 91 } else { 92 SECURITY_ATTRIBUTES sattr; 93 ZeroMemory(&sattr, sizeof(sattr)); 94 sattr.nLength = sizeof(SECURITY_ATTRIBUTES); 95 sattr.bInheritHandle = TRUE; 96 97 file_handle = CreateFile(temp_filename, // filename 98 GENERIC_WRITE, // access: write 99 FILE_SHARE_READ, // share mode: read OK 100 &sattr, // security attributes 101 CREATE_ALWAYS, // create even if exists 102 FILE_ATTRIBUTE_NORMAL, // flags and attributes 103 NULL); // template 104 if (file_handle == INVALID_HANDLE_VALUE) { 105 display_error("Create temp file failed"); 106 } 107 } 108 109 free(temp_path); 110 return file_handle; 111 } 112 113 114 void read_temp_file(LPSTR temp_filename) { 115 HANDLE handle; 116 117 handle = CreateFile(temp_filename, // filename 118 GENERIC_READ, // access: read 119 FILE_SHARE_READ, // share mode: read OK 120 NULL, // security attributes 121 OPEN_EXISTING, // only open existing file 122 FILE_ATTRIBUTE_NORMAL, // flags and attributes 123 NULL); // template 124 125 if (handle == INVALID_HANDLE_VALUE) { 126 display_error("Open temp file failed"); 127 return; 128 } 129 130 /* Cap the size we're reading. 131 4K is good enough to display in a message box. 132 */ 133 DWORD size = 4096; 134 135 LPSTR buffer = (LPSTR) malloc(size + 1); 136 137 LPSTR p = buffer; 138 DWORD num_left = size; 139 DWORD num_read; 140 do { 141 if (!ReadFile(handle, p, num_left, &num_read, NULL)) { 142 display_error("Read Output failed"); 143 break; 144 } 145 146 num_left -= num_read; 147 p += num_read; 148 } while (num_read > 0); 149 150 if (p != buffer) { 151 *p = 0; 152 153 /* Only output the buffer if it contains special keywords WARNING or ERROR. */ 154 char* s1 = strstr(buffer, "WARNING"); 155 char* s2 = strstr(buffer, "ERROR"); 156 157 if (s2 != NULL && s2 < s1) { 158 s1 = s2; 159 } 160 161 if (s1 != NULL) { 162 /* We end the message at the first occurence of [INFO]. */ 163 s2 = strstr(s1, "[INFO]"); 164 if (s2 != NULL) { 165 *s2 = 0; 166 } 167 168 MessageBox(NULL, s1, "Android AVD Manager - Output", MB_OK); 169 } 170 171 } 172 173 free(buffer); 174 175 if (!CloseHandle(handle)) { 176 display_error("CloseHandle read temp file failed"); 177 } 178 } 179 180 181 int avd_launcher() { 182 int result = 0; 183 STARTUPINFO startup; 184 PROCESS_INFORMATION pinfo; 185 CHAR program_dir[MAX_PATH]; 186 int ret, pos; 187 CHAR temp_filename[MAX_PATH]; 188 HANDLE temp_handle; 189 190 ZeroMemory(&pinfo, sizeof(pinfo)); 191 192 temp_handle = create_temp_file(temp_filename); 193 if (temp_handle == INVALID_HANDLE_VALUE) { 194 return 1; 195 } 196 197 ZeroMemory(&startup, sizeof(startup)); 198 startup.cb = sizeof(startup); 199 startup.dwFlags = STARTF_USESTDHANDLES; 200 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 201 startup.hStdOutput = temp_handle; 202 startup.hStdError = temp_handle; 203 204 /* get path of current program, to switch dirs here when executing the command. */ 205 ret = GetModuleFileName(NULL, program_dir, sizeof(program_dir)); 206 if (ret == 0) { 207 display_error("Failed to get program's filename:"); 208 result = 1; 209 } else { 210 /* Remove the last segment to keep only the directory. */ 211 pos = ret - 1; 212 while (pos > 0 && program_dir[pos] != '\\') { 213 --pos; 214 } 215 program_dir[pos] = 0; 216 } 217 218 if (!result) { 219 dprintf("Program dir: %s\n", program_dir); 220 221 ret = CreateProcess( 222 NULL, /* program path */ 223 "tools\\android.bat avd", /* command-line */ 224 NULL, /* process handle is not inheritable */ 225 NULL, /* thread handle is not inheritable */ 226 TRUE, /* yes, inherit some handles */ 227 CREATE_NO_WINDOW, /* we don't want a console */ 228 NULL, /* use parent's environment block */ 229 program_dir, /* use parent's starting directory */ 230 &startup, /* startup info, i.e. std handles */ 231 &pinfo); 232 233 dprintf("CreateProcess returned %d\n", ret); 234 235 if (!ret) { 236 display_error("Failed to execute tools\\android.bat:"); 237 result = 1; 238 } else { 239 dprintf("Wait for process to finish.\n"); 240 241 WaitForSingleObject(pinfo.hProcess, INFINITE); 242 CloseHandle(pinfo.hProcess); 243 CloseHandle(pinfo.hThread); 244 } 245 } 246 247 dprintf("Cleanup.\n"); 248 249 if (!CloseHandle(temp_handle)) { 250 display_error("CloseHandle temp file failed"); 251 } 252 253 if (!result) { 254 read_temp_file(temp_filename); 255 } 256 257 if (!DeleteFile(temp_filename)) { 258 display_error("Delete temp file failed"); 259 } 260 261 return result; 262 } 263 264 int main(int argc, char **argv) { 265 _enable_dprintf = argc > 1 && strcmp(argv[1], "-v") == 0; 266 dprintf("Verbose debug mode.\n"); 267 268 return avd_launcher(); 269 } 270 271 #endif /* _WIN32 */ 272