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 "android/avd/util.h"
13 #include "android/utils/bufprint.h"
14 #include "android/utils/debug.h"
15 #include "android/utils/eintr_wrapper.h"
16 #include "android/utils/path.h"
17 #include "android/utils/dirscanner.h"
18 #include "android/main-common.h"
19 #include "android/globals.h"
20 #include "android/resource.h"
21 #include "android/user-config.h"
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #ifdef _WIN32
27 #include <process.h>
28 #endif
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34
35
36 /***********************************************************************/
37 /***********************************************************************/
38 /***** *****/
39 /***** U T I L I T Y R O U T I N E S *****/
40 /***** *****/
41 /***********************************************************************/
42 /***********************************************************************/
43
44 #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
45
reassign_string(char ** string,const char * new_value)46 void reassign_string(char** string, const char* new_value) {
47 free(*string);
48 *string = ASTRDUP(new_value);
49 }
50
convertBytesToMB(uint64_t size)51 unsigned convertBytesToMB( uint64_t size )
52 {
53 if (size == 0)
54 return 0;
55
56 size = (size + ONE_MB-1) >> 20;
57 if (size > UINT_MAX)
58 size = UINT_MAX;
59
60 return (unsigned) size;
61 }
62
convertMBToBytes(unsigned megaBytes)63 uint64_t convertMBToBytes( unsigned megaBytes )
64 {
65 return ((uint64_t)megaBytes << 20);
66 }
67
68 /* this function is used to perform auto-detection of the
69 * system directory in the case of a SDK installation.
70 *
71 * we want to deal with several historical usages, hence
72 * the slightly complicated logic.
73 *
74 * NOTE: the function returns the path to the directory
75 * containing 'fileName'. this is *not* the full
76 * path to 'fileName'.
77 */
78 static char*
_getSdkImagePath(const char * fileName)79 _getSdkImagePath( const char* fileName )
80 {
81 char temp[MAX_PATH];
82 char* p = temp;
83 char* end = p + sizeof(temp);
84 char* q;
85 char* app;
86
87 static const char* const searchPaths[] = {
88 "", /* program's directory */
89 "/lib/images", /* this is for SDK 1.0 */
90 "/../platforms/android-1.1/images", /* this is for SDK 1.1 */
91 NULL
92 };
93
94 app = bufprint_app_dir(temp, end);
95 if (app >= end)
96 return NULL;
97
98 do {
99 int nn;
100
101 /* first search a few well-known paths */
102 for (nn = 0; searchPaths[nn] != NULL; nn++) {
103 p = bufprint(app, end, "%s", searchPaths[nn]);
104 q = bufprint(p, end, "/%s", fileName);
105 if (q < end && path_exists(temp)) {
106 *p = 0;
107 goto FOUND_IT;
108 }
109 }
110
111 /* hmmm. let's assume that we are in a post-1.1 SDK
112 * scan ../platforms if it exists
113 */
114 p = bufprint(app, end, "/../platforms");
115 if (p < end) {
116 DirScanner* scanner = dirScanner_new(temp);
117 if (scanner != NULL) {
118 int found = 0;
119 const char* subdir;
120
121 for (;;) {
122 subdir = dirScanner_next(scanner);
123 if (!subdir) break;
124
125 q = bufprint(p, end, "/%s/images/%s", subdir, fileName);
126 if (q >= end || !path_exists(temp))
127 continue;
128
129 found = 1;
130 p = bufprint(p, end, "/%s/images", subdir);
131 break;
132 }
133 dirScanner_free(scanner);
134 if (found)
135 break;
136 }
137 }
138
139 /* I'm out of ideas */
140 return NULL;
141
142 } while (0);
143
144 FOUND_IT:
145 //D("image auto-detection: %s/%s", temp, fileName);
146 return android_strdup(temp);
147 }
148
149 static char*
_getSdkImage(const char * path,const char * file)150 _getSdkImage( const char* path, const char* file )
151 {
152 char temp[MAX_PATH];
153 char *p = temp, *end = p + sizeof(temp);
154
155 p = bufprint(temp, end, "%s/%s", path, file);
156 if (p >= end || !path_exists(temp))
157 return NULL;
158
159 return android_strdup(temp);
160 }
161
162 static char*
_getSdkSystemImage(const char * path,const char * optionName,const char * file)163 _getSdkSystemImage( const char* path, const char* optionName, const char* file )
164 {
165 char* image = _getSdkImage(path, file);
166
167 if (image == NULL) {
168 derror("Your system directory is missing the '%s' image file.\n"
169 "Please specify one with the '%s <filepath>' option",
170 file, optionName);
171 exit(2);
172 }
173 return image;
174 }
175
sanitizeOptions(AndroidOptions * opts)176 void sanitizeOptions( AndroidOptions* opts )
177 {
178 /* legacy support: we used to use -system <dir> and -image <file>
179 * instead of -sysdir <dir> and -system <file>, so handle this by checking
180 * whether the options point to directories or files.
181 */
182 if (opts->image != NULL) {
183 if (opts->system != NULL) {
184 if (opts->sysdir != NULL) {
185 derror( "You can't use -sysdir, -system and -image at the same time.\n"
186 "You should probably use '-sysdir <path> -system <file>'.\n" );
187 exit(2);
188 }
189 }
190 dwarning( "Please note that -image is obsolete and that -system is now used to point\n"
191 "to the system image. Next time, try using '-sysdir <path> -system <file>' instead.\n" );
192 opts->sysdir = opts->system;
193 opts->system = opts->image;
194 opts->image = NULL;
195 }
196 else if (opts->system != NULL && path_is_dir(opts->system)) {
197 if (opts->sysdir != NULL) {
198 derror( "Option -system should now be followed by a file path, not a directory one.\n"
199 "Please use '-sysdir <path>' to point to the system directory.\n" );
200 exit(1);
201 }
202 dwarning( "Please note that the -system option should now be used to point to the initial\n"
203 "system image (like the obsolete -image option). To point to the system directory\n"
204 "please now use '-sysdir <path>' instead.\n" );
205
206 opts->sysdir = opts->system;
207 opts->system = NULL;
208 }
209
210 if (opts->nojni) {
211 opts->no_jni = opts->nojni;
212 opts->nojni = 0;
213 }
214
215 if (opts->nocache) {
216 opts->no_cache = opts->nocache;
217 opts->nocache = 0;
218 }
219
220 if (opts->noaudio) {
221 opts->no_audio = opts->noaudio;
222 opts->noaudio = 0;
223 }
224
225 if (opts->noskin) {
226 opts->no_skin = opts->noskin;
227 opts->noskin = 0;
228 }
229
230 /* If -no-cache is used, ignore any -cache argument */
231 if (opts->no_cache) {
232 opts->cache = 0;
233 }
234
235 /* the purpose of -no-audio is to disable sound output from the emulator,
236 * not to disable Audio emulation. So simply force the 'none' backends */
237 if (opts->no_audio)
238 opts->audio = "none";
239
240 /* we don't accept -skindir without -skin now
241 * to simplify the autoconfig stuff with virtual devices
242 */
243 if (opts->no_skin) {
244 opts->skin = "320x480";
245 opts->skindir = NULL;
246 }
247
248 if (opts->skindir) {
249 if (!opts->skin) {
250 derror( "the -skindir <path> option requires a -skin <name> option");
251 exit(1);
252 }
253 }
254
255 if (opts->bootchart) {
256 char* end;
257 int timeout = strtol(opts->bootchart, &end, 10);
258 if (timeout == 0)
259 opts->bootchart = NULL;
260 else if (timeout < 0 || timeout > 15*60) {
261 derror( "timeout specified for -bootchart option is invalid.\n"
262 "please use integers between 1 and 900\n");
263 exit(1);
264 }
265 }
266 }
267
createAVD(AndroidOptions * opts,int * inAndroidBuild)268 AvdInfo* createAVD(AndroidOptions* opts, int* inAndroidBuild)
269 {
270 AvdInfo* ret = NULL;
271 char tmp[MAX_PATH];
272 char* tmpend = tmp + sizeof(tmp);
273 char* android_build_root = NULL;
274 char* android_build_out = NULL;
275
276 /* If no AVD name was given, try to find the top of the
277 * Android build tree
278 */
279 if (opts->avd == NULL) {
280 do {
281 char* out = getenv("ANDROID_PRODUCT_OUT");
282
283 if (out == NULL || out[0] == 0)
284 break;
285
286 if (!path_exists(out)) {
287 derror("Can't access ANDROID_PRODUCT_OUT as '%s'\n"
288 "You need to build the Android system before launching the emulator",
289 out);
290 exit(2);
291 }
292
293 android_build_root = getenv("ANDROID_BUILD_TOP");
294 if (android_build_root == NULL || android_build_root[0] == 0)
295 break;
296
297 if (!path_exists(android_build_root)) {
298 derror("Can't find the Android build root '%s'\n"
299 "Please check the definition of the ANDROID_BUILD_TOP variable.\n"
300 "It should point to the root of your source tree.\n",
301 android_build_root );
302 exit(2);
303 }
304 android_build_out = out;
305 D( "found Android build root: %s", android_build_root );
306 D( "found Android build out: %s", android_build_out );
307 } while (0);
308 }
309 /* if no virtual device name is given, and we're not in the
310 * Android build system, we'll need to perform some auto-detection
311 * magic :-)
312 */
313 if (opts->avd == NULL && !android_build_out)
314 {
315 if (!opts->sysdir) {
316 opts->sysdir = _getSdkImagePath("system.img");
317 if (!opts->sysdir) {
318 derror(
319 "You did not specify a virtual device name, and the system\n"
320 "directory could not be found.\n\n"
321 "If you are an Android SDK user, please use '@<name>' or '-avd <name>'\n"
322 "to start a given virtual device (see -help-avd for details).\n\n"
323
324 "Otherwise, follow the instructions in -help-disk-images to start the emulator\n"
325 );
326 exit(2);
327 }
328 D("autoconfig: -sysdir %s", opts->sysdir);
329 }
330
331 if (!opts->system) {
332 opts->system = _getSdkSystemImage(opts->sysdir, "-image", "system.img");
333 D("autoconfig: -system %s", opts->system);
334 }
335
336 if (!opts->kernel) {
337 opts->kernel = _getSdkSystemImage(opts->sysdir, "-kernel", "kernel-qemu");
338 D("autoconfig: -kernel %s", opts->kernel);
339 }
340
341 if (!opts->ramdisk) {
342 opts->ramdisk = _getSdkSystemImage(opts->sysdir, "-ramdisk", "ramdisk.img");
343 D("autoconfig: -ramdisk %s", opts->ramdisk);
344 }
345
346 /* if no data directory is specified, use the system directory */
347 if (!opts->datadir) {
348 opts->datadir = android_strdup(opts->sysdir);
349 D("autoconfig: -datadir %s", opts->sysdir);
350 }
351
352 if (!opts->data) {
353 /* check for userdata-qemu.img in the data directory */
354 bufprint(tmp, tmpend, "%s/userdata-qemu.img", opts->datadir);
355 if (!path_exists(tmp)) {
356 derror(
357 "You did not provide the name of an Android Virtual Device\n"
358 "with the '-avd <name>' option. Read -help-avd for more information.\n\n"
359
360 "If you *really* want to *NOT* run an AVD, consider using '-data <file>'\n"
361 "to specify a data partition image file (I hope you know what you're doing).\n"
362 );
363 exit(2);
364 }
365
366 opts->data = android_strdup(tmp);
367 D("autoconfig: -data %s", opts->data);
368 }
369
370 if (!opts->snapstorage && opts->datadir) {
371 bufprint(tmp, tmpend, "%s/snapshots.img", opts->datadir);
372 if (path_exists(tmp)) {
373 opts->snapstorage = android_strdup(tmp);
374 D("autoconfig: -snapstorage %s", opts->snapstorage);
375 }
376 }
377 }
378
379 /* setup the virtual device differently depending on whether
380 * we are in the Android build system or not
381 */
382 if (opts->avd != NULL)
383 {
384 ret = avdInfo_new( opts->avd, android_avdParams );
385 if (ret == NULL) {
386 /* an error message has already been printed */
387 dprint("could not find virtual device named '%s'", opts->avd);
388 exit(1);
389 }
390 }
391 else
392 {
393 if (!android_build_out) {
394 android_build_out = android_build_root = opts->sysdir;
395 }
396 ret = avdInfo_newForAndroidBuild(
397 android_build_root,
398 android_build_out,
399 android_avdParams );
400
401 if(ret == NULL) {
402 D("could not start virtual device\n");
403 exit(1);
404 }
405 }
406
407 if (android_build_out) {
408 *inAndroidBuild = 1;
409 } else {
410 *inAndroidBuild = 0;
411 }
412
413 return ret;
414 }
415
handle_ui_options(AndroidOptions * opts)416 void handle_ui_options( AndroidOptions* opts )
417 {
418 return;
419 }
420
attach_ui_to_core(AndroidOptions * opts)421 int attach_ui_to_core( AndroidOptions* opts )
422 {
423 return 0;
424 }
425