• Home
  • History
  • Annotate
  • 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 "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