Home | History | Annotate | Download | only in avd
      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 <stdlib.h>
     13 #include <stdio.h>
     14 #include <errno.h>
     15 #include "android/utils/debug.h"
     16 #include "android/utils/bufprint.h"
     17 #include "android/utils/ini.h"
     18 #include "android/utils/panic.h"
     19 #include "android/utils/path.h"
     20 #include "android/utils/system.h"
     21 #include "android/avd/util.h"
     22 
     23 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
     24 
     25 /* this is the subdirectory of $HOME/.android where all
     26  * root configuration files (and default content directories)
     27  * are located.
     28  */
     29 #define  ANDROID_AVD_DIR    "avd"
     30 
     31 
     32 /* Return the path to the Android SDK root installation.
     33  *
     34  * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
     35  * environment variable, or 0 otherwise.
     36  *
     37  * Caller must free() returned string.
     38  */
     39 char*
     40 path_getSdkRoot( char *pFromEnv )
     41 {
     42     const char*  env;
     43     char*        sdkPath;
     44     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
     45 
     46     /* If ANDROID_SDK_ROOT is defined is must point to a directory
     47      * containing a valid SDK installation.
     48      */
     49 #define  SDK_ROOT_ENV  "ANDROID_SDK_ROOT"
     50 
     51     env = getenv(SDK_ROOT_ENV);
     52     if (env != NULL && env[0] != 0) {
     53         if (path_exists(env)) {
     54             D("found " SDK_ROOT_ENV ": %s", env);
     55             *pFromEnv = 1;
     56             return ASTRDUP(env);
     57         }
     58         D(SDK_ROOT_ENV " points to unknown directory: %s", env);
     59     }
     60 
     61     *pFromEnv = 0;
     62 
     63     /* We assume the emulator binary is under tools/ so use its
     64      * parent as the Android SDK root.
     65      */
     66     (void) bufprint_app_dir(temp, end);
     67     sdkPath = path_parent(temp, 1);
     68     if (sdkPath == NULL) {
     69         derror("can't find root of SDK directory");
     70         return NULL;
     71     }
     72     D("found SDK root at %s", sdkPath);
     73     return sdkPath;
     74 }
     75 
     76 
     77 /* Return the path to the AVD's root configuration .ini file. it is located in
     78  * ~/.android/avd/<name>.ini or Windows equivalent
     79  *
     80  * This file contains the path to the AVD's content directory, which
     81  * includes its own config.ini.
     82  */
     83 char*
     84 path_getRootIniPath( const char*  avdName )
     85 {
     86     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
     87 
     88     p = bufprint_config_path(temp, end);
     89     p = bufprint(p, end, "/" ANDROID_AVD_DIR "/%s.ini", avdName);
     90     if (p >= end) {
     91         return NULL;
     92     }
     93     if (!path_exists(temp)) {
     94         return NULL;
     95     }
     96     return ASTRDUP(temp);
     97 }
     98 
     99 
    100 char*
    101 path_getSdkHome(void)
    102 {
    103     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    104     p = bufprint_config_path(temp, end);
    105     if (p >= end) {
    106         APANIC("User path too long!: %s\n", temp);
    107     }
    108     return strdup(temp);
    109 }
    110 
    111 
    112 static char*
    113 _getAvdContentPath(const char* avdName)
    114 {
    115     char*    sdkHome = path_getSdkHome();
    116     char*    avdPath = NULL;
    117     IniFile* ini;
    118     char     temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    119 
    120     /* Look for the root .ini file */
    121     p = bufprint(temp, end, "%s/avd/%s.ini", sdkHome, avdName);
    122     if (p >= end) {
    123         APANIC("AVD Name too long: %s\n", avdName);
    124     }
    125 
    126     ini = iniFile_newFromFile(temp);
    127     if (ini == NULL) {
    128         APANIC("Could not open: %s", temp);
    129     }
    130 
    131     avdPath = iniFile_getString(ini, "path", NULL);
    132 
    133     iniFile_free(ini);
    134     AFREE(sdkHome);
    135 
    136     return avdPath;
    137 }
    138 
    139 
    140 static char*
    141 _getAvdTargetArch(const char* avdPath)
    142 {
    143     IniFile* ini;
    144     char*    targetArch = NULL;
    145     char     temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    146     p = bufprint(temp, end, "%s/config.ini", avdPath);
    147     if (p >= end) {
    148         APANIC("AVD path too long: %s\n", avdPath);
    149     }
    150     ini = iniFile_newFromFile(temp);
    151     if (ini == NULL) {
    152         APANIC("Could not open AVD config file: %s", temp);
    153     }
    154     targetArch = iniFile_getString(ini, "hw.cpu.arch", "arm");
    155     iniFile_free(ini);
    156 
    157     return targetArch;
    158 }
    159 
    160 char*
    161 path_getAvdTargetArch( const char* avdName )
    162 {
    163     char*  avdPath = _getAvdContentPath(avdName);
    164     char*  avdArch = _getAvdTargetArch(avdPath);
    165 
    166     return avdArch;
    167 }
    168 
    169 /* Retrieves the value of a given system property defined in a .prop
    170  * file. This is a text file that contains definitions of the format:
    171  * <name>=<value>
    172  *
    173  * Returns NULL if property <name> is undefined or empty.
    174  * Returned string must be freed by the caller.
    175  */
    176 static char*
    177 _getSystemProperty( const char* propFile, const char* propName )
    178 {
    179     FILE*  file;
    180     char   temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    181     int    propNameLen = strlen(propName);
    182     char*  result = NULL;
    183 
    184     file = fopen(propFile, "rb");
    185     if (file == NULL) {
    186         D("Could not open file: %s: %s", temp, strerror(errno));
    187         return NULL;
    188     }
    189 
    190     while (fgets(temp, sizeof temp, file) != NULL) {
    191         /* Trim trailing newlines, if any */
    192         p = memchr(temp, '\0', sizeof temp);
    193         if (p == NULL)
    194             p = end;
    195         if (p > temp && p[-1] == '\n') {
    196             *--p = '\0';
    197         }
    198         if (p > temp && p[-1] == '\r') {
    199             *--p = '\0';
    200         }
    201         /* force zero-termination in case of full-buffer */
    202         if (p == end)
    203             *--p = '\0';
    204 
    205         /* check that the line starts with the property name */
    206         if (memcmp(temp, propName, propNameLen) != 0) {
    207             continue;
    208         }
    209         p = temp + propNameLen;
    210 
    211         /* followed by an equal sign */
    212         if (p >= end || *p != '=')
    213             continue;
    214         p++;
    215 
    216         /* followed by something */
    217         if (p >= end || !*p)
    218             break;
    219 
    220         result = ASTRDUP(p);
    221         break;
    222     }
    223     fclose(file);
    224     return result;
    225 }
    226 
    227 static char*
    228 _getBuildProperty( const char* androidOut, const char* propName )
    229 {
    230     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    231 
    232     p = bufprint(temp, end, "%s/system/build.prop", androidOut);
    233     if (p >= end) {
    234         D("%s: ANDROID_PRODUCT_OUT too long: %s", __FUNCTION__, androidOut);
    235         return NULL;
    236     }
    237     return _getSystemProperty(temp, propName);
    238 }
    239 
    240 char*
    241 path_getBuildTargetArch( const char* androidOut )
    242 {
    243     const char* defaultArch = "arm";
    244     char*       result = NULL;
    245     char*       cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
    246 
    247     if (cpuAbi == NULL) {
    248         D("Coult not find CPU ABI in build properties!");
    249         D("Default target architecture=%s", defaultArch);
    250         result = ASTRDUP(defaultArch);
    251     } else {
    252         /* Translate ABI to cpu arch if necessary */
    253         if (!strcmp("armeabi",cpuAbi))
    254             result = "arm";
    255         else if (!strcmp("armeabi-v7a", cpuAbi))
    256             result = "arm";
    257         else
    258             result = cpuAbi;
    259 
    260         D("Found target ABI=%s, architecture=%s", cpuAbi, result);
    261         result = ASTRDUP(result);
    262         AFREE(cpuAbi);
    263     }
    264     return result;
    265 }
    266 
    267 char*
    268 path_getBuildTargetAbi( const char* androidOut )
    269 {
    270     const char* defaultAbi = "armeabi";
    271     char*       result = NULL;
    272     char*       cpuAbi = _getBuildProperty(androidOut, "ro.product.cpu.abi");
    273 
    274     if (cpuAbi == NULL) {
    275         D("Coult not find CPU ABI in build properties!");
    276         D("Default target ABI: %s", defaultAbi);
    277         result = ASTRDUP(defaultAbi);
    278     } else {
    279         D("Found target ABI=%s", cpuAbi);
    280         result = cpuAbi;
    281     }
    282     return result;
    283 }
    284 
    285 
    286 int
    287 path_getBuildTargetApiLevel( const char* androidOut )
    288 {
    289     const int  defaultLevel = 1000;
    290     int        level        = defaultLevel;
    291     char*      sdkVersion = _getBuildProperty(androidOut, "ro.build.version.sdk");
    292 
    293     if (sdkVersion != NULL) {
    294         long  value;
    295         char* end;
    296         value = strtol(sdkVersion, &end, 10);
    297         if (end == NULL || *end != '\0' || value != (int)value) {
    298             D("Invalid SDK version build property: '%s'", sdkVersion);
    299             D("Defaulting to target API level %d", level);
    300         } else {
    301             level = (int)value;
    302             /* Sanity check, the Android SDK doesn't support anything
    303              * before Android 1.5, a.k.a API level 3 */
    304             if (level < 3)
    305                 level = 3;
    306             D("Found target API level: %d", level);
    307         }
    308         AFREE(sdkVersion);
    309     } else {
    310         D("Could not find target API level / SDK version in build properties!");
    311         D("Default target API level: %d", level);
    312     }
    313     return level;
    314 }
    315 
    316