blob: ed3c5849821d7181b0cdb1b3fe3be8f3ee3aceb9 [file] [log] [blame]
/* Copyright (C) 2011 The Android Open Source Project
**
** This software is licensed under the terms of the GNU General Public
** License version 2, as published by the Free Software Foundation, and
** may be copied, distributed, and modified under those terms.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
*/
#include "android/avd/util.h"
#include "android/utils/bufprint.h"
#include "android/utils/debug.h"
#include "android/utils/eintr_wrapper.h"
#include "android/utils/path.h"
#include "android/utils/dirscanner.h"
#include "android/main-common.h"
#include "android/globals.h"
#include "android/resource.h"
#include "android/user-config.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#ifdef _WIN32
#include <process.h>
#endif
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
/***********************************************************************/
/***********************************************************************/
/***** *****/
/***** U T I L I T Y R O U T I N E S *****/
/***** *****/
/***********************************************************************/
/***********************************************************************/
#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
void reassign_string(char** string, const char* new_value) {
free(*string);
*string = ASTRDUP(new_value);
}
unsigned convertBytesToMB( uint64_t size )
{
if (size == 0)
return 0;
size = (size + ONE_MB-1) >> 20;
if (size > UINT_MAX)
size = UINT_MAX;
return (unsigned) size;
}
uint64_t convertMBToBytes( unsigned megaBytes )
{
return ((uint64_t)megaBytes << 20);
}
/* this function is used to perform auto-detection of the
* system directory in the case of a SDK installation.
*
* we want to deal with several historical usages, hence
* the slightly complicated logic.
*
* NOTE: the function returns the path to the directory
* containing 'fileName'. this is *not* the full
* path to 'fileName'.
*/
static char*
_getSdkImagePath( const char* fileName )
{
char temp[MAX_PATH];
char* p = temp;
char* end = p + sizeof(temp);
char* q;
char* app;
static const char* const searchPaths[] = {
"", /* program's directory */
"/lib/images", /* this is for SDK 1.0 */
"/../platforms/android-1.1/images", /* this is for SDK 1.1 */
NULL
};
app = bufprint_app_dir(temp, end);
if (app >= end)
return NULL;
do {
int nn;
/* first search a few well-known paths */
for (nn = 0; searchPaths[nn] != NULL; nn++) {
p = bufprint(app, end, "%s", searchPaths[nn]);
q = bufprint(p, end, "/%s", fileName);
if (q < end && path_exists(temp)) {
*p = 0;
goto FOUND_IT;
}
}
/* hmmm. let's assume that we are in a post-1.1 SDK
* scan ../platforms if it exists
*/
p = bufprint(app, end, "/../platforms");
if (p < end) {
DirScanner* scanner = dirScanner_new(temp);
if (scanner != NULL) {
int found = 0;
const char* subdir;
for (;;) {
subdir = dirScanner_next(scanner);
if (!subdir) break;
q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
if (q >= end || !path_exists(temp))
continue;
found = 1;
p = bufprint(p, end, "/%s/images", subdir);
break;
}
dirScanner_free(scanner);
if (found)
break;
}
}
/* I'm out of ideas */
return NULL;
} while (0);
FOUND_IT:
//D("image auto-detection: %s/%s", temp, fileName);
return android_strdup(temp);
}
static char*
_getSdkImage( const char* path, const char* file )
{
char temp[MAX_PATH];
char *p = temp, *end = p + sizeof(temp);
p = bufprint(temp, end, "%s/%s", path, file);
if (p >= end || !path_exists(temp))
return NULL;
return android_strdup(temp);
}
static char*
_getSdkSystemImage( const char* path, const char* optionName, const char* file )
{
char* image = _getSdkImage(path, file);
if (image == NULL) {
derror("Your system directory is missing the '%s' image file.\n"
"Please specify one with the '%s <filepath>' option",
file, optionName);
exit(2);
}
return image;
}
void sanitizeOptions( AndroidOptions* opts )
{
/* legacy support: we used to use -system <dir> and -image <file>
* instead of -sysdir <dir> and -system <file>, so handle this by checking
* whether the options point to directories or files.
*/
if (opts->image != NULL) {
if (opts->system != NULL) {
if (opts->sysdir != NULL) {
derror( "You can't use -sysdir, -system and -image at the same time.\n"
"You should probably use '-sysdir <path> -system <file>'.\n" );
exit(2);
}
}
dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
"to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
opts->sysdir = opts->system;
opts->system = opts->image;
opts->image = NULL;
}
else if (opts->system != NULL && path_is_dir(opts->system)) {
if (opts->sysdir != NULL) {
derror( "Option -system should now be followed by a file path, not a directory one.\n"
"Please use '-sysdir <path>' to point to the system directory.\n" );
exit(1);
}
dwarning( "Please note that the -system option should now be used to point to the initial\n"
"system image (like the obsolete -image option). To point to the system directory\n"
"please now use '-sysdir <path>' instead.\n" );
opts->sysdir = opts->system;
opts->system = NULL;
}
if (opts->nojni) {
opts->no_jni = opts->nojni;
opts->nojni = 0;
}
if (opts->nocache) {
opts->no_cache = opts->nocache;
opts->nocache = 0;
}
if (opts->noaudio) {
opts->no_audio = opts->noaudio;
opts->noaudio = 0;
}
if (opts->noskin) {
opts->no_skin = opts->noskin;
opts->noskin = 0;
}
/* If -no-cache is used, ignore any -cache argument */
if (opts->no_cache) {
opts->cache = 0;
}
/* the purpose of -no-audio is to disable sound output from the emulator,
* not to disable Audio emulation. So simply force the 'none' backends */
if (opts->no_audio)
opts->audio = "none";
/* we don't accept -skindir without -skin now
* to simplify the autoconfig stuff with virtual devices
*/
if (opts->no_skin) {
opts->skin = "320x480";
opts->skindir = NULL;
}
if (opts->skindir) {
if (!opts->skin) {
derror( "the -skindir <path> option requires a -skin <name> option");
exit(1);
}
}
if (opts->bootchart) {
char* end;
int timeout = strtol(opts->bootchart, &end, 10);
if (timeout == 0)
opts->bootchart = NULL;
else if (timeout < 0 || timeout > 15*60) {
derror( "timeout specified for -bootchart option is invalid.\n"
"please use integers between 1 and 900\n");
exit(1);
}
}
}
AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
{
AvdInfo* ret = NULL;
char tmp[MAX_PATH];
char* tmpend = tmp + sizeof(tmp);
char* android_build_root = NULL;
char* android_build_out = NULL;
/* If no AVD name was given, try to find the top of the
* Android build tree
*/
if (opts->avd == NULL) {
do {
char* out = getenv("ANDROID_PRODUCT_OUT");
if (out == NULL || out[0] == 0)
break;
if (!path_exists(out)) {
derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
"You need to build the Android system before launching the emulator",
out);
exit(2);
}
android_build_root = getenv("ANDROID_BUILD_TOP");
if (android_build_root == NULL || android_build_root[0] == 0)
break;
if (!path_exists(android_build_root)) {
derror("Can't find the Android build root '%s'\n"
"Please check the definition of the ANDROID_BUILD_TOP variable.\n"
"It should point to the root of your source tree.\n",
android_build_root );
exit(2);
}
android_build_out = out;
D( "found Android build root: %s", android_build_root );
D( "found Android build out: %s", android_build_out );
} while (0);
}
/* if no virtual device name is given, and we're not in the
* Android build system, we'll need to perform some auto-detection
* magic :-)
*/
if (opts->avd == NULL && !android_build_out)
{
if (!opts->sysdir) {
opts->sysdir = _getSdkImagePath("system.img");
if (!opts->sysdir) {
derror(
"You did not specify a virtual device name, and the system\n"
"directory could not be found.\n\n"
"If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
"to start a given virtual device (see -help-avd for details).\n\n"
"Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
);
exit(2);
}
D("autoconfig: -sysdir %s", opts->sysdir);
}
if (!opts->system) {
opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
D("autoconfig: -system %s", opts->system);
}
if (!opts->kernel) {
opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
D("autoconfig: -kernel %s", opts->kernel);
}
if (!opts->ramdisk) {
opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
D("autoconfig: -ramdisk %s", opts->ramdisk);
}
/* if no data directory is specified, use the system directory */
if (!opts->datadir) {
opts->datadir = android_strdup(opts->sysdir);
D("autoconfig: -datadir %s", opts->sysdir);
}
if (!opts->data) {
/* check for userdata-qemu.img in the data directory */
bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
if (!path_exists(tmp)) {
derror(
"You did not provide the name of an Android Virtual Device\n"
"with the '-avd <name>' option. Read -help-avd for more information.\n\n"
"If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
"to specify a data partition image file (I hope you know what you're doing).\n"
);
exit(2);
}
opts->data = android_strdup(tmp);
D("autoconfig: -data %s", opts->data);
}
if (!opts->snapstorage && opts->datadir) {
bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
if (path_exists(tmp)) {
opts->snapstorage = android_strdup(tmp);
D("autoconfig: -snapstorage %s", opts->snapstorage);
}
}
}
/* setup the virtual device differently depending on whether
* we are in the Android build system or not
*/
if (opts->avd != NULL)
{
ret = avdInfo_new( opts->avd, android_avdParams );
if (ret == NULL) {
/* an error message has already been printed */
dprint("could not find virtual device named '%s'", opts->avd);
exit(1);
}
}
else
{
if (!android_build_out) {
android_build_out = android_build_root = opts->sysdir;
}
ret = avdInfo_newForAndroidBuild(
android_build_root,
android_build_out,
android_avdParams );
if(ret == NULL) {
D("could not start virtual device\n");
exit(1);
}
}
if (android_build_out) {
*inAndroidBuild = 1;
} else {
*inAndroidBuild = 0;
}
return ret;
}
void handle_ui_options( AndroidOptions* opts )
{
return;
}
int attach_ui_to_core( AndroidOptions* opts )
{
return 0;
}