Merge changes I5fc0f53f,If810fe10,Ie3f03d96,I59c1c4fc

* changes:
  android-constants.c: Move constants to single file.
  main-common.h: Add reassign_string().
  android/: Add proper C++ inclusion guards.
  android/avd: Add proper C++ inclusion guards.
diff --git a/Makefile.common b/Makefile.common
index 2ff49e8..c3f6820 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -103,6 +103,7 @@
 # Android utility functions
 #
 common_LOCAL_SRC_FILES += \
+	android/android-constants.c \
 	android/async-console.c \
 	android/async-utils.c \
 	android/charmap.c \
diff --git a/Makefile.target b/Makefile.target
index e2d2871..4b50420 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -306,6 +306,7 @@
     android/display-core.c \
     android/help.c \
     android/main-common.c \
+    android/main-common-ui.c \
     android/main.c \
     android/opengles.c \
     android/protocol/core-commands-qemu.c \
diff --git a/android/android-constants.c b/android/android-constants.c
new file mode 100644
index 0000000..aa73d70
--- /dev/null
+++ b/android/android-constants.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+
+#include "android/android.h"
+
+/* see http://en.wikipedia.org/wiki/List_of_device_bandwidths or a complete list */
+const NetworkSpeed  android_netspeeds[] = {
+    { "gsm", "GSM/CSD", 14400, 14400 },
+    { "hscsd", "HSCSD", 14400, 43200 },
+    { "gprs", "GPRS", 40000, 80000 },
+    { "edge", "EDGE/EGPRS", 118400, 236800 },
+    { "umts", "UMTS/3G", 128000, 1920000 },
+    { "hsdpa", "HSDPA", 348000, 14400000 },
+    { "full", "no limit", 0, 0 },
+    { NULL, NULL, 0, 0 }
+};
+const size_t android_netspeeds_count =
+    sizeof(android_netspeeds) / sizeof(android_netspeeds[0]);
+
+const NetworkLatency  android_netdelays[] = {
+    /* FIXME: these numbers are totally imaginary */
+    { "gprs", "GPRS", 150, 550 },
+    { "edge", "EDGE/EGPRS", 80, 400 },
+    { "umts", "UMTS/3G", 35, 200 },
+    { "none", "no latency", 0, 0 },
+    { NULL, NULL, 0, 0 }
+};
+const size_t android_netdelays_count =
+    sizeof(android_netdelays) / sizeof(android_netdelays[0]);
+
diff --git a/android/avd/hw-config.h b/android/avd/hw-config.h
index 82a3a5e..df9f1f0 100644
--- a/android/avd/hw-config.h
+++ b/android/avd/hw-config.h
@@ -13,8 +13,11 @@
 #define _ANDROID_AVD_HW_CONFIG_H
 
 #include <stdint.h>
+#include "android/utils/compiler.h"
 #include "android/utils/ini.h"
 
+ANDROID_BEGIN_HEADER
+
 typedef char      hw_bool_t;
 typedef int       hw_int_t;
 typedef int64_t   hw_disksize_t;
@@ -86,4 +89,6 @@
 // kernel.newDeviceNaming.
 const char* androidHwConfig_getKernelSerialPrefix( AndroidHwConfig* config );
 
+ANDROID_END_HEADER
+
 #endif /* _ANDROID_AVD_HW_CONFIG_H */
diff --git a/android/avd/info.h b/android/avd/info.h
index d2b0b74..f0fc1db 100644
--- a/android/avd/info.h
+++ b/android/avd/info.h
@@ -12,11 +12,14 @@
 #ifndef ANDROID_AVD_INFO_H
 #define ANDROID_AVD_INFO_H
 
+#include "android/utils/compiler.h"
 #include "android/utils/ini.h"
 #include "android/avd/hw-config.h"
 #include "android/config/config.h"
 #include "android/utils/file_data.h"
 
+ANDROID_BEGIN_HEADER
+
 /* An Android Virtual Device (AVD for short) corresponds to a
  * directory containing all kernel/disk images for a given virtual
  * device, as well as information about its hardware capabilities,
@@ -284,6 +287,6 @@
 */
 int          avdInfo_getSnapshotPresent(AvdInfo* i);
 
-/* */
+ANDROID_END_HEADER
 
 #endif /* ANDROID_AVD_INFO_H */
diff --git a/android/cmdline-option.h b/android/cmdline-option.h
index 6fba00a..cb650dd 100644
--- a/android/cmdline-option.h
+++ b/android/cmdline-option.h
@@ -12,6 +12,10 @@
 #ifndef _ANDROID_OPTION_H
 #define _ANDROID_OPTION_H
 
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
 /* a structure used to model a linked list of parameters
  */
 typedef struct ParamList {
@@ -43,4 +47,6 @@
  */
 #define  DEFAULT_DEVICE_DPI  165
 
+ANDROID_END_HEADER
+
 #endif /* _ANDROID_OPTION_H */
diff --git a/android/help.c b/android/help.c
index 0fb7f40..3ba19bf 100644
--- a/android/help.c
+++ b/android/help.c
@@ -4,13 +4,13 @@
 #include "android/utils/bufprint.h"
 #include "android/utils/debug.h"
 #include "android/utils/misc.h"
+#ifndef NO_SKIN
 #include "android/skin/keyset.h"
+#endif
 #include "android/android.h"
 #include <stdint.h>
-#include "audio/audio.h"
 #include <string.h>
 #include <stdlib.h>
-#include "android/protocol/core-commands-api.h"
 
 /* XXX: TODO: put most of the help stuff in auto-generated files */
 
@@ -208,6 +208,7 @@
 static void
 help_keys(stralloc_t*  out)
 {
+#ifndef NO_SKIN
     int  pass, maxw = 0;
 
     stralloc_add_str( out, "  When running the emulator, use the following keypresses:\n\n");
@@ -244,6 +245,7 @@
     }
     PRINTF( "\n" );
     PRINTF( "  note that NumLock must be deactivated for keypad keys to work\n\n" );
+#endif  // !NO_SKIN
 }
 
 
@@ -281,6 +283,7 @@
 static void
 help_keyset_file(stralloc_t*  out)
 {
+#ifndef NO_SKIN
     int           n, count;
     const char**  strings;
     char          temp[MAX_PATH];
@@ -346,6 +349,7 @@
     "    CHANGE_LAYOUT_PREV  Keypad_7,Ctrl-J   # switch to a previous skin layout\n"
     "\n"
     );
+#endif  // !NO_SKIN
 }
 
 
