blob: 82145b513c903d171f3ccf9439b39bf0cb7a3a77 [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 <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "android/utils/debug.h"
#include "android/utils/bufprint.h"
#include "android/utils/ini.h"
#include "android/utils/panic.h"
#include "android/utils/path.h"
#include "android/utils/system.h"
#include "android/avd/util.h"
#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
/* this is the subdirectory of $HOME/.android where all
* root configuration files (and default content directories)
* are located.
*/
#define ANDROID_AVD_DIR "avd"
/* Return the path to the Android SDK root installation.
*
* (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
* environment variable, or 0 otherwise.
*
* Caller must free() returned string.
*/
char*
path_getSdkRoot( char *pFromEnv )
{
const char* env;
char* sdkPath;
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
/* If ANDROID_SDK_ROOT is defined is must point to a directory
* containing a valid SDK installation.
*/
#define SDK_ROOT_ENV "ANDROID_SDK_ROOT"
env = getenv(SDK_ROOT_ENV);
if (env != NULL && env[0] != 0) {
if (path_exists(env)) {
D("found " SDK_ROOT_ENV ": %s", env);
*pFromEnv = 1;
return ASTRDUP(env);
}
D(SDK_ROOT_ENV " points to unknown directory: %s", env);
}
*pFromEnv = 0;
/* We assume the emulator binary is under tools/ so use its
* parent as the Android SDK root.
*/
(void) bufprint_app_dir(temp, end);
sdkPath = path_parent(temp, 1);
if (sdkPath == NULL) {
derror("can't find root of SDK directory");
return NULL;
}
D("found SDK root at %s", sdkPath);
return sdkPath;
}
/* Return the path to the AVD's root configuration .ini file. it is located in
* ~/.android/avd/<name>.ini or Windows equivalent
*
* This file contains the path to the AVD's content directory, which
* includes its own config.ini.
*/
char*
path_getRootIniPath( const char* avdName )
{
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
p = bufprint_config_path(temp, end);
p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName);
if (p >= end) {
return NULL;
}
if (!path_exists(temp)) {
return NULL;
}
return ASTRDUP(temp);
}
char*
path_getSdkHome(void)
{
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
p = bufprint_config_path(temp, end);
if (p >= end) {
APANIC("User path too long!: %s\n", temp);
}
return strdup(temp);
}
static char*
_getAvdContentPath(const char* avdName)
{
char* sdkHome = path_getSdkHome();
char* avdPath = NULL;
IniFile* ini;
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
/* Look for the root .ini file */
p = bufprint(temp, end, "%s/avd/%s.ini", sdkHome, avdName);
if (p >= end) {
APANIC("AVD Name too long: %s\n", avdName);
}
ini = iniFile_newFromFile(temp);
if (ini == NULL) {
APANIC("Could not open: %s", temp);
}
avdPath = iniFile_getString(ini, "path", NULL);
iniFile_free(ini);
AFREE(sdkHome);
return avdPath;
}
static char*
_getAvdTargetArch(const char* avdPath)
{
IniFile* ini;
char* targetArch = NULL;
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
p = bufprint(temp, end, "%s/config.ini", avdPath);
if (p >= end) {
APANIC("AVD path too long: %s\n", avdPath);
}
ini = iniFile_newFromFile(temp);
if (ini == NULL) {
APANIC("Could not open AVD config file: %s", temp);
}
targetArch = iniFile_getString(ini, "hw.cpu.arch", "arm");
iniFile_free(ini);
return targetArch;
}
char*
path_getAvdTargetArch( const char* avdName )
{
char* avdPath = _getAvdContentPath(avdName);
char* avdArch = _getAvdTargetArch(avdPath);
return avdArch;
}
/* Retrieves the value of a given system property defined in a .prop
* file. This is a text file that contains definitions of the format:
* <name>=<value>
*
* Returns NULL if property <name> is undefined or empty.
* Returned string must be freed by the caller.
*/
static char*
_getSystemProperty( const char* propFile, const char* propName )
{
FILE* file;
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
int propNameLen = strlen(propName);
char* result = NULL;
file = fopen(propFile, "rb");
if (file == NULL) {
D("Could not open file: %s: %s", temp, strerror(errno));
return NULL;
}
while (fgets(temp, sizeof temp, file) != NULL) {
/* Trim trailing newlines, if any */
p = memchr(temp, '\0', sizeof temp);
if (p == NULL)
p = end;
if (p > temp && p[-1] == '\n') {
*--p = '\0';
}
if (p > temp && p[-1] == '\r') {
*--p = '\0';
}
/* force zero-termination in case of full-buffer */
if (p == end)
*--p = '\0';
/* check that the line starts with the property name */
if (memcmp(temp, propName, propNameLen) != 0) {
continue;
}
p = temp + propNameLen;
/* followed by an equal sign */
if (p >= end || *p != '=')
continue;
p++;
/* followed by something */
if (p >= end || !*p)
break;
result = ASTRDUP(p);
break;
}
fclose(file);
return result;
}
static char*
_getBuildProperty( const char* androidOut, const char* propName )
{
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
p = bufprint(temp, end, "%s/system/build.prop", androidOut);
if (p >= end) {
D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut);
return NULL;
}
return _getSystemProperty(temp, propName);
}
char*
path_getBuildTargetArch( const char* androidOut )
{
const char* defaultArch = "arm";
char* result = NULL;
char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
if (cpuAbi == NULL) {
D("Coult not find CPU ABI in build properties!");
D("Default target architecture=%s", defaultArch);
result = ASTRDUP(defaultArch);
} else {
/* Translate ABI to cpu arch if necessary */
if (!strcmp("armeabi",cpuAbi))
result = "arm";
else if (!strcmp("armeabi-v7a", cpuAbi))
result = "arm";
else
result = cpuAbi;
D("Found target ABI=%s, architecture=%s", cpuAbi, result);
result = ASTRDUP(result);
AFREE(cpuAbi);
}
return result;
}
char*
path_getBuildTargetAbi( const char* androidOut )
{
const char* defaultAbi = "armeabi";
char* result = NULL;
char* cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
if (cpuAbi == NULL) {
D("Coult not find CPU ABI in build properties!");
D("Default target ABI: %s", defaultAbi);
result = ASTRDUP(defaultAbi);
} else {
D("Found target ABI=%s", cpuAbi);
result = cpuAbi;
}
return result;
}
int
path_getBuildTargetApiLevel( const char* androidOut )
{
const int defaultLevel = 1000;
int level = defaultLevel;
char* sdkVersion = _getBuildProperty(androidOut, "ro.build.version.sdk");
if (sdkVersion != NULL) {
long value;
char* end;
value = strtol(sdkVersion, &end, 10);
if (end == NULL || *end != '\0' || value != (int)value) {
D("Invalid SDK version build property: '%s'", sdkVersion);
D("Defaulting to target API level %d", level);
} else {
level = (int)value;
/* Sanity check, the Android SDK doesn't support anything
* before Android 1.5, a.k.a API level 3 */
if (level < 3)
level = 3;
D("Found target API level: %d", level);
}
AFREE(sdkVersion);
} else {
D("Could not find target API level / SDK version in build properties!");
D("Default target API level: %d", level);
}
return level;
}
int
path_getAdbdCommunicationMode( const char* androidOut )
{
char* prop = _getBuildProperty(androidOut, "ro.adb.qemud");
if (prop != NULL) {
long val = 0;
char* end;
val = strtol(prop, &end, 10);
if (end == NULL || *end != '\0' || val != (int)val) {
D("Invalid ro.adb.qemud build property: '%s'", prop);
val = 0;
} else {
D("Found ro.adb.qemud build property: %d", val);
}
AFREE(prop);
return (int)val;
} else {
/* Missing ro.adb.qemud means "legacy" ADBD. */
return 0;
}
}