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