@@ -809,8 +813,6 @@
 help_shaper(stralloc_t*  out)
 {
     int  n;
-    NetworkSpeed* android_netspeed;
-    NetworkLatency* android_netdelay;
     PRINTF(
     "  the Android emulator supports network throttling, i.e. slower network\n"
     "  bandwidth as well as higher connection latencies. this is done either through\n"
@@ -818,24 +820,30 @@
 
     "  the format of -netspeed is one of the following (numbers are kbits/s):\n\n" );
 
-    for (n = 0; !corecmd_get_netspeed(n, &android_netspeed); n++) {
+    for (n = 0;; ++n) {
+        const NetworkSpeed* android_netspeed = &android_netspeeds[n];
+        if (!android_netspeed->name) {
+            break;
+        }
         PRINTF( "    -netspeed %-12s %-15s  (up: %.1f, down: %.1f)\n",
                         android_netspeed->name,
                         android_netspeed->display,
                         android_netspeed->upload/1000.,
                         android_netspeed->download/1000. );
-        free(android_netspeed);
     }
     PRINTF( "\n" );
     PRINTF( "    -netspeed %-12s %s", "<num>", "select both upload and download speed\n");
     PRINTF( "    -netspeed %-12s %s", "<up>:<down>", "select individual up and down speed\n");
 
     PRINTF( "\n  The format of -netdelay is one of the following (numbers are msec):\n\n" );
-    for (n = 0; !corecmd_get_netdelay(n, &android_netdelay); n++) {
+    for (n = 0; ; ++n) {
+        const NetworkLatency* android_netdelay = &android_netdelays[n];
+        if (!android_netdelay->name) {
+            break;
+        }
         PRINTF( "    -netdelay %-10s   %-15s  (min %d, max %d)\n",
                         android_netdelay->name, android_netdelay->display,
                         android_netdelay->min_ms, android_netdelay->max_ms );
-        free(android_netdelay);
     }
     PRINTF( "    -netdelay %-10s   %s", "<num>", "select exact latency\n");
     PRINTF( "    -netdelay %-10s   %s", "<min>:<max>", "select min and max latencies\n\n");
diff --git a/android/help.h b/android/help.h
index ee15941..5624823 100644
--- a/android/help.h
+++ b/android/help.h
@@ -12,8 +12,11 @@
 #ifndef _ANDROID_HELP_H
 #define _ANDROID_HELP_H
 
+#include "android/utils/compiler.h"
 #include "android/utils/stralloc.h"
 
+ANDROID_BEGIN_HEADER
+
 /* these values give the maximum length of system property
  * names and values. They must match the definitions for PROPERTY_MAX_NAME and
  * PROPERTY_MAX_VALUE in the Android source tree
@@ -41,4 +44,6 @@
  */
 extern int  android_help_for_topic( const char*  topic, stralloc_t*  out );
 
+ANDROID_END_HEADER
+
 #endif /* _ANDROID_HELP_H */
diff --git a/android/main-common-ui.c b/android/main-common-ui.c
new file mode 100644
index 0000000..0a58eda
--- /dev/null
+++ b/android/main-common-ui.c
@@ -0,0 +1,758 @@
+/* Copyright (C) 2011 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+
+#include <SDL.h>
+#include <SDL_syswm.h>
+
+#include "android/avd/util.h"
+#include "android/globals.h"
+#include "android/main-common.h"
+#include "android/qemulator.h"
+#include "android/display.h"
+#include "android/resource.h"
+#include "android/skin/image.h"
+#include "android/skin/trackball.h"
+#include "android/skin/keyboard.h"
+#include "android/skin/file.h"
+#include "android/skin/window.h"
+#include "android/user-config.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+#include "android/utils/eintr_wrapper.h"
+#include "android/utils/path.h"
+
+#include "ui/console.h"
+
+#include <stdlib.h>
+
+#define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
+
+/***  CONFIGURATION
+ ***/
+
+static AUserConfig*  userConfig;
+
+void
+user_config_init( void )
+{
+    userConfig = auserConfig_new( android_avdInfo );
+}
+
+/* only call this function on normal exits, so that ^C doesn't save the configuration */
+void
+user_config_done( void )
+{
+    int  win_x, win_y;
+
+    if (!userConfig) {
+        D("no user configuration?");
+        return;
+    }
+
+    SDL_WM_GetPos( &win_x, &win_y );
+    auserConfig_setWindowPos(userConfig, win_x, win_y);
+    auserConfig_save(userConfig);
+}
+
+void
+user_config_get_window_pos( int *window_x, int *window_y )
+{
+    *window_x = *window_y = 10;
+
+    if (userConfig)
+        auserConfig_getWindowPos(userConfig, window_x, window_y);
+}
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****            K E Y S E T   R O U T I N E S                    *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+#define  KEYSET_FILE    "default.keyset"
+
+SkinKeyset*  android_keyset = NULL;
+
+static int
+load_keyset(const char*  path)
+{
+    if (path_can_read(path)) {
+        AConfig*  root = aconfig_node("","");
+        if (!aconfig_load_file(root, path)) {
+            android_keyset = skin_keyset_new(root);
+            if (android_keyset != NULL) {
+                D( "keyset loaded from: %s", path);
+                return 0;
+            }
+        }
+    }
+    return -1;
+}
+
+void
+parse_keyset(const char*  keyset, AndroidOptions*  opts)
+{
+    char   kname[MAX_PATH];
+    char   temp[MAX_PATH];
+    char*  p;
+    char*  end;
+
+    /* append .keyset suffix if needed */
+    if (strchr(keyset, '.') == NULL) {
+        p   =  kname;
+        end = p + sizeof(kname);
+        p   = bufprint(p, end, "%s.keyset", keyset);
+        if (p >= end) {
+            derror( "keyset name too long: '%s'\n", keyset);
+            exit(1);
+        }
+        keyset = kname;
+    }
+
+    /* look for a the keyset file */
+    p   = temp;
+    end = p + sizeof(temp);
+    p = bufprint_config_file(p, end, keyset);
+    if (p < end && load_keyset(temp) == 0)
+        return;
+
+    p = temp;
+    p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset);
+    if (p < end && load_keyset(temp) == 0)
+        return;
+
+    p = temp;
+    p = bufprint_app_dir(p, end);
+    p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
+    if (p < end && load_keyset(temp) == 0)
+        return;
+
+    return;
+}
+
+void
+write_default_keyset( void )
+{
+    char   path[MAX_PATH];
+
+    bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
+
+    /* only write if there is no file here */
+    if (!path_exists(path)) {
+        int          fd = open( path, O_WRONLY | O_CREAT, 0666 );
+        const char*  ks = skin_keyset_get_default();
+
+
+        D( "writing default keyset file to %s", path );
+
+        if (fd < 0) {
+            D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
+            return;
+        }
+        HANDLE_EINTR(write(fd, ks, strlen(ks)));
+        IGNORE_EINTR(close(fd));
+    }
+}
+
+
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****            S D L   S U P P O R T                            *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+void *readpng(const unsigned char*  base, size_t  size, unsigned *_width, unsigned *_height);
+
+#ifdef CONFIG_DARWIN
+#  define  ANDROID_ICON_PNG  "android_icon_256.png"
+#else
+#  define  ANDROID_ICON_PNG  "android_icon_16.png"
+#endif
+
+static void
+sdl_set_window_icon( void )
+{
+    static int  window_icon_set;
+
+    if (!window_icon_set)
+    {
+#ifdef _WIN32
+        HANDLE         handle = GetModuleHandle( NULL );
+        HICON          icon   = LoadIcon( handle, MAKEINTRESOURCE(1) );
+        SDL_SysWMinfo  wminfo;
+
+        SDL_GetWMInfo(&wminfo);
+
+        SetClassLongPtr( wminfo.window, GCLP_HICON, (LONG)icon );
+#else  /* !_WIN32 */
+        unsigned              icon_w, icon_h;
+        size_t                icon_bytes;
+        const unsigned char*  icon_data;
+        void*                 icon_pixels;
+
+        window_icon_set = 1;
+
+        icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
+        if ( !icon_data )
+            return;
+
+        icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
+        if ( !icon_pixels )
+            return;
+
+       /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
+        * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
+        * on our CPU endianess
+        */
+        {
+            unsigned*  d     = icon_pixels;
+            unsigned*  d_end = d + icon_w*icon_h;
+
+            for ( ; d < d_end; d++ ) {
+                unsigned  pix = d[0];
+#if HOST_WORDS_BIGENDIAN
+                /* R,G,B,A read as RGBA => ARGB */
+                pix = ((pix >> 8) & 0xffffff) | (pix << 24);
+#else
+                /* R,G,B,A read as ABGR => ARGB */
+                pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
+#endif
+                d[0] = pix;
+            }
+        }
+
+        SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
+        if (icon != NULL) {
+            SDL_WM_SetIcon(icon, NULL);
+            SDL_FreeSurface(icon);
+            free( icon_pixels );
+        }
+#endif  /* !_WIN32 */
+    }
+}
+
+/***********************************************************************/
+/***********************************************************************/
+/*****                                                             *****/
+/*****            S K I N   S U P P O R T                          *****/
+/*****                                                             *****/
+/***********************************************************************/
+/***********************************************************************/
+
+const char*  skin_network_speed = NULL;
+const char*  skin_network_delay = NULL;
+
+
+static void sdl_at_exit(void)
+{
+    user_config_done();
+    qemulator_done(qemulator_get());
+    SDL_Quit();
+}
+
+
+void sdl_display_init(DisplayState *ds, int full_screen, int  no_frame)
+{
+    QEmulator*    emulator = qemulator_get();
+    SkinDisplay*  disp     = skin_layout_get_display(emulator->layout);
+    int           width, height;
+    char          buf[128];
+
+    if (disp->rotation & 1) {
+        width  = disp->rect.size.h;
+        height = disp->rect.size.w;
+    } else {
+        width  = disp->rect.size.w;
+        height = disp->rect.size.h;
+    }
+
+    snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
+#if !defined(CONFIG_STANDALONE_UI) && !defined(CONFIG_STANDALONE_CORE)
+    android_display_init(ds, qframebuffer_fifo_get());
+#endif
+}
+
+typedef struct part_properties part_properties;
+struct part_properties {
+    const char*      name;
+    int              width;
+    int              height;
+    part_properties* next;
+};
+
+part_properties*
+read_all_part_properties(AConfig* parts)
+{
+    part_properties* head = NULL;
+    part_properties* prev = NULL;
+
+    AConfig *node = parts->first_child;
+    while (node) {
+        part_properties* t = calloc(1, sizeof(part_properties));
+        t->name = node->name;
+
+        AConfig* bg = aconfig_find(node, "background");
+        if (bg != NULL) {
+            t->width = aconfig_int(bg, "width", 0);
+            t->height = aconfig_int(bg, "height", 0);
+        }
+
+        if (prev == NULL) {
+            head = t;
+        } else {
+            prev->next = t;
+        }
+        prev = t;
+        node = node->next;
+    }
+
+    return head;
+}
+
+void
+free_all_part_properties(part_properties* head)
+{
+    part_properties* prev = head;
+    while (head) {
+        prev = head;
+        head = head->next;
+        free(prev);
+    }
+}
+
+part_properties*
+get_part_properties(part_properties* allparts, char *partname)
+{
+    part_properties* p;
+    for (p = allparts; p != NULL; p = p->next) {
+        if (!strcmp(partname, p->name))
+            return p;
+    }
+
+    return NULL;
+}
+
+void
+add_parts_to_layout(AConfig* layout,
+                    char* parts[],
+                    int n_parts,
+                    part_properties *props,
+                    int xoffset,
+                    int x_margin,
+                    int y_margin)
+{
+    int     i;
+    int     y = 10;
+    char    tmp[512];
+    for (i = 0; i < n_parts; i++) {
+        part_properties *p = get_part_properties(props, parts[i]);
+        snprintf(tmp, sizeof tmp,
+            "part%d {\n \
+                name %s\n \
+                x %d\n \
+                y %d\n \
+            }",
+            i + 2,  // layout already has the device part as part1, so start from part2
+            p->name,
+            xoffset + x_margin,
+            y
+            );
+        y += p->height + y_margin;
+        aconfig_load(layout, strdup(tmp));
+    }
+}
+
+int
+load_dynamic_skin(AndroidHwConfig* hwConfig,
+                  char**           skinDirPath,
+                  int              width,
+                  int              height,
+                  AConfig*         root)
+{
+    char      tmp[1024];
+    AConfig*  node;
+    int       i;
+    int       max_part_width;
+
+    *skinDirPath = avdInfo_getDynamicSkinPath(android_avdInfo);
+    if (*skinDirPath == NULL) {
+        dwarning("Unable to locate dynamic skin directory. Will not use dynamic skin.");
+        return 0;
+    }
+
+    snprintf(tmp, sizeof(tmp), "%s/layout", *skinDirPath);
+    D("trying to load skin file '%s'", tmp);
+
+    if(aconfig_load_file(root, tmp) < 0) {
+        dwarning("could not load skin file '%s', won't use a skin\n", tmp);
+        return 0;
+    }
+
+    /* Fix the width and height specified for the "device" part in the layout */
+    node = aconfig_find(root, "parts");
+    if (node != NULL) {
+        node = aconfig_find(node, "device");
+        if (node != NULL) {
+            node = aconfig_find(node, "display");
+            if (node != NULL) {
+                snprintf(tmp, sizeof tmp, "%d", width);
+                aconfig_set(node, "width", strdup(tmp));
+                snprintf(tmp, sizeof tmp, "%d", height);
+                aconfig_set(node, "height", strdup(tmp));
+            }
+        }
+    }
+
+    /* The dynamic layout declares all the parts that are available statically
+       in the layout file. Now we need to dynamically generate the
+       appropriate layout based on the hardware config */
+
+    part_properties* props = read_all_part_properties(aconfig_find(root, "parts"));
+
+    const int N_PARTS = 4;
+    char* parts[N_PARTS];
+    parts[0] = "basic_controls";
+    parts[1] = hwConfig->hw_mainKeys ? "hwkeys_on" : "hwkeys_off";
+    parts[2] = hwConfig->hw_dPad ? "dpad_on" : "dpad_off";
+    parts[3] = hwConfig->hw_keyboard ? "keyboard_on" : "keyboard_off";
+
+    for (i = 0, max_part_width = 0; i < N_PARTS; i++) {
+        part_properties *p = get_part_properties(props, parts[i]);
+        if (p != NULL && p->width > max_part_width)
+                max_part_width = p->width;
+    }
+
+    int x_margin = 10;
+    int y_margin = 10;
+    snprintf(tmp, sizeof tmp,
+            "layouts {\n \
+                portrait {\n \
+                    width %d\n \
+                    height %d\n \
+                    color 0x404040\n \
+                    event EV_SW:0:1\n \
+                    part1 {\n name device\n x 0\n y 0\n}\n \
+                }\n \
+                landscape {\n \
+                    width %d\n \
+                    height %d\n \
+                    color 0x404040\n \
+                    event EV_SW:0:0\n \
+                    dpad-rotation 3\n \
+                    part1 {\n name device\n x 0\n y %d\n rotation 3\n }\n \
+                    }\n \
+                }\n \
+             }\n",
+            width  + max_part_width + 2 * x_margin,
+            height,
+            height + max_part_width + 2 * x_margin,
+            width,
+            width);
+    aconfig_load(root, strdup(tmp));
+
+    /* Add parts to portrait orientation */
+    node = aconfig_find(root, "layouts");
+    if (node != NULL) {
+        node = aconfig_find(node, "portrait");
+        if (node != NULL) {
+            add_parts_to_layout(node, parts, N_PARTS, props, width, x_margin, y_margin);
+        }
+    }
+
+    /* Add parts to landscape orientation */
+    node = aconfig_find(root, "layouts");
+    if (node != NULL) {
+        node = aconfig_find(node, "landscape");
+        if (node != NULL) {
+            add_parts_to_layout(node, parts, N_PARTS, props, height, x_margin, y_margin);
+        }
+    }
+
+    free_all_part_properties(props);
+
+    return 1;
+}
+
+/* list of skin aliases */
+static const struct {
+    const char*  name;
+    const char*  alias;
+} skin_aliases[] = {
+    { "QVGA-L", "320x240" },
+    { "QVGA-P", "240x320" },
+    { "HVGA-L", "480x320" },
+    { "HVGA-P", "320x480" },
+    { "QVGA", "320x240" },
+    { "HVGA", "320x480" },
+    { NULL, NULL }
+};
+
+void
+parse_skin_files(const char*      skinDirPath,
+                 const char*      skinName,
+                 AndroidOptions*  opts,
+                 AndroidHwConfig* hwConfig,
+                 AConfig*        *skinConfig,
+                 char*           *skinPath)
+{
+    char      tmp[1024];
+    AConfig*  root;
+    const char* path = NULL;
+    AConfig*  n;
+
+    root = aconfig_node("", "");
+
+    if (skinName == NULL)
+        goto DEFAULT_SKIN;
+
+    /* Support skin aliases like QVGA-H QVGA-P, etc...
+       But first we check if it's a directory that exist before applying
+       the alias */
+    int  checkAlias = 1;
+
+    if (skinDirPath != NULL) {
+        bufprint(tmp, tmp+sizeof(tmp), "%s/%s", skinDirPath, skinName);
+        if (path_exists(tmp)) {
+            checkAlias = 0;
+        } else {
+            D("there is no '%s' skin in '%s'", skinName, skinDirPath);
+        }
+    }
+
+    if (checkAlias) {
+        int  nn;
+
+        for (nn = 0; ; nn++ ) {
+            const char*  skin_name  = skin_aliases[nn].name;
+            const char*  skin_alias = skin_aliases[nn].alias;
+
+            if (!skin_name)
+                break;
+
+            if (!strcasecmp( skin_name, skinName )) {
+                D("skin name '%s' aliased to '%s'", skinName, skin_alias);
+                skinName = skin_alias;
+                break;
+            }
+        }
+    }
+
+    /* Magically support skins like "320x240" or "320x240x16" */
+    if(isdigit(skinName[0])) {
+        char *x = strchr(skinName, 'x');
+        if(x && isdigit(x[1])) {
+            int width = atoi(skinName);
+            int height = atoi(x+1);
+            int bpp   = 16;
+            char* y = strchr(x+1, 'x');
+            if (y && isdigit(y[1])) {
+                bpp = atoi(y+1);
+            }
+
+            if (opts->dynamic_skin) {
+                char *dynamicSkinDirPath;
+                if (load_dynamic_skin(hwConfig, &dynamicSkinDirPath, width, height, root)) {
+                    path = dynamicSkinDirPath;
+                    D("loaded dynamic skin width=%d height=%d bpp=%d\n", width, height, bpp);
+                    goto FOUND_SKIN;
+                }
+            }
+
+            snprintf(tmp, sizeof tmp,
+                    "display {\n  width %d\n  height %d\n bpp %d}\n",
+                    width, height,bpp);
+            aconfig_load(root, strdup(tmp));
+            path = ":";
+            D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp);
+            goto FOUND_SKIN;
+        }
+    }
+
+    if (skinDirPath == NULL) {
+        derror("unknown skin name '%s'", skinName);
+        exit(1);
+    }
+
+    snprintf(tmp, sizeof tmp, "%s/%s/layout", skinDirPath, skinName);
+    D("trying to load skin file '%s'", tmp);
+
+    if(aconfig_load_file(root, tmp) < 0) {
+        dwarning("could not load skin file '%s', using built-in one\n",
+                 tmp);
+        goto DEFAULT_SKIN;
+    }
+
+    snprintf(tmp, sizeof tmp, "%s/%s/", skinDirPath, skinName);
+    path = tmp;
+    goto FOUND_SKIN;
+
+FOUND_SKIN:
+    /* the default network speed and latency can now be specified by the device skin */
+    n = aconfig_find(root, "network");
+    if (n != NULL) {
+        skin_network_speed = aconfig_str(n, "speed", 0);
+        skin_network_delay = aconfig_str(n, "delay", 0);
+    }
+
+    /* extract framebuffer information from the skin.
+     *
+     * for version 1 of the skin format, they are in the top-level
+     * 'display' element.
+     *
+     * for version 2 of the skin format, they are under parts.device.display
+     */
+    n = aconfig_find(root, "display");
+    if (n == NULL) {
+        n = aconfig_find(root, "parts");
+        if (n != NULL) {
+            n = aconfig_find(n, "device");
+            if (n != NULL) {
+                n = aconfig_find(n, "display");
+            }
+        }
+    }
+
+    if (n != NULL) {
+        int  width  = aconfig_int(n, "width", hwConfig->hw_lcd_width);
+        int  height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
+        int  depth  = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
+
+        if (width > 0 && height > 0) {
+            /* The emulated framebuffer wants sizes that are multiples of 4 */
+            if (((width|height) & 3) != 0) {
+                width  = (width+3) & ~3;
+                height = (height+3) & ~3;
+                D("adjusting LCD dimensions to (%dx%dx)", width, height);
+            }
+
+            /* only depth values of 16 and 32 are correct. 16 is the default. */
+            if (depth != 32 && depth != 16) {
+                depth = 16;
+                D("adjusting LCD bit depth to %d", depth);
+            }
+
+            hwConfig->hw_lcd_width  = width;
+            hwConfig->hw_lcd_height = height;
+            hwConfig->hw_lcd_depth  = depth;
+        }
+        else {
+            D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
+              width, height, depth);
+        }
+    }
+
+    *skinConfig = root;
+    *skinPath   = strdup(path);
+    return;
+
+DEFAULT_SKIN:
+    {
+        const unsigned char*  layout_base;
+        size_t                layout_size;
+        char*                 base;
+
+        skinName = "<builtin>";
+
+        layout_base = android_resource_find( "layout", &layout_size );
+        if (layout_base == NULL) {
+            fprintf(stderr, "Couldn't load builtin skin\n");
+            exit(1);
+        }
+        base = malloc( layout_size+1 );
+        memcpy( base, layout_base, layout_size );
+        base[layout_size] = 0;
+
+        D("parsing built-in skin layout file (%d bytes)", (int)layout_size);
+        aconfig_load(root, base);
+        path = ":";
+    }
+    goto FOUND_SKIN;
+}
+
+
+void
+init_sdl_ui(AConfig*         skinConfig,
+            const char*      skinPath,
+            AndroidOptions*  opts)
+{
+    int  win_x, win_y, flags;
+
+    signal(SIGINT, SIG_DFL);
+#ifndef _WIN32
+    signal(SIGQUIT, SIG_DFL);
+#endif
+
+    /* we're not a game, so allow the screensaver to run */
+    setenv("SDL_VIDEO_ALLOW_SCREENSAVER","1",1);
+
+    flags = SDL_INIT_NOPARACHUTE;
+    if (!opts->no_window)
+        flags |= SDL_INIT_VIDEO;
+
+    if(SDL_Init(flags)){
+        fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
+        exit(1);
+    }
+
+    if (!opts->no_window) {
+        SDL_EnableUNICODE(!opts->raw_keys);
+        SDL_EnableKeyRepeat(0,0);
+
+        sdl_set_window_icon();
+    }
+    else
+    {
+#ifndef _WIN32
+       /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
+        * able to run the emulator in the background (e.g. "emulator &").
+        * despite the fact that the emulator should not grab input or try to
+        * write to the output in normal cases, we're stopped on some systems
+        * (e.g. OS X)
+        */
+        signal(SIGTTIN, SIG_IGN);
+        signal(SIGTTOU, SIG_IGN);
+#endif
+    }
+    atexit(sdl_at_exit);
+
+    user_config_get_window_pos(&win_x, &win_y);
+
+    if ( qemulator_init(qemulator_get(), skinConfig, skinPath, win_x, win_y, opts) < 0 ) {
+        fprintf(stderr, "### Error: could not load emulator skin from '%s'\n", skinPath);
+        exit(1);
+    }
+
+    /* add an onion overlay image if needed */
+    if (opts->onion) {
+        SkinImage*  onion = skin_image_find_simple( opts->onion );
+        int         alpha, rotate;
+
+        if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
+            alpha = (256*alpha)/100;
+        } else
+            alpha = 128;
+
+        if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
+            rotate &= 3;
+        } else
+            rotate = SKIN_ROTATION_0;
+
+        qemulator_get()->onion          = onion;
+        qemulator_get()->onion_alpha    = alpha;
+        qemulator_get()->onion_rotation = rotate;
+    }
+}
diff --git a/android/main-common.c b/android/main-common.c
index 990c44b..de51109 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -9,39 +9,28 @@
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 */
-#include <signal.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <fcntl.h>
-#ifdef _WIN32
-#include <process.h>
-#endif
-
-#include <SDL.h>
-#include <SDL_syswm.h>
-
-#include "ui/console.h"
-
 #include "android/avd/util.h"
