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