• 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 <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*
path_getSdkRoot(char * pFromEnv)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*
path_getRootIniPath(const char * avdName)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*
path_getSdkHome(void)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*
_getAvdContentPath(const char * avdName)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*
_getAvdTargetArch(const char * avdPath)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*
path_getAvdTargetArch(const char * avdName)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*
_getSystemProperty(const char * propFile,const char * propName)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*
_getBuildProperty(const char * androidOut,const char * propName)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*
path_getBuildTargetArch(const char * androidOut)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*
path_getBuildTargetAbi(const char * androidOut)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
path_getBuildTargetApiLevel(const char * androidOut)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
path_getAdbdCommunicationMode(const char * androidOut)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