+#include "android/utils/bufprint.h"
 #include "android/utils/debug.h"
 #include "android/utils/eintr_wrapper.h"
 #include "android/utils/path.h"
-#include "android/utils/bufprint.h"
 #include "android/utils/dirscanner.h"
 #include "android/main-common.h"
 #include "android/globals.h"
 #include "android/resource.h"
 #include "android/user-config.h"
-#include "android/qemulator.h"
-#include "android/display.h"
-#include "android/skin/image.h"
-#include "android/skin/trackball.h"
-#include "android/skin/keyboard.h"
-#include "android/skin/file.h"
-#include "android/skin/window.h"
 
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifdef _WIN32
+#include <process.h>
+#endif
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
 
 
 /***********************************************************************/
@@ -54,40 +43,9 @@
 
 #define  D(...)  do {  if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
 
-/***  CONFIGURATION
- ***/
-
-static AUserConfig*  userConfig;
-
-void
-user_config_init( void )
-{
-    userConfig = auserConfig_new( android_avdInfo );
-}
-
-/* only call this function on normal exits, so that ^C doesn't save the configuration */
-void
-user_config_done( void )
-{
-    int  win_x, win_y;
-
-    if (!userConfig) {
-        D("no user configuration?");
-        return;
-    }
-
-    SDL_WM_GetPos( &win_x, &win_y );
-    auserConfig_setWindowPos(userConfig, win_x, win_y);
-    auserConfig_save(userConfig);
-}
-
-void
-user_config_get_window_pos( int *window_x, int *window_y )
-{
-    *window_x = *window_y = 10;
-
-    if (userConfig)
-        auserConfig_getWindowPos(userConfig, window_x, window_y);
+void reassign_string(char** string, const char* new_value) {
+    free(*string);
+    *string = ASTRDUP(new_value);
 }
 
 unsigned convertBytesToMB( uint64_t  size )
@@ -107,692 +65,6 @@
     return ((uint64_t)megaBytes << 20);
 }
 
