• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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*
path_getSdkRoot(char * pFromEnv)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*
path_getRootIniPath(const char * avdName)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*
path_getSdkHome(void)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*
_getAvdContentPath(const char * avdName)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*
propertyFile_getTargetAbi(const FileData * data)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*
propertyFile_getTargetArch(const FileData * data)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
propertyFile_getInt(const FileData * data,const char * key,int _default,SearchResult * searchResult)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
propertyFile_getApiLevel(const FileData * data)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
propertyFile_getAdbdCommunicationMode(const FileData * data)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 
path_getBuildBuildProp(const char * androidOut)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 
path_getBuildBootProp(const char * androidOut)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*
path_getBuildTargetArch(const char * androidOut)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*
_getAvdTargetArch(const char * avdPath)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*
path_getAvdTargetArch(const char * avdName)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*
emulator_getBackendSuffix(const char * targetArch)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