• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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