-
-/***********************************************************************/
-/***********************************************************************/
-/*****                                                             *****/
-/*****            K E Y S E T   R O U T I N E S                    *****/
-/*****                                                             *****/
-/***********************************************************************/
-/***********************************************************************/
-
-#define  KEYSET_FILE    "default.keyset"
-
-SkinKeyset*  android_keyset = NULL;
-
-static int
-load_keyset(const char*  path)
-{
-    if (path_can_read(path)) {
-        AConfig*  root = aconfig_node("","");
-        if (!aconfig_load_file(root, path)) {
-            android_keyset = skin_keyset_new(root);
-            if (android_keyset != NULL) {
-                D( "keyset loaded from: %s", path);
-                return 0;
-            }
-        }
-    }
-    return -1;
-}
-
-void
-parse_keyset(const char*  keyset, AndroidOptions*  opts)
-{
-    char   kname[MAX_PATH];
-    char   temp[MAX_PATH];
-    char*  p;
-    char*  end;
-
-    /* append .keyset suffix if needed */
-    if (strchr(keyset, '.') == NULL) {
-        p   =  kname;
-        end = p + sizeof(kname);
-        p   = bufprint(p, end, "%s.keyset", keyset);
-        if (p >= end) {
-            derror( "keyset name too long: '%s'\n", keyset);
-            exit(1);
-        }
-        keyset = kname;
-    }
-
-    /* look for a the keyset file */
-    p   = temp;
-    end = p + sizeof(temp);
-    p = bufprint_config_file(p, end, keyset);
-    if (p < end && load_keyset(temp) == 0)
-        return;
-
-    p = temp;
-    p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->sysdir, keyset);
-    if (p < end && load_keyset(temp) == 0)
-        return;
-
-    p = temp;
-    p = bufprint_app_dir(p, end);
-    p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
-    if (p < end && load_keyset(temp) == 0)
-        return;
-
-    return;
-}
-
-void
-write_default_keyset( void )
-{
-    char   path[MAX_PATH];
-
-    bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
-
-    /* only write if there is no file here */
-    if (!path_exists(path)) {
-        int          fd = open( path, O_WRONLY | O_CREAT, 0666 );
-        const char*  ks = skin_keyset_get_default();
-
-
-        D( "writing default keyset file to %s", path );
-
-        if (fd < 0) {
-            D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
-            return;
-        }
-        HANDLE_EINTR(write(fd, ks, strlen(ks)));
-        IGNORE_EINTR(close(fd));
-    }
-}
-
-
-
-/***********************************************************************/
-/***********************************************************************/
-/*****                                                             *****/
-/*****            S D L   S U P P O R T                            *****/
-/*****                                                             *****/
-/***********************************************************************/
-/***********************************************************************/
-
-void *readpng(const unsigned char*  base, size_t  size, unsigned *_width, unsigned *_height);
-
-#ifdef CONFIG_DARWIN
-#  define  ANDROID_ICON_PNG  "android_icon_256.png"
-#else
-#  define  ANDROID_ICON_PNG  "android_icon_16.png"
-#endif
-
-static void
-sdl_set_window_icon( void )
-{
-    static int  window_icon_set;
-
-    if (!window_icon_set)
-    {
-#ifdef _WIN32
-        HANDLE         handle = GetModuleHandle( NULL );
-        HICON          icon   = LoadIcon( handle, MAKEINTRESOURCE(1) );
-        SDL_SysWMinfo  wminfo;
-
-        SDL_GetWMInfo(&wminfo);
-
-        SetClassLongPtr( wminfo.window, GCLP_HICON, (LONG)icon );
-#else  /* !_WIN32 */
-        unsigned              icon_w, icon_h;
-        size_t                icon_bytes;
-        const unsigned char*  icon_data;
-        void*                 icon_pixels;
-
-        window_icon_set = 1;
-
-        icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
-        if ( !icon_data )
-            return;
-
-        icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
-        if ( !icon_pixels )
-            return;
-
-       /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
-        * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
-        * on our CPU endianess
-        */
-        {
-            unsigned*  d     = icon_pixels;
-            unsigned*  d_end = d + icon_w*icon_h;
-
-            for ( ; d < d_end; d++ ) {
-                unsigned  pix = d[0];
-#if HOST_WORDS_BIGENDIAN
-                /* R,G,B,A read as RGBA => ARGB */
-                pix = ((pix >> 8) & 0xffffff) | (pix << 24);
-#else
-                /* R,G,B,A read as ABGR => ARGB */
-                pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
-#endif
-                d[0] = pix;
-            }
-        }
-
-        SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
-        if (icon != NULL) {
-            SDL_WM_SetIcon(icon, NULL);
-            SDL_FreeSurface(icon);
-            free( icon_pixels );
-        }
-#endif  /* !_WIN32 */
-    }
-}
-
-/***********************************************************************/
-/***********************************************************************/
-/*****                                                             *****/
-/*****            S K I N   S U P P O R T                          *****/
-/*****                                                             *****/
-/***********************************************************************/
-/***********************************************************************/
-
-const char*  skin_network_speed = NULL;
-const char*  skin_network_delay = NULL;
-
-
-static void sdl_at_exit(void)
-{
-    user_config_done();
-    qemulator_done(qemulator_get());
-    SDL_Quit();
-}
-
-
-void sdl_display_init(DisplayState *ds, int full_screen, int  no_frame)
-{
-    QEmulator*    emulator = qemulator_get();
-    SkinDisplay*  disp     = skin_layout_get_display(emulator->layout);
-    int           width, height;
-    char          buf[128];
-
-    if (disp->rotation & 1) {
-        width  = disp->rect.size.h;
-        height = disp->rect.size.w;
-    } else {
-        width  = disp->rect.size.w;
-        height = disp->rect.size.h;
-    }
-
-    snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
-#if !defined(CONFIG_STANDALONE_UI) && !defined(CONFIG_STANDALONE_CORE)
-    android_display_init(ds, qframebuffer_fifo_get());
-#endif
-}
-
-typedef struct part_properties part_properties;
-struct part_properties {
-    const char*      name;
-    int              width;
-    int              height;
-    part_properties* next;
-};
-
-part_properties*
-read_all_part_properties(AConfig* parts)
-{
-    part_properties* head = NULL;
-    part_properties* prev = NULL;
-
-    AConfig *node = parts->first_child;
-    while (node) {
-        part_properties* t = calloc(1, sizeof(part_properties));
-        t->name = node->name;
-
-        AConfig* bg = aconfig_find(node, "background");
-        if (bg != NULL) {
-            t->width = aconfig_int(bg, "width", 0);
-            t->height = aconfig_int(bg, "height", 0);
-        }
-
-        if (prev == NULL) {
-            head = t;
-        } else {
-            prev->next = t;
-        }
-        prev = t;
-        node = node->next;
-    }
-
-    return head;
-}
-
-void
-free_all_part_properties(part_properties* head)
-{
-    part_properties* prev = head;
-    while (head) {
-        prev = head;
-        head = head->next;
-        free(prev);
-    }
-}
-
-part_properties*
-get_part_properties(part_properties* allparts, char *partname)
-{
-    part_properties* p;
-    for (p = allparts; p != NULL; p = p->next) {
-        if (!strcmp(partname, p->name))
-            return p;
-    }
-
-    return NULL;
-}
-
-void
-add_parts_to_layout(AConfig* layout,
-                    char* parts[],
-                    int n_parts,
-                    part_properties *props,
-                    int xoffset,
-                    int x_margin,
-                    int y_margin)
-{
-    int     i;
-    int     y = 10;
-    char    tmp[512];
-    for (i = 0; i < n_parts; i++) {
-        part_properties *p = get_part_properties(props, parts[i]);
-        snprintf(tmp, sizeof tmp,
-            "part%d {\n \
-                name %s\n \
-                x %d\n \
-                y %d\n \
-            }",
-            i + 2,  // layout already has the device part as part1, so start from part2
-            p->name,
-            xoffset + x_margin,
-            y
-            );
-        y += p->height + y_margin;
-        aconfig_load(layout, strdup(tmp));
-    }
-}
-
-int
-load_dynamic_skin(AndroidHwConfig* hwConfig,
-                  char**           skinDirPath,
-                  int              width,
-                  int              height,
-                  AConfig*         root)
-{
-    char      tmp[1024];
-    AConfig*  node;
-    int       i;
-    int       max_part_width;
-
-    *skinDirPath = avdInfo_getDynamicSkinPath(android_avdInfo);
-    if (*skinDirPath == NULL) {
-        dwarning("Unable to locate dynamic skin directory. Will not use dynamic skin.");
-        return 0;
-    }
-
-    snprintf(tmp, sizeof(tmp), "%s/layout", *skinDirPath);
-    D("trying to load skin file '%s'", tmp);
-
-    if(aconfig_load_file(root, tmp) < 0) {
-        dwarning("could not load skin file '%s', won't use a skin\n", tmp);
-        return 0;
-    }
-
-    /* Fix the width and height specified for the "device" part in the layout */
-    node = aconfig_find(root, "parts");
-    if (node != NULL) {
-        node = aconfig_find(node, "device");
-        if (node != NULL) {
-            node = aconfig_find(node, "display");
-            if (node != NULL) {
-                snprintf(tmp, sizeof tmp, "%d", width);
-                aconfig_set(node, "width", strdup(tmp));
-                snprintf(tmp, sizeof tmp, "%d", height);
-                aconfig_set(node, "height", strdup(tmp));
-            }
-        }
-    }
-
-    /* The dynamic layout declares all the parts that are available statically
-       in the layout file. Now we need to dynamically generate the
-       appropriate layout based on the hardware config */
-
-    part_properties* props = read_all_part_properties(aconfig_find(root, "parts"));
-
-    const int N_PARTS = 4;
-    char* parts[N_PARTS];
-    parts[0] = "basic_controls";
-    parts[1] = hwConfig->hw_mainKeys ? "hwkeys_on" : "hwkeys_off";
-    parts[2] = hwConfig->hw_dPad ? "dpad_on" : "dpad_off";
-    parts[3] = hwConfig->hw_keyboard ? "keyboard_on" : "keyboard_off";
-
-    for (i = 0, max_part_width = 0; i < N_PARTS; i++) {
-        part_properties *p = get_part_properties(props, parts[i]);
-        if (p != NULL && p->width > max_part_width)
-                max_part_width = p->width;
-    }
-
-    int x_margin = 10;
-    int y_margin = 10;
-    snprintf(tmp, sizeof tmp,
-            "layouts {\n \
-                portrait {\n \
-                    width %d\n \
-                    height %d\n \
-                    color 0x404040\n \
-                    event EV_SW:0:1\n \
-                    part1 {\n name device\n x 0\n y 0\n}\n \
-                }\n \
-                landscape {\n \
-                    width %d\n \
-                    height %d\n \
-                    color 0x404040\n \
-                    event EV_SW:0:0\n \
-                    dpad-rotation 3\n \
-                    part1 {\n name device\n x 0\n y %d\n rotation 3\n }\n \
-                    }\n \
-                }\n \
-             }\n",
-            width  + max_part_width + 2 * x_margin,
-            height,
-            height + max_part_width + 2 * x_margin,
-            width,
-            width);
-    aconfig_load(root, strdup(tmp));
-
-    /* Add parts to portrait orientation */
-    node = aconfig_find(root, "layouts");
-    if (node != NULL) {
-        node = aconfig_find(node, "portrait");
-        if (node != NULL) {
-            add_parts_to_layout(node, parts, N_PARTS, props, width, x_margin, y_margin);
-        }
-    }
-
-    /* Add parts to landscape orientation */
-    node = aconfig_find(root, "layouts");
-    if (node != NULL) {
-        node = aconfig_find(node, "landscape");
-        if (node != NULL) {
-            add_parts_to_layout(node, parts, N_PARTS, props, height, x_margin, y_margin);
-        }
-    }
-
-    free_all_part_properties(props);
-
-    return 1;
-}
-
-/* list of skin aliases */
-static const struct {
-    const char*  name;
-    const char*  alias;
-} skin_aliases[] = {
-    { "QVGA-L", "320x240" },
-    { "QVGA-P", "240x320" },
-    { "HVGA-L", "480x320" },
-    { "HVGA-P", "320x480" },
-    { "QVGA", "320x240" },
-    { "HVGA", "320x480" },
-    { NULL, NULL }
-};
-
-void
-parse_skin_files(const char*      skinDirPath,
-                 const char*      skinName,
-                 AndroidOptions*  opts,
-                 AndroidHwConfig* hwConfig,
-                 AConfig*        *skinConfig,
-                 char*           *skinPath)
-{
-    char      tmp[1024];
-    AConfig*  root;
-    const char* path = NULL;
-    AConfig*  n;
-
-    root = aconfig_node("", "");
-
-    if (skinName == NULL)
-        goto DEFAULT_SKIN;
-
-    /* Support skin aliases like QVGA-H QVGA-P, etc...
-       But first we check if it's a directory that exist before applying
-       the alias */
-    int  checkAlias = 1;
-
-    if (skinDirPath != NULL) {
-        bufprint(tmp, tmp+sizeof(tmp), "%s/%s", skinDirPath, skinName);
-        if (path_exists(tmp)) {
-            checkAlias = 0;
-        } else {
-            D("there is no '%s' skin in '%s'", skinName, skinDirPath);
-        }
-    }
-
-    if (checkAlias) {
-        int  nn;
-
-        for (nn = 0; ; nn++ ) {
-            const char*  skin_name  = skin_aliases[nn].name;
-            const char*  skin_alias = skin_aliases[nn].alias;
-
-            if (!skin_name)
-                break;
-
-            if (!strcasecmp( skin_name, skinName )) {
-                D("skin name '%s' aliased to '%s'", skinName, skin_alias);
-                skinName = skin_alias;
-                break;
-            }
-        }
-    }
-
-    /* Magically support skins like "320x240" or "320x240x16" */
-    if(isdigit(skinName[0])) {
-        char *x = strchr(skinName, 'x');
-        if(x && isdigit(x[1])) {
-            int width = atoi(skinName);
-            int height = atoi(x+1);
-            int bpp   = 16;
-            char* y = strchr(x+1, 'x');
-            if (y && isdigit(y[1])) {
-                bpp = atoi(y+1);
-            }
-
-            if (opts->dynamic_skin) {
-                char *dynamicSkinDirPath;
-                if (load_dynamic_skin(hwConfig, &dynamicSkinDirPath, width, height, root)) {
-                    path = dynamicSkinDirPath;
-                    D("loaded dynamic skin width=%d height=%d bpp=%d\n", width, height, bpp);
-                    goto FOUND_SKIN;
-                }
-            }
-
-            snprintf(tmp, sizeof tmp,
-                    "display {\n  width %d\n  height %d\n bpp %d}\n",
-                    width, height,bpp);
-            aconfig_load(root, strdup(tmp));
-            path = ":";
-            D("found magic skin width=%d height=%d bpp=%d\n", width, height, bpp);
-            goto FOUND_SKIN;
-        }
-    }
-
-    if (skinDirPath == NULL) {
-        derror("unknown skin name '%s'", skinName);
-        exit(1);
-    }
-
-    snprintf(tmp, sizeof tmp, "%s/%s/layout", skinDirPath, skinName);
-    D("trying to load skin file '%s'", tmp);
-
-    if(aconfig_load_file(root, tmp) < 0) {
-        dwarning("could not load skin file '%s', using built-in one\n",
-                 tmp);
-        goto DEFAULT_SKIN;
-    }
-
-    snprintf(tmp, sizeof tmp, "%s/%s/", skinDirPath, skinName);
-    path = tmp;
-    goto FOUND_SKIN;
-
-FOUND_SKIN:
-    /* the default network speed and latency can now be specified by the device skin */
-    n = aconfig_find(root, "network");
-    if (n != NULL) {
-        skin_network_speed = aconfig_str(n, "speed", 0);
-        skin_network_delay = aconfig_str(n, "delay", 0);
-    }
-
-    /* extract framebuffer information from the skin.
-     *
-     * for version 1 of the skin format, they are in the top-level
-     * 'display' element.
-     *
-     * for version 2 of the skin format, they are under parts.device.display
-     */
-    n = aconfig_find(root, "display");
-    if (n == NULL) {
-        n = aconfig_find(root, "parts");
-        if (n != NULL) {
-            n = aconfig_find(n, "device");
-            if (n != NULL) {
-                n = aconfig_find(n, "display");
-            }
-        }
-    }
-
-    if (n != NULL) {
-        int  width  = aconfig_int(n, "width", hwConfig->hw_lcd_width);
-        int  height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
-        int  depth  = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
-
-        if (width > 0 && height > 0) {
-            /* The emulated framebuffer wants sizes that are multiples of 4 */
-            if (((width|height) & 3) != 0) {
-                width  = (width+3) & ~3;
-                height = (height+3) & ~3;
-                D("adjusting LCD dimensions to (%dx%dx)", width, height);
-            }
-
-            /* only depth values of 16 and 32 are correct. 16 is the default. */
-            if (depth != 32 && depth != 16) {
-                depth = 16;
-                D("adjusting LCD bit depth to %d", depth);
-            }
-
-            hwConfig->hw_lcd_width  = width;
-            hwConfig->hw_lcd_height = height;
-            hwConfig->hw_lcd_depth  = depth;
-        }
-        else {
-            D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
-              width, height, depth);
-        }
-    }
-
-    *skinConfig = root;
-    *skinPath   = strdup(path);
-    return;
-
-DEFAULT_SKIN:
-    {
-        const unsigned char*  layout_base;
-        size_t                layout_size;
-        char*                 base;
-
-        skinName = "<builtin>";
-
-        layout_base = android_resource_find( "layout", &layout_size );
-        if (layout_base == NULL) {
-            fprintf(stderr, "Couldn't load builtin skin\n");
-            exit(1);
-        }
-        base = malloc( layout_size+1 );
-        memcpy( base, layout_base, layout_size );
-        base[layout_size] = 0;
-
-        D("parsing built-in skin layout file (%d bytes)", (int)layout_size);
-        aconfig_load(root, base);
-        path = ":";
-    }
-    goto FOUND_SKIN;
-}
-
-
-void
-init_sdl_ui(AConfig*         skinConfig,
-            const char*      skinPath,
-            AndroidOptions*  opts)
-{
-    int  win_x, win_y, flags;
-
-    signal(SIGINT, SIG_DFL);
-#ifndef _WIN32
-    signal(SIGQUIT, SIG_DFL);
-#endif
-
-    /* we're not a game, so allow the screensaver to run */
-    setenv("SDL_VIDEO_ALLOW_SCREENSAVER","1",1);
-
-    flags = SDL_INIT_NOPARACHUTE;
-    if (!opts->no_window)
-        flags |= SDL_INIT_VIDEO;
-
-    if(SDL_Init(flags)){
-        fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
-        exit(1);
-    }
-
-    if (!opts->no_window) {
-        SDL_EnableUNICODE(!opts->raw_keys);
-        SDL_EnableKeyRepeat(0,0);
-
-        sdl_set_window_icon();
-    }
-    else
-    {
-#ifndef _WIN32
-       /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
-        * able to run the emulator in the background (e.g. "emulator &").
-        * despite the fact that the emulator should not grab input or try to
-        * write to the output in normal cases, we're stopped on some systems
-        * (e.g. OS X)
-        */
-        signal(SIGTTIN, SIG_IGN);
-        signal(SIGTTOU, SIG_IGN);
-#endif
-    }
-    atexit(sdl_at_exit);
-
-    user_config_get_window_pos(&win_x, &win_y);
-
-    if ( qemulator_init(qemulator_get(), skinConfig, skinPath, win_x, win_y, opts) < 0 ) {
-        fprintf(stderr, "### Error: could not load emulator skin from '%s'\n", skinPath);
-        exit(1);
-    }
-
-    /* add an onion overlay image if needed */
-    if (opts->onion) {
-        SkinImage*  onion = skin_image_find_simple( opts->onion );
-        int         alpha, rotate;
-
-        if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
-            alpha = (256*alpha)/100;
-        } else
-            alpha = 128;
-
-        if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
-            rotate &= 3;
-        } else
-            rotate = SKIN_ROTATION_0;
-
-        qemulator_get()->onion          = onion;
-        qemulator_get()->onion_alpha    = alpha;
-        qemulator_get()->onion_rotation = rotate;
-    }
-}
-
 /* this function is used to perform auto-detection of the
  * system directory in the case of a SDK installation.
  *
diff --git a/android/main-common.h b/android/main-common.h
index 523e441..53c9029 100644
--- a/android/main-common.h
+++ b/android/main-common.h
@@ -13,13 +13,20 @@
 #define ANDROID_MAIN_COMMON_H
 
 #include <stdint.h>
-#include "android/cmdline-option.h"
-#include "android/skin/keyset.h"
-#include "android/config-file.h"
 #include "android/avd/hw-config.h"
+#include "android/cmdline-option.h"
+#include "android/config-file.h"
+#include "android/skin/keyset.h"
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
 
 /* Common routines used by both android/main.c and android/main-ui.c */
 
