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 <limits.h>
     13 #include <stdlib.h>
     14 #include <stdio.h>
     15 #include <errno.h>
     16 #include "android/utils/debug.h"
     17 #include "android/utils/bufprint.h"
     18 #include "android/utils/ini.h"
     19 #include "android/utils/property_file.h"
     20 #include "android/utils/panic.h"
     21 #include "android/utils/path.h"
     22 #include "android/utils/system.h"
     23 #include "android/avd/util.h"
     24 #include "android/avd/keys.h"
     25 
     26 #define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
     27 
     28 /* this is the subdirectory of $HOME/.android where all
     29  * root configuration files (and default content directories)
     30  * are located.
     31  */
     32 #define  ANDROID_AVD_DIR    "avd"
     33 
     34 
     35 /* Return the path to the Android SDK root installation.
     36  *
     37  * (*pFromEnv) will be set to 1 if it comes from the $ANDROID_SDK_ROOT
     38  * environment variable, or 0 otherwise.
     39  *
     40  * Caller must free() returned string.
     41  */
     42 char*
     43 path_getSdkRoot( char *pFromEnv )
     44 {
     45     const char*  env;
     46     char*        sdkPath;
     47     char         temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
     48 
     49     /* If ANDROID_SDK_ROOT is defined is must point to a directory
     50      * containing a valid SDK installation.
     51      */
     52 #define  SDK_ROOT_ENV  "ANDROID_SDK_ROOT"
     53 
     54     env = getenv(SDK_ROOT_ENV);
     55     if (env != NULL && env[0] != 0) {
     56         if (path_exists(env)) {
     57             D("found " SDK_ROOT_ENV ": %s", env);
     58             *pFromEnv = 1;
     59             return ASTRDUP(env);
     60         }
     61         D(SDK_ROOT_ENV " points to unknown directory: %s", env);
     62     }
     63 
     64     *pFromEnv = 0;
     65 
     66     /* We assume the emulator binary is under tools/ so use its
     67      * parent as the Android SDK root.
     68      */
     69     (void) bufprint_app_dir(temp, end);
     70     sdkPath = path_parent(temp, 1);
     71     if (sdkPath == NULL) {
     72         derror("can't find root of SDK directory");
     73         return NULL;
     74     }
     75     D("found SDK root at %s", sdkPath);
     76     return sdkPath;
     77 }
     78 
     79 
     80 /* Return the path to the AVD's root configuration .ini file. it is located in
     81  * ~/.android/avd/<name>.ini or Windows equivalent
     82  *
     83  * This file contains the path to the AVD's content directory, which
     84  * includes its own config.ini.
     85  */
     86 char*
     87 path_getRootIniPath( const char*  avdName )
     88 {
     89     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
     90 
     91     p = bufprint_config_path(temp, end);
     92     p = bufprint(p, end, PATH_SEP ANDROID_AVD_DIR PATH_SEP "%s.ini", avdName);
     93     if (p >= end) {
     94         return NULL;
     95     }
     96     if (!path_exists(temp)) {
     97         return NULL;
     98     }
     99     return ASTRDUP(temp);
    100 }
    101 
    102 
    103 char*
    104 path_getSdkHome(void)
    105 {
    106     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    107     p = bufprint_config_path(temp, end);
    108     if (p >= end) {
    109         APANIC("User path too long!: %s\n", temp);
    110     }
    111     return strdup(temp);
    112 }
    113 
    114 
    115 static char*
    116 _getAvdContentPath(const char* avdName)
    117 {
    118     char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    119     IniFile* ini = NULL;
    120     char*    iniPath = path_getRootIniPath(avdName);
    121     char*    avdPath = NULL;
    122 
    123     if (iniPath != NULL) {
    124         ini = iniFile_newFromFile(iniPath);
    125         AFREE(iniPath);
    126     }
    127 
    128     if (ini == NULL) {
    129         APANIC("Could not open: %s\n", iniPath == NULL ? avdName : iniPath);
    130     }
    131 
    132     avdPath = iniFile_getString(ini, ROOT_ABS_PATH_KEY, NULL);
    133 
    134     if (!path_is_dir(avdPath)) {
    135         // If the absolute path doesn't match an actual directory, try
    136         // the relative path if present.
    137         const char* relPath = iniFile_getString(ini, ROOT_REL_PATH_KEY, NULL);
    138         if (relPath != NULL) {
    139             p = bufprint_config_path(temp, end);
    140             p = bufprint(p, end, PATH_SEP "%s", relPath);
    141             if (p < end && path_is_dir(temp)) {
    142                 AFREE(avdPath);
    143                 avdPath = ASTRDUP(temp);
    144             }
    145         }
    146     }
    147 
    148     iniFile_free(ini);
    149 
    150     return avdPath;
    151 }
    152 
    153 char*
    154 propertyFile_getTargetAbi(const FileData* data) {
    155     return propertyFile_getValue((const char*)data->data,
    156                                  data->size,
    157                                  "ro.product.cpu.abi");
    158 }
    159 
    160 
    161 char*
    162 propertyFile_getTargetArch(const FileData* data) {
    163     char* ret = propertyFile_getTargetAbi(data);
    164     if (ret) {
    165         // Translate ABI name into architecture name.
    166         // By default, there are the same with a few exceptions.
    167         static const struct {
    168             const char* input;
    169             const char* output;
    170         } kData[] = {
    171             { "armeabi", "arm" },
    172             { "armeabi-v7a", "arm" },
    173         };
    174         size_t n;
    175         for (n = 0; n < sizeof(kData)/sizeof(kData[0]); ++n) {
    176             if (!strcmp(ret, kData[n].input)) {
    177                 free(ret);
    178                 ret = ASTRDUP(kData[n].output);
    179                 break;
    180             }
    181         }
    182     }
    183     return ret;
    184 }
    185 
    186 
    187 int
    188 propertyFile_getInt(const FileData* data, const char* key, int _default,
    189                     SearchResult* searchResult) {
    190     char* prop = propertyFile_getValue((const char*)data->data,
    191                                        data->size,
    192                                        key);
    193     if (!prop) {
    194         if (searchResult) {
    195             *searchResult = RESULT_NOT_FOUND;
    196         }
    197         return _default;
    198     }
    199 
    200     char* end;
    201     // long is only 32 bits on windows so it isn't enough to detect int overflow
    202     long long val = strtoll(prop, &end, 10);
    203     if (val < INT_MIN || val > INT_MAX ||
    204         end == prop || *end != '\0') {
    205         D("Invalid int property: '%s:%s'", key, prop);
    206         AFREE(prop);
    207         if (searchResult) {
    208             *searchResult = RESULT_INVALID;
    209         }
    210         return _default;
    211     }
    212 
    213     AFREE(prop);
    214 
    215     if (searchResult) {
    216         *searchResult = RESULT_FOUND;
    217     }
    218     return (int)val;
    219 }
    220 
    221 int
    222 propertyFile_getApiLevel(const FileData* data) {
    223     const int kMinLevel = 3;
    224     const int kMaxLevel = 10000;
    225     SearchResult searchResult;
    226     int level = propertyFile_getInt(data, "ro.build.version.sdk", kMinLevel,
    227                                     &searchResult);
    228     if (searchResult == RESULT_NOT_FOUND) {
    229         level = kMaxLevel;
    230         D("Could not find SDK version in build.prop, default is: %d", level);
    231     } else if (searchResult == RESULT_INVALID || level < 0) {
    232         D("Defaulting to target API sdkVersion %d", level);
    233     } else {
    234         D("Found target API sdkVersion: %d\n", level);
    235     }
    236     return level;
    237 }
    238 
    239 int
    240 propertyFile_getAdbdCommunicationMode(const FileData* data) {
    241     SearchResult searchResult;
    242     int qemud = propertyFile_getInt(data, "ro.adb.qemud", 1, &searchResult);
    243     if (searchResult == RESULT_FOUND) {
    244         D("Found ro.adb.qemud build property: %d", qemud);
    245         return qemud;
    246     }
    247     D("ro.adb.qemud invalid or not found, API >= 16, defaulting ro.adb.qemud==1");
    248     return 1;
    249 }
    250 
    251 char* path_getBuildBuildProp(const char* androidOut) {
    252     char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
    253     p = bufprint(temp, end, "%s/system/build.prop", androidOut);
    254     if (p >= end) {
    255         D("ANDROID_BUILD_OUT is too long: %s\n", androidOut);
    256         return NULL;
    257     }
    258     if (!path_exists(temp)) {
    259         D("Cannot find build properties file: %s\n", temp);
    260         return NULL;
    261     }
    262     return ASTRDUP(temp);
    263 }
    264 
    265 
    266 char* path_getBuildBootProp(const char* androidOut) {
    267     char temp[MAX_PATH], *p = temp, *end = p + sizeof(temp);
    268     p = bufprint(temp, end, "%s/boot.prop", androidOut);
    269     if (p >= end) {
    270         D("ANDROID_BUILD_OUT is too long: %s\n", androidOut);
    271         return NULL;
    272     }
    273     if (!path_exists(temp)) {
    274         D("Cannot find boot properties file: %s\n", temp);
    275         return NULL;
    276     }
    277     return ASTRDUP(temp);
    278 }
    279 
    280 
    281 char*
    282 path_getBuildTargetArch(const char* androidOut) {
    283     char* buildPropPath = path_getBuildBuildProp(androidOut);
    284     if (!buildPropPath) {
    285         return NULL;
    286     }
    287 
    288     FileData buildProp[1];
    289     fileData_initFromFile(buildProp, buildPropPath);
    290     char* ret = propertyFile_getTargetArch(buildProp);
    291     fileData_done(buildProp);
    292     AFREE(buildPropPath);
    293     return ret;
    294 }
    295 
    296 
    297 static char*
    298 _getAvdTargetArch(const char* avdPath)
    299 {
    300     IniFile* ini;
    301     char*    targetArch = NULL;
    302     char     temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
    303     p = bufprint(temp, end, "%s" PATH_SEP "config.ini", avdPath);
    304     if (p >= end) {
    305         APANIC("AVD path too long: %s\n", avdPath);
    306     }
    307     ini = iniFile_newFromFile(temp);
    308     if (ini == NULL) {
    309         APANIC("Could not open AVD config file: %s\n", temp);
    310     }
    311     targetArch = iniFile_getString(ini, "hw.cpu.arch", "arm");
    312     iniFile_free(ini);
    313 
    314     return targetArch;
    315 }
    316 
    317 char*
    318 path_getAvdTargetArch( const char* avdName )
    319 {
    320     char*  avdPath = _getAvdContentPath(avdName);
    321     char*  avdArch = _getAvdTargetArch(avdPath);
    322     AFREE(avdPath);
    323 
    324     return avdArch;
    325 }
    326 
    327 const char*
    328 emulator_getBackendSuffix(const char* targetArch)
    329 {
    330     if (!targetArch)
    331         return NULL;
    332 
    333     static const struct {
    334         const char* avd_arch;
    335         const char* emulator_suffix;
    336     } kPairs[] = {
    337         { "arm", "arm" },
    338         { "x86", "x86" },
    339         { "x86_64", "x86" },
    340         { "mips", "mips" },
    341         { "arm64", "arm" },
    342         // Add more if needed here.
    343     };
    344     size_t n;
    345     for (n = 0; n < sizeof(kPairs)/sizeof(kPairs[0]); ++n) {
    346         if (!strcmp(targetArch, kPairs[n].avd_arch)) {
    347             return kPairs[n].emulator_suffix;
    348         }
    349     }
    350     return NULL;
    351 }
    352