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