+// Reset the value of |*string| to a copy of |new_value|. This
+// will free() the previous value of |*string| first.
+void reassign_string(char** string, const char* new_value);
+
 /** Emulator user configuration (e.g. last window position)
  **/
 
@@ -103,4 +110,6 @@
  */
 int attach_ui_to_core( AndroidOptions* opts );
 
+ANDROID_END_HEADER
+
 #endif /* ANDROID_MAIN_COMMON_H */
diff --git a/android/main.c b/android/main.c
index 4f48291..b1a3053 100644
--- a/android/main.c
+++ b/android/main.c
@@ -405,14 +405,11 @@
     /* Update CPU architecture for HW configs created from build dir. */
     if (inAndroidBuild) {
 #if defined(TARGET_ARM)
-        free(android_hw->hw_cpu_arch);
-        android_hw->hw_cpu_arch = ASTRDUP("arm");
+        reassign_string(&android_hw->hw_cpu_arch, "arm");
 #elif defined(TARGET_I386)
-        free(android_hw->hw_cpu_arch);
-        android_hw->hw_cpu_arch = ASTRDUP("x86");
+        reassign_string(&android_hw->hw_cpu_arch, "x86");
 #elif defined(TARGET_MIPS)
-        free(android_hw->hw_cpu_arch);
-        android_hw->hw_cpu_arch = ASTRDUP("mips");
+        reassign_string(&android_hw->hw_cpu_arch, "mips");
 #endif
     }
 
