sdklauncher.c revision 0913421ffd4ab078bc2f9472c73f1e5bbf9525c4
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
37int _enable_dprintf = 0;
38
39void 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
50void 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
75HANDLE 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
117void 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
184int 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
267int 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