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
dprintf(char * msg,...)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
display_error(LPSTR description)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
create_temp_file(LPSTR temp_filename)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
read_temp_file(LPSTR temp_filename)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
avd_launcher()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
main(int argc,char ** argv)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