@@ -472,8 +469,7 @@
         } else {
             D("Auto-detect: Kernel image requires legacy device naming scheme.");
         }
-        AFREE(hw->kernel_newDeviceNaming);
-        hw->kernel_newDeviceNaming = ASTRDUP(newDeviceNaming);
+        reassign_string(&hw->kernel_newDeviceNaming, newDeviceNaming);
     }
 
     // Auto-detect YAFFS2 partition support if needed.
@@ -486,8 +482,7 @@
         } else {
             D("Auto-detect: Kernel does not support YAFFS2 partitions.");
         }
-        AFREE(hw->kernel_supportsYaffs2);
-        hw->kernel_supportsYaffs2 = ASTRDUP(newYaffs2Support);
+        reassign_string(&hw->kernel_supportsYaffs2, newYaffs2Support);
     }
 
     if (boot_prop_ip[0]) {
@@ -541,8 +536,7 @@
 
     /* opts->ramdisk is never NULL (see createAVD) here */
     if (opts->ramdisk) {
-        AFREE(hw->disk_ramdisk_path);
-        hw->disk_ramdisk_path = ASTRDUP(opts->ramdisk);
+        reassign_string(&hw->disk_ramdisk_path, opts->ramdisk);
     }
     else if (!hw->disk_ramdisk_path[0]) {
         hw->disk_ramdisk_path = avdInfo_getRamdiskPath(avd);
@@ -1157,8 +1151,7 @@
          */
         kcm_extract_charmap_name(opts->charmap, charmap_name,
                                  sizeof(charmap_name));
-        AFREE(hw->hw_keyboard_charmap);
-        hw->hw_keyboard_charmap = ASTRDUP(charmap_name);
+        reassign_string(&hw->hw_keyboard_charmap, charmap_name);
     }
 
     if (opts->gpu) {
@@ -1247,8 +1240,7 @@
                 exit(1);
             }
         } else {
-            AFREE(opts->accel);
-            opts->accel = ASTRDUP("off");
+            reassign_string(&opts->accel, "off");
         }
     }
 
