Home | History | Annotate | Download | only in android
      1 /* Copyright (C) 2011 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 #include "android/avd/util.h"
     13 #include "android/utils/bufprint.h"
     14 #include "android/utils/debug.h"
     15 #include "android/utils/eintr_wrapper.h"
     16 #include "android/utils/path.h"
     17 #include "android/utils/dirscanner.h"
     18 #include "android/main-common.h"
     19 #include "android/globals.h"
     20 #include "android/resource.h"
     21 #include "android/user-config.h"
     22 
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 #include <limits.h>
     26 #ifdef _WIN32
     27 #include <process.h>
     28 #endif
     29 #include <signal.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <sys/time.h>
     33 #include <unistd.h>
     34 
     35 
     36 /***********************************************************************/
     37 /***********************************************************************/
     38 /*****                                                             *****/
     39 /*****            U T I L I T Y   R O U T I N E S                  *****/
     40 /*****                                                             *****/
     41 /***********************************************************************/
     42 /***********************************************************************/
     43 
     44 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
     45 
     46 void reassign_string(char** string, const char* new_value) {
     47     free(*string);
     48     *string = ASTRDUP(new_value);
     49 }
     50 
     51 unsigned convertBytesToMB( uint64_t  size )
     52 {
     53     if (size == 0)
     54         return 0;
     55 
     56     size = (size + ONE_MB-1) >> 20;
     57     if (size > UINT_MAX)
     58         size = UINT_MAX;
     59 
     60     return (unsigned) size;
     61 }
     62 
     63 uint64_t convertMBToBytes( unsigned  megaBytes )
     64 {
     65     return ((uint64_t)megaBytes << 20);
     66 }
     67 
     68 /* this function is used to perform auto-detection of the
     69  * system directory in the case of a SDK installation.
     70  *
     71  * we want to deal with several historical usages, hence
     72  * the slightly complicated logic.
     73  *
     74  * NOTE: the function returns the path to the directory
     75  *       containing 'fileName'. this is *not* the full
     76  *       path to 'fileName'.
     77  */
     78 static char*
     79 _getSdkImagePath( const char*  fileName )
     80 {
     81     char   temp[MAX_PATH];
     82     char*  p   = temp;
     83     char*  end = p + sizeof(temp);
     84     char*  q;
     85     char*  app;
     86 
     87     static const char* const  searchPaths[] = {
     88         "",                                  /* program's directory */
     89         "/lib/images",                       /* this is for SDK 1.0 */
     90         "/../platforms/android-1.1/images",  /* this is for SDK 1.1 */
     91         NULL
     92     };
     93 
     94     app = bufprint_app_dir(temp, end);
     95     if (app >= end)
     96         return NULL;
     97 
     98     do {
     99         int  nn;
    100 
    101         /* first search a few well-known paths */
    102         for (nn = 0; searchPaths[nn] != NULL; nn++) {
    103             p = bufprint(app, end, "%s", searchPaths[nn]);
    104             q = bufprint(p, end, "/%s", fileName);
    105             if (q < end && path_exists(temp)) {
    106                 *p = 0;
    107                 goto FOUND_IT;
    108             }
    109         }
    110 
    111         /* hmmm. let's assume that we are in a post-1.1 SDK
    112          * scan ../platforms if it exists
    113          */
    114         p = bufprint(app, end, "/../platforms");
    115         if (p < end) {
    116             DirScanner*  scanner = dirScanner_new(temp);
    117             if (scanner != NULL) {
    118                 int          found = 0;
    119                 const char*  subdir;
    120 
    121                 for (;;) {
    122                     subdir = dirScanner_next(scanner);
    123                     if (!subdir) break;
    124 
    125                     q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
    126                     if (q >= end || !path_exists(temp))
    127                         continue;
    128 
    129                     found = 1;
    130                     p = bufprint(p, end, "/%s/images", subdir);
    131                     break;
    132                 }
    133                 dirScanner_free(scanner);
    134                 if (found)
    135                     break;
    136             }
    137         }
    138 
    139         /* I'm out of ideas */
    140         return NULL;
    141 
    142     } while (0);
    143 
    144 FOUND_IT:
    145     //D("image auto-detection: %s/%s", temp, fileName);
    146     return android_strdup(temp);
    147 }
    148 
    149 static char*
    150 _getSdkImage( const char*  path, const char*  file )
    151 {
    152     char  temp[MAX_PATH];
    153     char  *p = temp, *end = p + sizeof(temp);
    154 
    155     p = bufprint(temp, end, "%s/%s", path, file);
    156     if (p >= end || !path_exists(temp))
    157         return NULL;
    158 
    159     return android_strdup(temp);
    160 }
    161 
    162 static char*
    163 _getSdkSystemImage( const char*  path, const char*  optionName, const char*  file )
    164 {
    165     char*  image = _getSdkImage(path, file);
    166 
    167     if (image == NULL) {
    168         derror("Your system directory is missing the '%s' image file.\n"
    169                "Please specify one with the '%s <filepath>' option",
    170                file, optionName);
    171         exit(2);
    172     }
    173     return image;
    174 }
    175 
    176 void sanitizeOptions( AndroidOptions* opts )
    177 {
    178     /* legacy support: we used to use -system <dir> and -image <file>
    179      * instead of -sysdir <dir> and -system <file>, so handle this by checking
    180      * whether the options point to directories or files.
    181      */
    182     if (opts->image != NULL) {
    183         if (opts->system != NULL) {
    184             if (opts->sysdir != NULL) {
    185                 derror( "You can't use -sysdir, -system and -image at the same time.\n"
    186                         "You should probably use '-sysdir <path> -system <file>'.\n" );
    187                 exit(2);
    188             }
    189         }
    190         dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
    191                   "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
    192         opts->sysdir = opts->system;
    193         opts->system = opts->image;
    194         opts->image  = NULL;
    195     }
    196     else if (opts->system != NULL && path_is_dir(opts->system)) {
    197         if (opts->sysdir != NULL) {
    198             derror( "Option -system should now be followed by a file path, not a directory one.\n"
    199                     "Please use '-sysdir <path>' to point to the system directory.\n" );
    200             exit(1);
    201         }
    202         dwarning( "Please note that the -system option should now be used to point to the initial\n"
    203                   "system image (like the obsolete -image option). To point to the system directory\n"
    204                   "please now use '-sysdir <path>' instead.\n" );
    205 
    206         opts->sysdir = opts->system;
    207         opts->system = NULL;
    208     }
    209 
    210     if (opts->nojni) {
    211         opts->no_jni = opts->nojni;
    212         opts->nojni  = 0;
    213     }
    214 
    215     if (opts->nocache) {
    216         opts->no_cache = opts->nocache;
    217         opts->nocache  = 0;
    218     }
    219 
    220     if (opts->noaudio) {
    221         opts->no_audio = opts->noaudio;
    222         opts->noaudio  = 0;
    223     }
    224 
    225     if (opts->noskin) {
    226         opts->no_skin = opts->noskin;
    227         opts->noskin  = 0;
    228     }
    229 
    230     /* If -no-cache is used, ignore any -cache argument */
    231     if (opts->no_cache) {
    232         opts->cache = 0;
    233     }
    234 
    235     /* the purpose of -no-audio is to disable sound output from the emulator,
    236      * not to disable Audio emulation. So simply force the 'none' backends */
    237     if (opts->no_audio)
    238         opts->audio = "none";
    239 
    240     /* we don't accept -skindir without -skin now
    241      * to simplify the autoconfig stuff with virtual devices
    242      */
    243     if (opts->no_skin) {
    244         opts->skin    = "320x480";
    245         opts->skindir = NULL;
    246     }
    247 
    248     if (opts->skindir) {
    249         if (!opts->skin) {
    250             derror( "the -skindir <path> option requires a -skin <name> option");
    251             exit(1);
    252         }
    253     }
    254 
    255     if (opts->bootchart) {
    256         char*  end;
    257         int    timeout = strtol(opts->bootchart, &end, 10);
    258         if (timeout == 0)
    259             opts->bootchart = NULL;
    260         else if (timeout < 0 || timeout > 15*60) {
    261             derror( "timeout specified for -bootchart option is invalid.\n"
    262                     "please use integers between 1 and 900\n");
    263             exit(1);
    264         }
    265     }
    266 }
    267 
    268 AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
    269 {
    270     AvdInfo* ret = NULL;
    271     char   tmp[MAX_PATH];
    272     char*  tmpend = tmp + sizeof(tmp);
    273     char*  android_build_root = NULL;
    274     char*  android_build_out  = NULL;
    275 
    276     /* If no AVD name was given, try to find the top of the
    277      * Android build tree
    278      */
    279     if (opts->avd == NULL) {
    280         do {
    281             char*  out = getenv("ANDROID_PRODUCT_OUT");
    282 
    283             if (out == NULL || out[0] == 0)
    284                 break;
    285 
    286             if (!path_exists(out)) {
    287                 derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
    288                     "You need to build the Android system before launching the emulator",
    289                     out);
    290                 exit(2);
    291             }
    292 
    293             android_build_root = getenv("ANDROID_BUILD_TOP");
    294             if (android_build_root == NULL || android_build_root[0] == 0)
    295                 break;
    296 
    297             if (!path_exists(android_build_root)) {
    298                 derror("Can't find the Android build root '%s'\n"
    299                     "Please check the definition of the ANDROID_BUILD_TOP variable.\n"
    300                     "It should point to the root of your source tree.\n",
    301                     android_build_root );
    302                 exit(2);
    303             }
    304             android_build_out = out;
    305             D( "found Android build root: %s", android_build_root );
    306             D( "found Android build out:  %s", android_build_out );
    307         } while (0);
    308     }
    309     /* if no virtual device name is given, and we're not in the
    310      * Android build system, we'll need to perform some auto-detection
    311      * magic :-)
    312      */
    313     if (opts->avd == NULL && !android_build_out)
    314     {
    315         if (!opts->sysdir) {
    316             opts->sysdir = _getSdkImagePath("system.img");
    317             if (!opts->sysdir) {
    318                 derror(
    319                 "You did not specify a virtual device name, and the system\n"
    320                 "directory could not be found.\n\n"
    321                 "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
    322                 "to start a given virtual device (see -help-avd for details).\n\n"
    323 
    324                 "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
    325                 );
    326                 exit(2);
    327             }
    328             D("autoconfig: -sysdir %s", opts->sysdir);
    329         }
    330 
    331         if (!opts->system) {
    332             opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
    333             D("autoconfig: -system %s", opts->system);
    334         }
    335 
    336         if (!opts->kernel) {
    337             opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
    338             D("autoconfig: -kernel %s", opts->kernel);
    339         }
    340 
    341         if (!opts->ramdisk) {
    342             opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
    343             D("autoconfig: -ramdisk %s", opts->ramdisk);
    344         }
    345 
    346         /* if no data directory is specified, use the system directory */
    347         if (!opts->datadir) {
    348             opts->datadir   = android_strdup(opts->sysdir);
    349             D("autoconfig: -datadir %s", opts->sysdir);
    350         }
    351 
    352         if (!opts->data) {
    353             /* check for userdata-qemu.img in the data directory */
    354             bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
    355             if (!path_exists(tmp)) {
    356                 derror(
    357                 "You did not provide the name of an Android Virtual Device\n"
    358                 "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
    359 
    360                 "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
    361                 "to specify a data partition image file (I hope you know what you're doing).\n"
    362                 );
    363                 exit(2);
    364             }
    365 
    366             opts->data = android_strdup(tmp);
    367             D("autoconfig: -data %s", opts->data);
    368         }
    369 
    370         if (!opts->snapstorage && opts->datadir) {
    371             bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
    372             if (path_exists(tmp)) {
    373                 opts->snapstorage = android_strdup(tmp);
    374                 D("autoconfig: -snapstorage %s", opts->snapstorage);
    375             }
    376         }
    377     }
    378 
    379     /* setup the virtual device differently depending on whether
    380      * we are in the Android build system or not
    381      */
    382     if (opts->avd != NULL)
    383     {
    384         ret = avdInfo_new( opts->avd, android_avdParams );
    385         if (ret == NULL) {
    386             /* an error message has already been printed */
    387             dprint("could not find virtual device named '%s'", opts->avd);
    388             exit(1);
    389         }
    390     }
    391     else
    392     {
    393         if (!android_build_out) {
    394             android_build_out = android_build_root = opts->sysdir;
    395         }
    396         ret = avdInfo_newForAndroidBuild(
    397                             android_build_root,
    398                             android_build_out,
    399                             android_avdParams );
    400 
    401         if(ret == NULL) {
    402             D("could not start virtual device\n");
    403             exit(1);
    404         }
    405     }
    406 
    407     if (android_build_out) {
    408         *inAndroidBuild = 1;
    409     } else {
    410         *inAndroidBuild = 0;
    411     }
    412 
    413     return ret;
    414 }
    415 
    416 void handle_ui_options( AndroidOptions* opts )
    417 {
    418     return;
    419 }
    420 
    421 int attach_ui_to_core( AndroidOptions* opts )
    422 {
    423     return 0;
    424 }
    425