Home | History | Annotate | Download | only in sdklauncher
      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