@@ -1382,8 +1374,7 @@
     }
 
     if (forceArmv7 != 0) {
-        AFREE(hw->hw_cpu_model);
-        hw->hw_cpu_model = ASTRDUP("cortex-a8");
+        reassign_string(&hw->hw_cpu_model, "cortex-a8");
         D("Auto-config: -qemu -cpu %s", hw->hw_cpu_model);
     }
 
@@ -1396,8 +1387,7 @@
         char* arch = avdInfo_getTargetCpuArch(avd);
         D("Target arch = '%s'", arch ? arch : "NULL");
         if (arch != NULL && !strcmp(arch, "x86")) {
-            AFREE(hw->hw_cpu_model);
-            hw->hw_cpu_model = ASTRDUP("qemu32");
+            reassign_string(&hw->hw_cpu_model, "qemu32");
             D("Auto-config: -qemu -cpu %s", hw->hw_cpu_model);
         }
         AFREE(arch);
diff --git a/net/net-android.c b/net/net-android.c
index f12e865..23db2f2 100644
--- a/net/net-android.c
+++ b/net/net-android.c
@@ -135,31 +135,6 @@
 
 static VLANState *first_vlan;
 
-/* see http://en.wikipedia.org/wiki/List_of_device_bandwidths or a complete list */
-const NetworkSpeed  android_netspeeds[] = {
-    { "gsm", "GSM/CSD", 14400, 14400 },
-    { "hscsd", "HSCSD", 14400, 43200 },
-    { "gprs", "GPRS", 40000, 80000 },
-    { "edge", "EDGE/EGPRS", 118400, 236800 },
-    { "umts", "UMTS/3G", 128000, 1920000 },
-    { "hsdpa", "HSDPA", 348000, 14400000 },
-    { "full", "no limit", 0, 0 },
-    { NULL, NULL, 0, 0 }
-};
-const size_t android_netspeeds_count =
-    sizeof(android_netspeeds) / sizeof(android_netspeeds[0]);
-
-const NetworkLatency  android_netdelays[] = {
-    /* FIXME: these numbers are totally imaginary */
-    { "gprs", "GPRS", 150, 550 },
-    { "edge", "EDGE/EGPRS", 80, 400 },
-    { "umts", "UMTS/3G", 35, 200 },
-    { "none", "no latency", 0, 0 },
-    { NULL, NULL, 0, 0 }
-};
-const size_t android_netdelays_count =
-    sizeof(android_netdelays) / sizeof(android_netdelays[0]);
-
 /***********************************************************/
 /* network device redirectors */