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