auto import from //branches/cupcake/...@130745
diff --git a/android/utils/bufprint.c b/android/utils/bufprint.c
new file mode 100644
index 0000000..4309a4b
--- /dev/null
+++ b/android/utils/bufprint.c
@@ -0,0 +1,230 @@
+/* Copyright (C) 2007-2008 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/utils/bufprint.h"
+#include "android/utils/path.h"
+#include "android/utils/debug.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include "windows.h"
+#  include "shlobj.h"
+#else
+#  include <unistd.h>
+#  include <sys/stat.h>
+#endif
+
+#define  D(...)  VERBOSE_PRINT(init,__VA_ARGS__)
+
+
+/** USEFUL STRING BUFFER FUNCTIONS
+ **/
+
+char*
+vbufprint( char*        buffer,
+           char*        buffer_end,
+           const char*  fmt,
+           va_list      args )
+{
+    int  len = vsnprintf( buffer, buffer_end - buffer, fmt, args );
+    if (len < 0 || buffer+len >= buffer_end) {
+        if (buffer < buffer_end)
+            buffer_end[-1] = 0;
+        return buffer_end;
+    }
+    return buffer + len;
+}
+
+char*
+bufprint(char*  buffer, char*  end, const char*  fmt, ... )
+{
+    va_list  args;
+    char*    result;
+
+    va_start(args, fmt);
+    result = vbufprint(buffer, end, fmt, args);
+    va_end(args);
+    return  result;
+}
+
+/** USEFUL DIRECTORY SUPPORT
+ **
+ **  bufprint_app_dir() returns the directory where the emulator binary is located
+ **
+ **  get_android_home() returns a user-specific directory where the emulator will
+ **  store its writable data (e.g. config files, profiles, etc...).
+ **  on Unix, this is $HOME/.android, on Windows, this is something like
+ **  "%USERPROFILE%/Local Settings/AppData/Android" on XP, and something different
+ **  on Vista.
+ **
+ **  both functions return a string that must be freed by the caller
+ **/
+
+#ifdef __linux__
+char*
+bufprint_app_dir(char*  buff, char*  end)
+{
+    char   path[1024];
+    int    len;
+    char*  x;
+
+    len = readlink("/proc/self/exe", path, sizeof(path));
+    if (len <= 0 || len >= (int)sizeof(path)) goto Fail;
+    path[len] = 0;
+
+    x = strrchr(path, '/');
+    if (x == 0) goto Fail;
+    *x = 0;
+
+    return bufprint(buff, end, "%s", path);
+Fail:
+    fprintf(stderr,"cannot locate application directory\n");
+    exit(1);
+    return end;
+}
+
+#elif defined(__APPLE__)
+/* the following hack is needed in order to build with XCode 3.1
+ * don't ask me why, but it seems that there were changes in the
+ * GCC compiler that we don't have in our pre-compiled version
+ */
+#ifndef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ MAC_OS_X_VERSION_10_4
+#endif
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+char*
+bufprint_app_dir(char*  buff, char*  end)
+{
+    ProcessSerialNumber psn;
+    CFDictionaryRef     dict;
+    CFStringRef         value;
+    char                s[PATH_MAX];
+    char*               x;
+
+    GetCurrentProcess(&psn);
+    dict  = ProcessInformationCopyDictionary(&psn, 0xffffffff);
+    value = (CFStringRef)CFDictionaryGetValue(dict,
+                                             CFSTR("CFBundleExecutable"));
+    CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
+    x = strrchr(s, '/');
+    if (x == 0) goto fail;
+    *x = 0;
+
+    return bufprint(buff, end, "%s", s);
+fail:
+    fprintf(stderr,"cannot locate application directory\n");
+    exit(1);
+    return end;
+}
+#elif defined _WIN32
+char*
+bufprint_app_dir(char*  buff, char*  end)
+{
+    char   appDir[MAX_PATH];
+	int    len;
+	char*  sep;
+
+    len = GetModuleFileName( 0, appDir, sizeof(appDir)-1 );
+	if (len == 0) {
+		fprintf(stderr, "PANIC CITY!!\n");
+		exit(1);
+	}
+	if (len >= (int)sizeof(appDir)) {
+		len = sizeof(appDir)-1;
+	    appDir[len] = 0;
+    }
+	
+	sep = strrchr(appDir, '\\');
+	if (sep)
+	  *sep = 0;
+
+    return bufprint(buff, end, "%s", appDir);
+}
+#else
+char*
+bufprint_app_dir(char*  buff, char*  end)
+{
+    return bufprint(buff, end, ".");
+}
+#endif
+
+#define  _ANDROID_PATH   ".android"
+
+char*
+bufprint_config_path(char*  buff, char*  end)
+{
+#ifdef _WIN32
+    const char*  home = getenv("ANDROID_SDK_HOME");
+    if (home != NULL) {
+        return bufprint(buff, end, "%s\\%s", home, _ANDROID_PATH );
+    } else {
+        char  path[MAX_PATH];
+
+        SHGetFolderPath( NULL, CSIDL_PROFILE,
+                         NULL, 0, path);
+
+        return bufprint(buff, end, "%s\\%s", path, _ANDROID_PATH );
+    }
+#else
+    const char*  home = getenv("HOME");
+    if (home == NULL)
+        home = "/tmp";
+    return bufprint(buff, end, "%s/%s", home, _ANDROID_PATH );
+#endif
+}
+
+char*
+bufprint_config_file(char*  buff, char*  end, const char*  suffix)
+{
+    char*   p;
+    p = bufprint_config_path(buff, end);
+    p = bufprint(p, end, PATH_SEP "%s", suffix);
+    return p;
+}
+
+char*
+bufprint_temp_dir(char*  buff, char*  end)
+{
+#ifdef _WIN32
+    char   path[MAX_PATH];
+    DWORD  retval;
+
+    retval = GetTempPath( sizeof(path), path );
+    if (retval > sizeof(path) || retval == 0) {
+        D( "can't locate TEMP directory" );
+        strncpy(path, "C:\\Temp", sizeof(path) );
+    }
+    strncat( path, "\\AndroidEmulator", sizeof(path)-1 );
+    path_mkdir(path, 0744);
+
+    return  bufprint(buff, end, "%s", path);
+#else
+    const char*  tmppath = "/tmp/android";
+    mkdir(tmppath, 0744);
+    return  bufprint(buff, end, "%s", tmppath );
+#endif
+}
+
+char*
+bufprint_temp_file(char*  buff, char*  end, const char*  suffix)
+{
+    char*  p;
+    p = bufprint_temp_dir(buff, end);
+    p = bufprint(p, end, PATH_SEP "%s", suffix);
+    return p;
+}
+
diff --git a/android/utils/bufprint.h b/android/utils/bufprint.h
new file mode 100644
index 0000000..32d64dc
--- /dev/null
+++ b/android/utils/bufprint.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2007-2008 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.
+*/
+
+#ifndef _ANDROID_UTILS_BUFPRINT_H
+#define _ANDROID_UTILS_BUFPRINT_H
+
+#include <stdarg.h>
+
+/** FORMATTED BUFFER PRINTING
+ **
+ **  bufprint() allows your to easily and safely append formatted string
+ **  content to a given bounded character buffer, in a way that is easier
+ **  to use than raw snprintf()
+ **
+ **  'buffer'  is the start position in the buffer,
+ **  'buffend' is the end of the buffer, the function assumes (buffer <= buffend)
+ **  'format'  is a standard printf-style format string, followed by any number
+ **            of formatting arguments
+ **
+ **  the function returns the next position in the buffer if everything fits
+ **  in it. in case of overflow or formatting error, it will always return "buffend"
+ **
+ **  this allows you to chain several calls to bufprint() and only check for
+ **  overflow at the end, for exemple:
+ **
+ **     char   buffer[1024];
+ **     char*  p   = buffer;
+ **     char*  end = p + sizeof(buffer);
+ **
+ **     p = bufprint(p, end, "%s/%s", first, second);
+ **     p = bufprint(p, end, "/%s", third);
+ **     if (p >= end) ---> overflow
+ **
+ **  as a convenience, the appended string is zero-terminated if there is no overflow.
+ **  (this means that even if p >= end, the content of "buffer" is zero-terminated)
+ **
+ **  vbufprint() is a variant that accepts a va_list argument
+ **/
+
+extern char*   vbufprint(char*  buffer, char*  buffend, const char*  fmt, va_list  args );
+extern char*   bufprint (char*  buffer, char*  buffend, const char*  fmt, ... );
+
+/** USEFUL DIRECTORY SUPPORT
+ **
+ **  bufprint_add_dir() appends the application's directory to a given bounded buffer
+ **
+ **  bufprint_config_path() appends the applications' user-specific configuration directory
+ **  to a bounded buffer. on Unix this is usually ~/.android, and something a bit more
+ **  complex on Windows
+ **
+ **  bufprint_config_file() appends the name of a file or directory relative to the
+ **  user-specific configuration directory to a bounded buffer. this really is equivalent
+ **  to concat-ing the config path + path separator + 'suffix'
+ **
+ **  bufprint_temp_dir() appends the temporary directory's path to a given bounded buffer
+ **
+ **  bufprint_temp_file() appens the name of a file or directory relative to the
+ **  temporary directory. equivalent to concat-ing the temp path + path separator + 'suffix'
+ **/
+
+extern char*  bufprint_app_dir    (char*  buffer, char*  buffend);
+extern char*  bufprint_config_path(char*  buffer, char*  buffend);
+extern char*  bufprint_config_file(char*  buffer, char*  buffend, const char*  suffix);
+extern char*  bufprint_temp_dir   (char*  buffer, char*  buffend);
+extern char*  bufprint_temp_file  (char*  buffer, char*  buffend, const char*  suffix);
+
+#endif /* _ANDROID_UTILS_BUFPRINT_H */
diff --git a/android/utils/debug.c b/android/utils/debug.c
new file mode 100644
index 0000000..32936d2
--- /dev/null
+++ b/android/utils/debug.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2007-2008 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/utils/debug.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+void
+dprint( const char*  format,  ... )
+{
+    va_list  args;
+    va_start( args, format );
+    fprintf( stdout, "emulator: ");
+    vfprintf( stdout, format, args );
+    fprintf( stdout, "\n" );
+    va_end( args );
+}
+
+void
+dprintn( const char*  format, ... )
+{
+    va_list  args;
+    va_start( args, format );
+    vfprintf( stdout, format, args );
+    va_end( args );
+}
+
+void
+dprintnv( const char*  format, va_list args )
+{
+    vfprintf( stdout, format, args );
+}
+
+
+void
+dwarning( const char*  format, ... )
+{
+    va_list  args;
+    va_start( args, format );
+    dprintn( "emulator: WARNING: " );
+    dprintnv( format, args );
+    dprintn( "\n" );
+    va_end( args );
+}
+
+
+void
+derror( const char*  format, ... )
+{
+    va_list  args;
+    va_start( args, format );
+    dprintn( "emulator: ERROR: " );
+    dprintnv( format, args );
+    dprintn( "\n" );
+    va_end( args );
+}
+
+/** STDOUT/STDERR REDIRECTION
+ **
+ ** allows you to shut temporarily shutdown stdout/stderr
+ ** this is useful to get rid of debug messages from ALSA and esd
+ ** on Linux.
+ **/
+static int    stdio_disable_count;
+static int    stdio_save_out_fd;
+static int    stdio_save_err_fd;
+
+#ifdef _WIN32
+extern void
+stdio_disable( void )
+{
+    if (++stdio_disable_count == 1) {
+        int  null_fd, out_fd, err_fd;
+        fflush(stdout);
+        out_fd = _fileno(stdout);
+        err_fd = _fileno(stderr);
+        stdio_save_out_fd = _dup(out_fd);
+        stdio_save_err_fd = _dup(err_fd);
+        null_fd = _open( "NUL", _O_WRONLY );
+        _dup2(null_fd, out_fd);
+        _dup2(null_fd, err_fd);
+        close(null_fd);
+    }
+}
+
+extern void
+stdio_enable( void )
+{
+    if (--stdio_disable_count == 0) {
+        int  out_fd, err_fd;
+        fflush(stdout);
+        out_fd = _fileno(stdout);
+        err_fd = _fileno(stderr);
+        _dup2(stdio_save_out_fd, out_fd);
+        _dup2(stdio_save_err_fd, err_fd);
+        _close(stdio_save_out_fd);
+        _close(stdio_save_err_fd);
+    }
+}
+#else
+extern void
+stdio_disable( void )
+{
+    if (++stdio_disable_count == 1) {
+        int  null_fd, out_fd, err_fd;
+        fflush(stdout);
+        out_fd = fileno(stdout);
+        err_fd = fileno(stderr);
+        stdio_save_out_fd = dup(out_fd);
+        stdio_save_err_fd = dup(err_fd);
+        null_fd = open( "/dev/null", O_WRONLY );
+        dup2(null_fd, out_fd);
+        dup2(null_fd, err_fd);
+        close(null_fd);
+    }
+}
+
+extern void
+stdio_enable( void )
+{
+    if (--stdio_disable_count == 0) {
+        int  out_fd, err_fd;
+        fflush(stdout);
+        out_fd = fileno(stdout);
+        err_fd = fileno(stderr);
+        dup2(stdio_save_out_fd, out_fd);
+        dup2(stdio_save_err_fd, err_fd);
+        close(stdio_save_out_fd);
+        close(stdio_save_err_fd);
+    }
+}
+#endif
diff --git a/android/utils/debug.h b/android/utils/debug.h
index 28b93ee..fdf93c9 100644
--- a/android/utils/debug.h
+++ b/android/utils/debug.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008 The Android Open Source Project
+/* Copyright (C) 2007-2008 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
@@ -12,7 +12,80 @@
 #ifndef _ANDROID_UTILS_DEBUG_H
 #define _ANDROID_UTILS_DEBUG_H
 
-/* we'll move android_debug.h here later */
-#include "android_debug.h"
+#include <stdarg.h>
+
+#define  VERBOSE_TAG_LIST    \
+    _VERBOSE_TAG(init,         "emulator initialization")  \
+    _VERBOSE_TAG(console,      "control console")  \
+    _VERBOSE_TAG(modem,        "emulated GSM modem")  \
+    _VERBOSE_TAG(radio,        "emulated GSM AT Command channel") \
+    _VERBOSE_TAG(keys,         "key bindings & presses") \
+    _VERBOSE_TAG(slirp,        "internal router/firewall") \
+    _VERBOSE_TAG(timezone,     "host timezone detection" ) \
+    _VERBOSE_TAG(socket,       "network sockets") \
+    _VERBOSE_TAG(proxy,        "network proxy support") \
+    _VERBOSE_TAG(audio,        "audio sub-system") \
+    _VERBOSE_TAG(audioin,      "audio input backend") \
+    _VERBOSE_TAG(audioout,     "audio output backend") \
+    _VERBOSE_TAG(surface,      "video surface support") \
+    _VERBOSE_TAG(qemud,        "qemud multiplexer daemon") \
+    _VERBOSE_TAG(gps,          "emulated GPS") \
+    _VERBOSE_TAG(nand_limits,  "nand/flash read/write thresholding") \
+    _VERBOSE_TAG(hw_control,   "emulated power/flashlight/led/vibrator") \
+    _VERBOSE_TAG(avd_config,   "android virtual device configuration") \
+
+#define  _VERBOSE_TAG(x,y)  VERBOSE_##x,
+typedef enum {
+    VERBOSE_TAG_LIST
+    VERBOSE_MAX  /* do not remove */
+} VerboseTag;
+#undef  _VERBOSE_TAG
+
+/* defined in android_main.c */
+extern unsigned long  android_verbose;
+
+#define  VERBOSE_ENABLE(tag)    \
+    android_verbose |= (1 << VERBOSE_##tag)
+
+#define  VERBOSE_DISABLE(tag)   \
+    android_verbose &= (1 << VERBOSE_##tag)
+
+#define  VERBOSE_CHECK(tag)    \
+    ((android_verbose & (1 << VERBOSE_##tag)) != 0)
+
+#define  VERBOSE_CHECK_ANY()    \
+    (android_verbose != 0)
+
+#define  VERBOSE_PRINT(tag,...)  \
+    do { if (VERBOSE_CHECK(tag)) dprint(__VA_ARGS__); } while (0)
+
+/** DEBUG TRACE SUPPORT
+ **
+ ** debug messages can be sent by calling these function
+ **
+ ** 'dprint' prints the message, then appends a '\n\
+ ** 'dprintn' simply prints the message as is
+ ** 'dprintnv' allows you to use a va_list argument
+ ** 'dwarning' prints a warning message, then appends a '\n'
+ ** 'derror' prints a severe error message, then appends a '\n'
+ */
+
+extern void   dprint( const char*  format, ... );
+extern void   dprintn( const char*  format, ... );
+extern void   dprintnv( const char*  format, va_list  args );
+extern void   dwarning( const char*  format, ... );
+extern void   derror( const char*  format, ... );
+
+/** STDOUT/STDERR REDIRECTION
+ **
+ ** allows you to shut temporarily shutdown stdout/stderr
+ ** this is useful to get rid of debug messages from ALSA and esd
+ ** on Linux.
+ **/
+
+extern void  stdio_disable( void );
+extern void  stdio_enable( void );
+
+/* */
 
 #endif /* _ANDROID_UTILS_DEBUG_H */
diff --git a/android/utils/dirscanner.c b/android/utils/dirscanner.c
index 9f44d2d..fc63ef0 100644
--- a/android/utils/dirscanner.c
+++ b/android/utils/dirscanner.c
@@ -10,8 +10,8 @@
 ** GNU General Public License for more details.
 */
 #include "android/utils/dirscanner.h"
-#include "android_utils.h"
-#include "vl.h"
+#include "android/utils/bufprint.h"
+#include "qemu-common.h"
 #include <stddef.h>
 
 #define  DIRSCANNER_BASE     \
@@ -46,7 +46,7 @@
     if (p >= end)
         return -1;
 
-    ret = _findfirst(s->root, &s->findData) + 1;
+    ret = _findfirst(s->root, &s->findData);
 
     s->findIndex1 = ret+1;
     return ret;
diff --git a/android/utils/dirscanner.h b/android/utils/dirscanner.h
index 9486cfc..871b05e 100644
--- a/android/utils/dirscanner.h
+++ b/android/utils/dirscanner.h
@@ -17,9 +17,35 @@
 
 typedef struct DirScanner  DirScanner;
 
+/* Create a new directory scanner object from a given rootPath.
+ * returns NULL in case of failure (error code in errno)
+ */
 DirScanner*    dirScanner_new ( const char*  rootPath );
+
+/* Destroy a given directory scanner. You must always call
+ * this function to release proper system resources.
+ */
 void           dirScanner_free( DirScanner*  s );
+
+/* Get the name of the next file from a directory scanner.
+ * Returns NULL when there is no more elements in the list.
+ *
+ * This is only the file name, use dirScanner_nextFull to
+ * get its full path.
+ *
+ * This will never return '.' and '..'.
+ *
+ * The returned string is owned by the scanner, and will
+ * change on the next call to this function or when the
+ * scanner is destroyed.
+ */
 const char*    dirScanner_next( DirScanner*  s );
+
+/* A variant of dirScanner_next() which returns the full path
+ * to the next directory element.
+ */
 const char*    dirScanner_nextFull( DirScanner*  s );
 
+/* */
+
 #endif /* _ANDROID_UTILS_DIR_H */
diff --git a/android/utils/display-quartz.m b/android/utils/display-quartz.m
new file mode 100644
index 0000000..594657e
--- /dev/null
+++ b/android/utils/display-quartz.m
@@ -0,0 +1,111 @@
+/* Copyright (C) 2007-2008 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.
+*/
+
+/* this is the Quartz-specific implementation of
+ * <android/utils/display.h>
+ */
+
+#include "android/utils/display.h"
+#include "android/utils/debug.h"
+
+#define  D(...)   VERBOSE_PRINT(init,__VA_ARGS__)
+
+#include <stdio.h>
+#include <Cocoa/Cocoa.h>
+#include <Carbon/Carbon.h>
+#include <SDL_syswm.h>
+
+int
+get_monitor_resolution( int  *px_dpi, int  *py_dpi )
+{
+    fprintf(stderr, "emulator: FIXME: implement get_monitor_resolution on OS X\n" );
+    return -1;
+}
+
+int
+get_nearest_monitor_rect( int  *x, int  *y, int  *width, int  *height )
+{
+    SDL_SysWMinfo  info;
+    NSWindow*      window;
+
+    SDL_VERSION(&info.version);
+    if ( SDL_GetWMInfo(&info) < 0 ) {
+        D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+        return -1;
+    }
+    window = info.nsWindowPtr;
+    if (window == NULL) {
+        D( "%s: SDL_GetWMInfo() returned NULL NSWindow ptr",
+           __FUNCTION__ );
+        return -1;
+    }
+    else
+    {
+        NSRect        frame   = [ window frame ];
+        int           fx1     = frame.origin.x;
+        int           fy1     = frame.origin.y;
+        int           fx2     = frame.size.width + fx1;
+        int           fy2     = frame.size.height + fy1; 
+        NSArray*      screens = [ NSScreen screens ];
+        unsigned int  count   = [ screens count ];
+        int           bestScreen = -1;
+        int           bestArea = 0;
+
+        unsigned int  n;
+        printf( "window frame (%d,%d) (%d,%d)\n", fx1, fy1, fx2, fy2 );
+
+        /* we need to compute which screen has the most window pixels */
+        for (n = 0; n < count; n++) {
+            NSScreen*  screen = [ screens objectAtIndex: n ];
+            NSRect     vis    = [ screen visibleFrame ];
+            int        vx1    = vis.origin.x;
+            int        vy1    = vis.origin.y;
+            int        vx2    = vis.size.width + vx1;
+            int        vy2    = vis.size.height + vy1;
+            int        cx1, cx2, cy1, cy2, cArea;
+
+            //printf( "screen %d/%d  frame (%d,%d) (%d,%d)\n", n+1, count,
+            //        vx1, vy1, vx2, vy2 );
+
+            if (fx1 >= vx2 || vx1 >= fx2 || fy1 >= vy2 || vy1 >= fy2)
+                continue;
+
+            cx1 = (fx1 < vx1) ? vx1 : fx1;
+            cx2 = (fx2 > vx2) ? vx2 : fx2;
+            cy1 = (fy1 < vy1) ? vy1 : fy1;
+            cy2 = (fy2 > vy2) ? vy2 : fy2;
+
+            if (cx1 >= cx2 || cy1 >= cy2)
+                continue;
+
+            cArea = (cx2-cx1)*(cy2-cy1);
+
+            if (bestScreen < 0 || cArea > bestArea) {
+                bestScreen = n;
+                bestArea   = cArea;
+            }
+        }
+        if (bestScreen < 0)
+            bestScreen = 0;
+
+        {
+            NSScreen*  screen = [ screens objectAtIndex: bestScreen ];
+            NSRect     vis    = [ screen visibleFrame ];
+
+            *x      = vis.origin.x;
+            *y      = vis.origin.y;
+            *width  = vis.size.width;
+            *height = vis.size.height; 
+        }
+        return 0;
+    }
+};
diff --git a/android/utils/display.c b/android/utils/display.c
new file mode 100644
index 0000000..e1ba507
--- /dev/null
+++ b/android/utils/display.c
@@ -0,0 +1,245 @@
+/* Copyright (C) 2007-2008 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/utils/display.h"
+#include "android/utils/debug.h"
+
+#define  D(...)   VERBOSE_PRINT(init,__VA_ARGS__)
+
+/** HOST RESOLUTION SETTINGS
+ **
+ ** return the main monitor's DPI resolution according to the host device
+ ** beware: this is not always reliable or even obtainable.
+ **
+ ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
+ **/
+
+/** NOTE: the following code assumes that we exclusively use X11 on Linux, and Quartz on OS X
+ **/
+
+#ifdef _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <SDL_syswm.h>
+
+int
+get_monitor_resolution( int  *px_dpi, int  *py_dpi )
+{
+    HDC  displayDC = CreateDC( "DISPLAY", NULL, NULL, NULL );
+    int  xdpi, ydpi;
+
+    if (displayDC == NULL) {
+        D( "%s: could not get display DC\n", __FUNCTION__ );
+        return -1;
+    }
+    xdpi = GetDeviceCaps( displayDC, LOGPIXELSX );
+    ydpi = GetDeviceCaps( displayDC, LOGPIXELSY );
+
+    /* sanity checks */
+    if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
+        D( "%s: bad resolution: xpi=%d ydpi=%d", __FUNCTION__,
+                xdpi, ydpi );
+        return -1;
+    }
+
+    *px_dpi = xdpi;
+    *py_dpi = ydpi;
+    return 0;
+}
+
+int
+get_nearest_monitor_rect( int  *x, int  *y, int  *width, int  *height )
+{
+    SDL_SysWMinfo  info;
+    HMONITOR       monitor;
+    MONITORINFO    monitorInfo;
+
+    SDL_VERSION(&info.version);
+
+    if ( !SDL_GetWMInfo(&info) ) {
+        D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+        return -1;
+    }
+
+    monitor = MonitorFromWindow( info.window, MONITOR_DEFAULTTONEAREST );
+    monitorInfo.cbSize = sizeof(monitorInfo);
+    GetMonitorInfo( monitor, &monitorInfo );
+
+    *x      = monitorInfo.rcMonitor.left;
+    *y      = monitorInfo.rcMonitor.top;
+    *width  = monitorInfo.rcMonitor.right - *x;
+    *height = monitorInfo.rcMonitor.bottom - *y;
+
+    D("%s: found (x,y,w,h)=(%d,%d,%d,%d)", __FUNCTION__,
+      *x, *y, *width, *height);
+
+    return 0;
+}
+
+
+#elif defined __APPLE__
+
+/* the real implementation is in display-quartz.m, but
+ * unfortunately, the Android build system doesn't know
+ * how to build Objective-C sources, so provide stubs
+ * here instead.
+ *
+ * CONFIG_NO_COCOA is set by Makefile.android
+ */
+
+#ifdef CONFIG_NO_COCOA
+int
+get_monitor_resolution( int  *px_dpi, int  *py_dpi )
+{
+    return -1;
+}
+
+int
+get_nearest_monitor_rect( int  *x, int  *y, int  *width, int  *height )
+{
+    return -1;
+}
+#endif /* CONFIG_NO_COCOA */
+
+#else  /* Linux and others */
+#include <SDL.h>
+#include <SDL_syswm.h>
+#include <dlfcn.h>
+#include <X11/Xlib.h>
+#define  MM_PER_INCH   25.4
+
+#define  DYNLINK_FUNCTIONS  \
+    DYNLINK_FUNC(int,XDefaultScreen,(Display*)) \
+    DYNLINK_FUNC(int,XDisplayWidth,(Display*,int)) \
+    DYNLINK_FUNC(int,XDisplayWidthMM,(Display*,int)) \
+    DYNLINK_FUNC(int,XDisplayHeight,(Display*,int)) \
+    DYNLINK_FUNC(int,XDisplayHeightMM,(Display*,int)) \
+
+#define  DYNLINK_FUNCTIONS_INIT \
+    x11_dynlink_init
+
+#include "dynlink.h"
+
+static int    x11_lib_inited;
+static void*  x11_lib;
+
+int
+x11_lib_init( void )
+{
+    if (!x11_lib_inited) {
+        x11_lib_inited = 1;
+
+        x11_lib = dlopen( "libX11.so", RTLD_NOW );
+
+        if (x11_lib == NULL) {
+            x11_lib = dlopen( "libX11.so.6", RTLD_NOW );
+        }
+        if (x11_lib == NULL) {
+            D("%s: Could not find libX11.so on this machine",
+              __FUNCTION__);
+            return -1;
+        }
+
+        if (x11_dynlink_init(x11_lib) < 0) {
+            D("%s: didn't find necessary symbols in libX11.so",
+              __FUNCTION__);
+            dlclose(x11_lib);
+            x11_lib = NULL;
+        }
+    }
+    return x11_lib ? 0 : -1;
+}
+
+
+int
+get_monitor_resolution( int  *px_dpi, int  *py_dpi )
+{
+    SDL_SysWMinfo info;
+    Display*      display;
+    int           screen;
+    int           width, width_mm, height, height_mm, xdpi, ydpi;
+
+    SDL_VERSION(&info.version);
+
+    if ( !SDL_GetWMInfo(&info) ) {
+        D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+        return -1;
+    }
+
+    if (x11_lib_init() < 0)
+        return -1;
+
+    display = info.info.x11.display;
+    screen  = FF(XDefaultScreen)(display);
+
+    width     = FF(XDisplayWidth)(display, screen);
+    width_mm  = FF(XDisplayWidthMM)(display, screen);
+    height    = FF(XDisplayHeight)(display, screen);
+    height_mm = FF(XDisplayHeightMM)(display, screen);
+
+    if (width_mm <= 0 || height_mm <= 0) {
+        D( "%s: bad screen dimensions: width_mm = %d, height_mm = %d",
+                __FUNCTION__, width_mm, height_mm);
+        return -1;
+    }
+
+    D( "%s: found screen width=%d height=%d width_mm=%d height_mm=%d",
+            __FUNCTION__, width, height, width_mm, height_mm );
+
+    xdpi = width  * MM_PER_INCH / width_mm;
+    ydpi = height * MM_PER_INCH / height_mm;
+
+    if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
+        D( "%s: bad resolution: xpi=%d ydpi=%d", __FUNCTION__,
+                xdpi, ydpi );
+        return -1;
+    }
+
+    *px_dpi = xdpi;
+    *py_dpi = ydpi;
+
+    return 0;
+}
+
+int
+get_nearest_monitor_rect( int  *x, int *y, int  *width, int  *height )
+{
+    SDL_SysWMinfo info;
+    Display*      display;
+    int           screen;
+
+    SDL_VERSION(&info.version);
+
+    if ( !SDL_GetWMInfo(&info) ) {
+        D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+        return -1;
+    }
+
+    if (x11_lib_init() < 0)
+        return -1;
+
+    display = info.info.x11.display;
+    screen  = FF(XDefaultScreen)(display);
+
+    *x      = 0;
+    *y      = 0;
+    *width  = FF(XDisplayWidth)(display, screen);
+    *height = FF(XDisplayHeight)(display, screen);
+
+    D("%s: found (x,y,w,h)=(%d,%d,%d,%d)", __FUNCTION__,
+      *x, *y, *width, *height);
+
+    return 0;
+}
+
+#endif
diff --git a/android/utils/display.h b/android/utils/display.h
new file mode 100644
index 0000000..7254aca
--- /dev/null
+++ b/android/utils/display.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2007-2008 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.
+*/
+
+#ifndef _ANDROID_UTILS_DISPLAY_H
+#define _ANDROID_UTILS_DISPLAY_H
+
+/** HOST RESOLUTION SETTINGS
+ **
+ ** return the main monitor's DPI resolution according to the host device
+ ** beware: this is not always reliable or even obtainable.
+ **
+ ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
+ **/
+extern  int    get_monitor_resolution( int  *px_dpi, int  *py_dpi );
+
+/** return the size in pixels of the nearest monitor for the current window.
+ ** this is used to implement full-screen presentation mode.
+ **/
+
+extern  int    get_nearest_monitor_rect( int  *x, int *y, int *width, int *height );
+
+#endif /* _ANDROID_UTILS_DISPLAY_H */
diff --git a/android/utils/filelock.c b/android/utils/filelock.c
new file mode 100644
index 0000000..a8b18da
--- /dev/null
+++ b/android/utils/filelock.c
@@ -0,0 +1,414 @@
+/* Copyright (C) 2007-2008 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/utils/filelock.h"
+#include "android/utils/path.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <fcntl.h>
+#ifdef _WIN32
+#  include <process.h>
+#  include <windows.h>
+#  include <tlhelp32.h>
+#else
+#  include <sys/types.h>
+#  include <unistd.h>
+#  include <signal.h>
+#endif
+
+#define  D(...)  ((void)0)
+
+#ifndef CHECKED
+#  ifdef _WIN32
+#    define   CHECKED(ret, call)    (ret) = (call)
+#  else
+#    define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+#  endif
+#endif
+
+/** FILE LOCKS SUPPORT
+ **
+ ** a FileLock is useful to prevent several emulator instances from using the same
+ ** writable file (e.g. the userdata.img disk images).
+ **
+ ** create a FileLock object with filelock_create(), ithis function should return NULL
+ ** only if the corresponding file path could not be locked.
+ **
+ ** all file locks are automatically released and destroyed when the program exits.
+ ** the filelock_lock() function can also detect stale file locks that can linger
+ ** when the emulator crashes unexpectedly, and will happily clean them for you
+ **
+ **  here's how it works, three files are used:
+ **     file  - the data file accessed by the emulator
+ **     lock  - a lock file  (file + '.lock')
+ **     temp  - a temporary file make unique with mkstemp
+ **
+ **  when locking:
+ **      create 'temp' and store our pid in it
+ **      attemp to link 'lock' to 'temp'
+ **         if the link succeeds, we obtain the lock
+ **      unlink 'temp'
+ **
+ **  when unlocking:
+ **      unlink 'lock'
+ **
+ **
+ **  on Windows, 'lock' is a directory name. locking is equivalent to
+ **  creating it...
+ **
+ **/
+
+struct FileLock
+{
+  const char*  file;
+  const char*  lock;
+  char*        temp;
+  int          locked;
+  FileLock*    next;
+};
+
+/* used to cleanup all locks at emulator exit */
+static FileLock*   _all_filelocks;
+
+
+#define  LOCK_NAME   ".lock"
+#define  TEMP_NAME   ".tmp-XXXXXX"
+
+#ifdef _WIN32
+#define  PIDFILE_NAME  "pid"
+#endif
+
+/* returns 0 on success, -1 on failure */
+static int
+filelock_lock( FileLock*  lock )
+{
+    int    ret;
+#ifdef _WIN32
+    int  pidfile_fd = -1;
+
+    ret = _mkdir( lock->lock );
+    if (ret < 0) {
+        if (errno == ENOENT) {
+            D( "could not access directory '%s', check path elements", lock->lock );
+            return -1;
+        } else if (errno != EEXIST) {
+            D( "_mkdir(%s): %s", lock->lock, strerror(errno) );
+            return -1;
+        }
+
+        /* if we get here, it's because the .lock directory already exists */
+        /* check to see if there is a pid file in it                       */
+        D("directory '%s' already exist, waiting a bit to ensure that no other emulator instance is starting", lock->lock );
+        {
+            int  _sleep = 200;
+            int  tries;
+
+            for ( tries = 4; tries > 0; tries-- )
+            {
+                pidfile_fd = open( lock->temp, O_RDONLY );
+
+                if (pidfile_fd >= 0)
+                    break;
+
+                Sleep( _sleep );
+                _sleep *= 2;
+            }
+        }
+
+        if (pidfile_fd < 0) {
+            D( "no pid file in '%s', assuming stale directory", lock->lock );
+        }
+        else
+        {
+            /* read the pidfile, and check wether the corresponding process is still running */
+            char            buf[16];
+            int             len, lockpid;
+            HANDLE          processSnapshot;
+            PROCESSENTRY32  pe32;
+            int             is_locked = 0;
+
+            len = read( pidfile_fd, buf, sizeof(buf)-1 );
+            if (len < 0) {
+                D( "could not read pid file '%s'", lock->temp );
+                close( pidfile_fd );
+                return -1;
+            }
+            buf[len] = 0;
+            lockpid  = atoi(buf);
+
+            /* PID 0 is the IDLE process, and 0 is returned in case of invalid input */
+            if (lockpid == 0)
+                lockpid = -1;
+
+            close( pidfile_fd );
+
+            pe32.dwSize     = sizeof( PROCESSENTRY32 );
+            processSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+
+            if ( processSnapshot == INVALID_HANDLE_VALUE ) {
+                D( "could not retrieve the list of currently active processes\n" );
+                is_locked = 1;
+            }
+            else if ( !Process32First( processSnapshot, &pe32 ) )
+            {
+                D( "could not retrieve first process id\n" );
+                CloseHandle( processSnapshot );
+                is_locked = 1;
+            }
+            else
+            {
+                do {
+                    if (pe32.th32ProcessID == lockpid) {
+                        is_locked = 1;
+                        break;
+                    }
+                } while (Process32Next( processSnapshot, &pe32 ) );
+
+                CloseHandle( processSnapshot );
+            }
+
+            if (is_locked) {
+                D( "the file '%s' is locked by process ID %d\n", lock->file, lockpid );
+                return -1;
+            }
+        }
+    }
+
+    /* write our PID into the pid file */
+    pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC );
+    if (pidfile_fd < 0) {
+        if (errno == EACCES) {
+            if ( path_delete_file( lock->temp ) < 0 ) {
+                D( "could not remove '%s': %s\n", lock->temp, strerror(errno) );
+                return -1;
+            }
+            pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC );
+        }
+        if (pidfile_fd < 0) {
+            D( "could not create '%s': %s\n", lock->temp, strerror(errno) );
+            return -1;
+        }
+    }
+
+    {
+        char  buf[16];
+        sprintf( buf, "%ld", GetCurrentProcessId() );
+        ret = write( pidfile_fd, buf, strlen(buf) );
+        close(pidfile_fd);
+        if (ret < 0) {
+            D( "could not write PID to '%s'\n", lock->temp );
+            return -1;
+        }
+    }
+
+    lock->locked = 1;
+    return 0;
+#else
+    int    temp_fd = -1;
+    int    lock_fd = -1;
+    int    rc, tries, _sleep;
+    FILE*  f = NULL;
+    char   pid[8];
+    struct stat  st_temp;
+
+    strcpy( lock->temp, lock->file );
+    strcat( lock->temp, TEMP_NAME );
+    temp_fd = mkstemp( lock->temp );
+
+    if (temp_fd < 0) {
+        D("cannot create locking temp file '%s'", lock->temp );
+        goto Fail;
+    }
+
+    sprintf( pid, "%d", getpid() );
+    ret = write( temp_fd, pid, strlen(pid)+1 );
+    if (ret < 0) {
+        D( "cannot write to locking temp file '%s'", lock->temp);
+        goto Fail;
+    }
+    close( temp_fd );
+    temp_fd = -1;
+
+    CHECKED(rc, lstat( lock->temp, &st_temp ));
+    if (rc < 0) {
+        D( "can't properly stat our locking temp file '%s'", lock->temp );
+        goto Fail;
+    }
+
+    /* now attempt to link the temp file to the lock file */
+    _sleep = 0;
+    for ( tries = 4; tries > 0; tries-- )
+    {
+        struct stat  st_lock;
+        int          rc;
+
+        if (_sleep > 0) {
+            if (_sleep > 2000000) {
+                D( "cannot acquire lock file '%s'", lock->lock );
+                goto Fail;
+            }
+            usleep( _sleep );
+        }
+        _sleep += 200000;
+
+        /* the return value of link() is buggy on NFS */
+        CHECKED(rc, link( lock->temp, lock->lock ));
+
+        CHECKED(rc, lstat( lock->lock, &st_lock ));
+        if (rc == 0 &&
+            st_temp.st_rdev == st_lock.st_rdev &&
+            st_temp.st_ino  == st_lock.st_ino  )
+        {
+            /* SUCCESS */
+            lock->locked = 1;
+            CHECKED(rc, unlink( lock->temp ));
+            return 0;
+        }
+
+        /* if we get there, it means that the link() call failed */
+        /* check the lockfile to see if it is stale              */
+        if (rc == 0) {
+            char    buf[16];
+            time_t  now;
+            int     lockpid = 0;
+            int     lockfd;
+            int     stale = 2;  /* means don't know */
+            struct stat  st;
+
+            CHECKED(rc, time( &now));
+            st.st_mtime = now - 120;
+
+            CHECKED(lockfd, open( lock->lock,O_RDONLY ));
+            if ( lockfd >= 0 ) {
+                int  len;
+
+                CHECKED(len, read( lockfd, buf, sizeof(buf)-1 ));
+                buf[len] = 0;
+                lockpid = atoi(buf);
+
+                CHECKED(rc, fstat( lockfd, &st ));
+                if (rc == 0)
+                  now = st.st_atime;
+
+                CHECKED(rc, close(lockfd));
+            }
+            /* if there is a PID, check that it is still alive */
+            if (lockpid > 0) {
+                CHECKED(rc, kill( lockpid, 0 ));
+                if (rc == 0 || errno == EPERM) {
+                    stale = 0;
+                } else if (rc < 0 && errno == ESRCH) {
+                    stale = 1;
+                }
+            }
+            if (stale == 2) {
+                /* no pid, stale if the file is older than 1 minute */
+                stale = (now >= st.st_mtime + 60);
+            }
+
+            if (stale) {
+                D( "removing stale lockfile '%s'", lock->lock );
+                CHECKED(rc, unlink( lock->lock ));
+                _sleep = 0;
+                tries++;
+            }
+        }
+    }
+    D("file '%s' is already in use by another process", lock->file );
+
+Fail:
+    if (f)
+        fclose(f);
+
+    if (temp_fd >= 0) {
+        close(temp_fd);
+    }
+
+    if (lock_fd >= 0) {
+        close(lock_fd);
+    }
+
+    unlink( lock->lock );
+    unlink( lock->temp );
+    return -1;
+#endif
+}
+
+void
+filelock_release( FileLock*  lock )
+{
+    if (lock->locked) {
+#ifdef _WIN32
+        path_delete_file( (char*)lock->temp );
+        rmdir( (char*)lock->lock );
+#else
+        unlink( (char*)lock->lock );
+#endif
+        lock->locked = 0;
+    }
+}
+
+static void
+filelock_atexit( void )
+{
+  FileLock*  lock;
+
+  for (lock = _all_filelocks; lock != NULL; lock = lock->next)
+     filelock_release( lock );
+}
+
+/* create a file lock */
+FileLock*
+filelock_create( const char*  file )
+{
+    int    file_len = strlen(file);
+    int    lock_len = file_len + sizeof(LOCK_NAME);
+#ifdef _WIN32
+    int    temp_len = lock_len + 1 + sizeof(PIDFILE_NAME);
+#else
+    int    temp_len = file_len + sizeof(TEMP_NAME);
+#endif
+    int    total_len = sizeof(FileLock) + file_len + lock_len + temp_len + 3;
+
+    FileLock*  lock = malloc(total_len);
+
+    lock->file = (const char*)(lock + 1);
+    memcpy( (char*)lock->file, file, file_len+1 );
+
+    lock->lock = lock->file + file_len + 1;
+    memcpy( (char*)lock->lock, file, file_len+1 );
+    strcat( (char*)lock->lock, LOCK_NAME );
+
+    lock->temp    = (char*)lock->lock + lock_len + 1;
+#ifdef _WIN32
+    snprintf( (char*)lock->temp, temp_len, "%s\\" PIDFILE_NAME, lock->lock );
+#else
+    lock->temp[0] = 0;
+#endif
+    lock->locked = 0;
+
+    if (filelock_lock(lock) < 0) {
+        free(lock);
+        return NULL;
+    }
+
+    lock->next     = _all_filelocks;
+    _all_filelocks = lock;
+
+    if (lock->next == NULL)
+        atexit( filelock_atexit );
+
+    return lock;
+}
diff --git a/android/utils/filelock.h b/android/utils/filelock.h
new file mode 100644
index 0000000..9bc86b5
--- /dev/null
+++ b/android/utils/filelock.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2007-2008 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.
+*/
+
+#ifndef _ANDROID_UTILS_FILELOCK_H
+#define _ANDROID_UTILS_FILELOCK_H
+
+/** FILE LOCKS SUPPORT
+ **
+ ** a FileLock is useful to prevent several emulator instances from using the same
+ ** writable file (e.g. the userdata.img disk images).
+ **
+ ** create a FileLock object with filelock_create(), the function will return
+ ** NULL only if the corresponding path is already locked by another emulator
+ ** of if the path is read-only.
+ **
+ ** note that 'path' can designate a non-existing path and that the lock creation
+ ** function can detect stale file locks that can longer when the emulator
+ ** crashes unexpectedly, and will happily clean them for you.
+ **
+ ** you can call filelock_release() to release a file lock explicitely. otherwise
+ ** all file locks are automatically released when the program exits.
+ **/
+
+typedef struct FileLock  FileLock;
+
+extern FileLock*  filelock_create ( const char*  path );
+extern void       filelock_release( FileLock*  lock );
+
+#endif /* _ANDROID_UTILS_FILELOCK_H */
diff --git a/android/utils/ini.c b/android/utils/ini.c
index 98355d4..56e40f2 100644
--- a/android/utils/ini.c
+++ b/android/utils/ini.c
@@ -15,12 +15,13 @@
 #include <string.h>
 #include <limits.h>
 #include <errno.h>
-#include "android_debug.h"
+#include "android/utils/debug.h"
+#include "android/utils/system.h" /* for ASTRDUP */
 #include "osdep.h"
 
 /* W() is used to print warnings, D() to print debugging info */
 #define  W(...)   dwarning(__VA_ARGS__)
-#define  D(...)   VERBOSE_PRINT(vm_config,__VA_ARGS__)
+#define  D(...)   VERBOSE_PRINT(avd_config,__VA_ARGS__)
 
 /* a simple .ini file parser and container for Android
  * no sections support. see android/utils/ini.h for
@@ -42,18 +43,20 @@
 {
     int  nn;
     for (nn = 0; nn < i->numPairs; nn++) {
-        free(i->pairs[nn].key);
+        AFREE(i->pairs[nn].key);
         i->pairs[nn].key   = NULL;
         i->pairs[nn].value = NULL;
     }
-    free(i->pairs);
-    free(i);
+    AFREE(i->pairs);
+    AFREE(i);
 }
 
 static IniFile*
 iniFile_alloc( void )
 {
-    IniFile*  i = calloc(1, sizeof(*i));
+    IniFile*  i;
+
+    ANEW0(i);
     return i;
 }
 
@@ -64,17 +67,16 @@
     IniPair*  pair;
 
     if (i->numPairs >= i->maxPairs) {
-        int       oldMax   = i->maxPairs;
-        int       newMax   = oldMax + (oldMax >> 1) + 4;
-        IniPair*  newPairs = realloc(i->pairs, newMax*sizeof(newPairs[0]));
+        int       oldMax = i->maxPairs;
+        int       newMax = oldMax + (oldMax >> 1) + 4;
 
-        i->pairs    = newPairs;
+        AARRAY_RENEW(i->pairs, newMax);
         i->maxPairs = newMax;
     }
 
     pair = i->pairs + i->numPairs;
 
-    pair->key   = malloc(keyLen + valueLen + 2);
+    AARRAY_NEW(pair->key, keyLen + valueLen + 2);
     memcpy(pair->key, key, keyLen);
     pair->key[keyLen] = 0;
 
@@ -269,12 +271,12 @@
     }
 
     /* read the file, add a sentinel at the end of it */
-    text = malloc(size+1);
+    AARRAY_NEW(text, size+1);
     fread(text, 1, size, fp);
     text[size] = 0;
 
     ini = iniFile_newFromMemory(text, filepath);
-    free(text);
+    AFREE(text);
 
 EXIT:
     fclose(fp);
@@ -289,7 +291,7 @@
     if (!val)
         return NULL;
 
-    return qemu_strdup(val);
+    return ASTRDUP(val);
 }
 
 int
@@ -345,8 +347,8 @@
 int64_t
 iniFile_getDiskSize( IniFile*  f, const char*  key, const char*  defaultValue )
 {
-    const char*    valStr = iniFile_getValue(f, key);
-    int64_t        value  = 0;
+    const char*  valStr = iniFile_getValue(f, key);
+    int64_t      value  = 0;
 
     if (!valStr)
         valStr = defaultValue;
@@ -364,3 +366,21 @@
     }
     return value;
 }
+
+int64_t
+iniFile_getInt64( IniFile*  f, const char*  key, int64_t  defaultValue )
+{
+    const char*  valStr = iniFile_getValue(f, key);
+    int64_t      value  = defaultValue;
+
+    if (valStr != NULL) {
+        char*    end;
+        int64_t  d;
+
+        d = strtoll(valStr, &end, 10);
+        if (end != NULL && end[0] == 0)
+            value = d;
+    }
+    return value;
+}
+
diff --git a/android/utils/ini.h b/android/utils/ini.h
index ad6b36a..bc8193e 100644
--- a/android/utils/ini.h
+++ b/android/utils/ini.h
@@ -93,6 +93,11 @@
  */
 int     iniFile_getInteger( IniFile*  f, const char*  key, int  defaultValue );
 
+/* returns a 64-bit integer value, or a default in case the value string is
+ * missing or badly formatted
+ */
+int64_t iniFile_getInt64( IniFile*  f, const char*  key, int64_t  defaultValue );
+
 /* returns a double value, or a default in case the value string is
  * missing or badly formatted
  */
diff --git a/android/utils/misc.c b/android/utils/misc.c
new file mode 100644
index 0000000..818ab78
--- /dev/null
+++ b/android/utils/misc.c
@@ -0,0 +1,193 @@
+/* Copyright (C) 2007-2008 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/utils/misc.h"
+#include "android/utils/stralloc.h"
+#include "android/utils/debug.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void
+print_tabular( const char** strings, int  count,
+               const char*  prefix,  int  width )
+{
+    int  nrows, ncols, r, c, n, maxw = 0;
+
+    for (n = 0; n < count; n++) {
+        int  len = strlen(strings[n]);
+        if (len > maxw)
+            maxw = len;
+    }
+    maxw += 2;
+    ncols = width/maxw;
+    nrows = (count + ncols-1)/ncols;
+
+    for (r = 0; r < nrows; r++) {
+        printf( "%s", prefix );
+        for (c = 0; c < ncols; c++) {
+            int  index = c*nrows + r;
+            if (index >= count) {
+                break;
+            }
+            printf( "%-*s", maxw, strings[index] );
+        }
+        printf( "\n" );
+    }
+}
+
+extern void
+string_translate_char( char*  str, char from, char to )
+{
+    char*  p = str;
+    while (p != NULL && (p = strchr(p, from)) != NULL)
+        *p++ = to;
+}
+
+extern void
+buffer_translate_char( char*        buff,
+                       unsigned     buffLen,
+                       const char*  src,
+                       char         fromChar,
+                       char         toChar )
+{
+    int    len = strlen(src);
+
+    if (len >= buffLen)
+        len = buffLen-1;
+
+    memcpy(buff, src, len);
+    buff[len] = 0;
+
+    string_translate_char( buff, fromChar, toChar );
+}
+
+
+/** TEMP CHAR STRINGS
+ **
+ ** implement a circular ring of temporary string buffers
+ **/
+
+typedef struct Temptring {
+    struct TempString*  next;
+    char*               buffer;
+    int                 size;
+} TempString;
+
+#define  MAX_TEMP_STRINGS   16
+
+static TempString  _temp_strings[ MAX_TEMP_STRINGS ];
+static int         _temp_string_n;
+
+extern char*
+tempstr_get( int  size )
+{
+    TempString*  t = &_temp_strings[_temp_string_n];
+
+    if ( ++_temp_string_n >= MAX_TEMP_STRINGS )
+        _temp_string_n = 0;
+
+    size += 1;  /* reserve 1 char for terminating zero */
+
+    if (t->size < size) {
+        t->buffer = realloc( t->buffer, size );
+        if (t->buffer == NULL) {
+            derror( "%s: could not allocate %d bytes",
+                    __FUNCTION__, size );
+            exit(1);
+        }
+        t->size   = size;
+    }
+    return  t->buffer;
+}
+
+extern char*
+tempstr_format( const char*  fmt, ... )
+{
+    va_list  args;
+    char*    result;
+    STRALLOC_DEFINE(s);
+    va_start(args, fmt);
+    stralloc_formatv(s, fmt, args);
+    va_end(args);
+    result = stralloc_to_tempstr(s);
+    stralloc_reset(s);
+    return result;
+}
+
+/** QUOTING
+ **
+ ** dumps a human-readable version of a string. this replaces
+ ** newlines with \n, etc...
+ **/
+
+extern const char*
+quote_bytes( const char*  str, int  len )
+{
+    STRALLOC_DEFINE(s);
+    char*  q;
+
+    stralloc_add_quote_bytes( s, str, len );
+    q = stralloc_to_tempstr( s );
+    stralloc_reset(s);
+    return q;
+}
+
+extern const char*
+quote_str( const char*  str )
+{
+    int  len = strlen(str);
+    return quote_bytes( str, len );
+}
+
+/** HEXADECIMAL CHARACTER SEQUENCES
+ **/
+
+static int
+hexdigit( int  c )
+{
+    unsigned  d;
+
+    d = (unsigned)(c - '0');
+    if (d < 10) return d;
+
+    d = (unsigned)(c - 'a');
+    if (d < 6) return d+10;
+
+    d = (unsigned)(c - 'A');
+    if (d < 6) return d+10;
+
+    return -1;
+}
+
+int
+hex2int( const uint8_t*  hex, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int  c = hexdigit(*hex++);
+        if (c < 0)
+            return -1;
+
+        result = (result << 4) | c;
+        len --;
+    }
+    return result;
+}
+
+void
+int2hex( uint8_t*  hex, int  len, int  val )
+{
+    static const uint8_t  hexchars[16] = "0123456789abcdef";
+    while ( --len >= 0 )
+        *hex++ = hexchars[(val >> (len*4)) & 15];
+}
diff --git a/android/utils/misc.h b/android/utils/misc.h
new file mode 100644
index 0000000..0db1e28
--- /dev/null
+++ b/android/utils/misc.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2007-2008 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.
+*/
+#ifndef _ANDROID_UTILS_MISC_H
+#define _ANDROID_UTILS_MISC_H
+
+#include <stdint.h>
+
+/** TABULAR OUTPUT
+ **
+ ** prints a list of strings in row/column format
+ **
+ **/
+
+extern void   print_tabular( const char** strings, int  count,
+                             const char*  prefix,  int  width );
+
+/** CHARACTER TRANSLATION
+ **
+ ** converts one character into another in strings
+ **/
+
+extern void   buffer_translate_char( char*        buff,
+                                     unsigned     buffLen,
+                                     const char*  src,
+                                     char         fromChar,
+                                     char         toChar );
+
+extern void   string_translate_char( char*  str, char from, char to );
+
+/** TEMP CHAR STRINGS
+ **
+ ** implement a circular ring of temporary string buffers
+ **/
+
+extern char*  tempstr_get( int   size );
+extern char*  tempstr_format( const char*  fmt, ... );
+
+/** QUOTING
+ **
+ ** dumps a human-readable version of a string. this replaces
+ ** newlines with \n, etc...
+ **/
+
+extern const char*   quote_bytes( const char*  str, int  len );
+extern const char*   quote_str( const char*  str );
+
+/** DECIMAL AND HEXADECIMAL CHARACTER SEQUENCES
+ **/
+
+/* decodes a sequence of 'len' hexadecimal chars from 'hex' into
+ * an integer. returns -1 in case of error (i.e. badly formed chars)
+ */
+extern int    hex2int( const uint8_t*  hex, int  len );
+
+/* encodes an integer 'val' into 'len' hexadecimal charaters into 'hex' */
+extern void   int2hex( uint8_t*  hex, int  len, int  val );
+
+#endif /* _ANDROID_UTILS_MISC_H */
diff --git a/android/utils/path.c b/android/utils/path.c
new file mode 100644
index 0000000..9dd238e
--- /dev/null
+++ b/android/utils/path.c
@@ -0,0 +1,430 @@
+/* Copyright (C) 2007-2009 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/utils/path.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+#include <process.h>
+#include <shlobj.h>
+#include <tlhelp32.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <limits.h>
+#include <winbase.h>
+#else
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+#endif
+
+#define  D(...)  ((void)0)
+
+#ifndef CHECKED
+#  ifdef _WIN32
+#    define   CHECKED(ret, call)    (ret) = (call)
+#  else
+#    define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+#  endif
+#endif
+
+/** PATH HANDLING ROUTINES
+ **
+ **  path_parent() can be used to return the n-level parent of a given directory
+ **  this understands . and .. when encountered in the input path
+ **/
+
+static __inline__ int
+ispathsep(int  c)
+{
+#ifdef _WIN32
+    return (c == '/' || c == '\\');
+#else
+    return (c == '/');
+#endif
+}
+
+char*
+path_parent( const char*  path, int  levels )
+{
+    const char*  end = path + strlen(path);
+    char*        result;
+
+    while (levels > 0) {
+        const char*  base;
+
+        /* trim any trailing path separator */
+        while (end > path && ispathsep(end[-1]))
+            end--;
+
+        base = end;
+        while (base > path && !ispathsep(base[-1]))
+            base--;
+
+        if (base <= path) /* we can't go that far */
+            return NULL;
+
+        if (end == base+1 && base[0] == '.')
+            goto Next;
+
+        if (end == base+2 && base[0] == '.' && base[1] == '.') {
+            levels += 1;
+            goto Next;
+        }
+
+        levels -= 1;
+
+    Next:
+        end = base - 1;
+    }
+    result = malloc( end-path+1 );
+    if (result != NULL) {
+        memcpy( result, path, end-path );
+        result[end-path] = 0;
+    }
+    return result;
+}
+
+
+/** MISC FILE AND DIRECTORY HANDLING
+ **/
+
+ABool
+path_exists( const char*  path )
+{
+    int  ret;
+    CHECKED(ret, access(path, F_OK));
+    return (ret == 0) || (errno != ENOENT);
+}
+
+/* checks that a path points to a regular file */
+ABool
+path_is_regular( const char*  path )
+{
+    int          ret;
+    struct stat  st;
+
+    CHECKED(ret, stat(path, &st));
+    if (ret < 0)
+        return 0;
+
+    return S_ISREG(st.st_mode);
+}
+
+
+/* checks that a path points to a directory */
+ABool
+path_is_dir( const char*  path )
+{
+    int          ret;
+    struct stat  st;
+
+    CHECKED(ret, stat(path, &st));
+    if (ret < 0)
+        return 0;
+
+    return S_ISDIR(st.st_mode);
+}
+
+/* checks that one can read/write a given (regular) file */
+ABool
+path_can_read( const char*  path )
+{
+    int  ret;
+    CHECKED(ret, access(path, R_OK));
+    return (ret == 0);
+}
+
+ABool
+path_can_write( const char*  path )
+{
+    int  ret;
+    CHECKED(ret, access(path, R_OK));
+    return (ret == 0);
+}
+
+/* try to make a directory. returns 0 on success, -1 on failure
+ * (error code in errno) */
+APosixStatus
+path_mkdir( const char*  path, int  mode )
+{
+#ifdef _WIN32
+    (void)mode;
+    return _mkdir(path);
+#else
+    int  ret;
+    CHECKED(ret, mkdir(path, mode));
+    return ret;
+#endif
+}
+
+static APosixStatus
+path_mkdir_recursive( char*  path, unsigned  len, int  mode )
+{
+    char      old_c;
+    int       ret;
+    unsigned  len2;
+
+    /* get rid of trailing separators */
+    while (len > 0 && ispathsep(path[len-1]))
+        len -= 1;
+
+    if (len == 0) {
+        errno = ENOENT;
+        return -1;
+    }
+
+    /* check that the parent exists, 'len2' is the length of
+     * the parent part of the path */
+    len2 = len-1;
+    while (len2 > 0 && !ispathsep(path[len2-1]))
+        len2 -= 1;
+
+    if (len2 > 0) {
+        old_c      = path[len2];
+        path[len2] = 0;
+        ret        = 0;
+        if ( !path_exists(path) ) {
+            /* the parent doesn't exist, so try to create it */
+            ret = path_mkdir_recursive( path, len2, mode );
+        }
+        path[len2] = old_c;
+
+        if (ret < 0)
+            return ret;
+    }
+
+    /* at this point, we now the parent exists */
+    old_c     = path[len];
+    path[len] = 0;
+    ret       = path_mkdir( path, mode );
+    path[len] = old_c;
+
+    return ret;
+}
+
+/* ensure that a given directory exists, create it if not, 
+   0 on success, -1 on failure (error code in errno) */
+APosixStatus
+path_mkdir_if_needed( const char*  path, int  mode )
+{
+    int  ret = 0;
+
+    if (!path_exists(path)) {
+        ret = path_mkdir(path, mode);
+
+        if (ret < 0 && errno == ENOENT) {
+            char      temp[MAX_PATH];
+            unsigned  len = (unsigned)strlen(path);
+
+            if (len > sizeof(temp)-1) {
+                errno = EINVAL;
+                return -1;
+            }
+            memcpy( temp, path, len );
+            temp[len] = 0;
+
+            return path_mkdir_recursive(temp, len, mode);
+        }
+    }
+    return ret;
+}
+
+/* return the size of a given file in '*psize'. returns 0 on
+ * success, -1 on failure (error code in errno) */
+APosixStatus
+path_get_size( const char*  path, uint64_t  *psize )
+{
+#ifdef _WIN32
+    /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
+    /* do not use OpenFile() because it has strange search behaviour that could */
+    /* result in getting the size of a different file */
+    LARGE_INTEGER  size;
+    HANDLE  file = CreateFile( /* lpFilename */        path,
+                               /* dwDesiredAccess */   GENERIC_READ,    
+                               /* dwSharedMode */     FILE_SHARE_READ|FILE_SHARE_WRITE, 
+                               /* lpSecurityAttributes */  NULL, 
+                               /* dwCreationDisposition */ OPEN_EXISTING,
+                               /* dwFlagsAndAttributes */  0,
+                               /* hTemplateFile */      NULL );
+    if (file == INVALID_HANDLE_VALUE) {
+        /* ok, just to play fair */
+        errno = ENOENT;
+        return -1;
+    }
+    if (!GetFileSizeEx(file, &size)) {
+        /* maybe we tried to get the size of a pipe or something like that ? */
+        *psize = 0;
+    }
+    else {
+        *psize = (uint64_t) size.QuadPart;
+    }
+    CloseHandle(file);
+    return 0;
+#else
+    int    ret;
+    struct stat  st;
+
+    CHECKED(ret, stat(path, &st));
+    if (ret == 0) {
+        *psize = (uint64_t) st.st_size;
+    }
+    return ret;
+#endif
+}
+
+
+/** OTHER FILE UTILITIES
+ **
+ **  path_empty_file() creates an empty file at a given path location.
+ **  if the file already exists, it is truncated without warning
+ **
+ **  path_copy_file() copies one file into another.
+ **
+ **  both functions return 0 on success, and -1 on error
+ **/
+
+APosixStatus
+path_empty_file( const char*  path )
+{
+#ifdef _WIN32
+    int  fd = _creat( path, S_IWRITE );
+#else
+    /* on Unix, only allow the owner to read/write, since the file *
+     * may contain some personal data we don't want to see exposed */
+    int  fd = creat(path, S_IRUSR | S_IWUSR);
+#endif
+    if (fd >= 0) {
+        close(fd);
+        return 0;
+    }
+    return -1;
+}
+
+APosixStatus
+path_copy_file( const char*  dest, const char*  source )
+{
+    int  fd, fs, result = -1;
+
+    /* if the destination doesn't exist, create it */
+    if ( access(source, F_OK)  < 0 ||
+         path_empty_file(dest) < 0) {
+        return -1;
+    }
+
+#ifdef _WIN32
+    fd = _open(dest, _O_RDWR | _O_BINARY);
+    fs = _open(source, _O_RDONLY |  _O_BINARY);
+#else
+    fd = creat(dest, S_IRUSR | S_IWUSR);
+    fs = open(source, S_IREAD);
+#endif
+    if (fs >= 0 && fd >= 0) {
+        char buf[4096];
+        ssize_t total = 0;
+        ssize_t n;
+        result = 0; /* success */
+        while ((n = read(fs, buf, 4096)) > 0) {
+            if (write(fd, buf, n) != n) {
+                /* write failed. Make it return -1 so that an
+                 * empty file be created. */
+                D("Failed to copy '%s' to '%s': %s (%d)",
+                       source, dest, strerror(errno), errno);
+                result = -1;
+                break;
+            }
+            total += n;
+        }
+    }
+
+    if (fs >= 0) {
+        close(fs);
+    }
+    if (fd >= 0) {
+        close(fd);
+    }
+    return result;
+}
+
+
+APosixStatus
+path_delete_file( const char*  path )
+{
+#ifdef _WIN32
+    int  ret = _unlink( path );
+    if (ret == -1 && errno == EACCES) {
+        /* a first call to _unlink will fail if the file is set read-only */
+        /* we can however try to change its mode first and call unlink    */
+        /* again...                                                       */
+        ret = _chmod( path, _S_IREAD | _S_IWRITE );
+        if (ret == 0)
+            ret = _unlink( path );
+    }
+    return ret;
+#else
+    return  unlink(path);
+#endif
+}
+
+
+void*
+path_load_file(const char *fn, size_t  *pSize)
+{
+    char*  data;
+    int    sz;
+    int    fd;
+
+    if (pSize)
+        *pSize = 0;
+
+    data   = NULL;
+
+    fd = open(fn, O_BINARY | O_RDONLY);
+    if(fd < 0) return NULL;
+
+    do {
+        sz = lseek(fd, 0, SEEK_END);
+        if(sz < 0) break;
+
+        if (pSize)
+            *pSize = (size_t) sz;
+
+        if (lseek(fd, 0, SEEK_SET) != 0)
+            break;
+
+        data = (char*) malloc(sz + 1);
+        if(data == NULL) break;
+
+        if (read(fd, data, sz) != sz)
+            break;
+
+        close(fd);
+        data[sz] = 0;
+
+        return data;
+    } while (0);
+
+    close(fd);
+
+    if(data != NULL)
+        free(data);
+
+    return NULL;
+}
+
diff --git a/android/utils/path.h b/android/utils/path.h
new file mode 100644
index 0000000..10436c6
--- /dev/null
+++ b/android/utils/path.h
@@ -0,0 +1,122 @@
+/* Copyright (C) 2007-2009 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.
+*/
+#ifndef _ANDROID_UTILS_PATH_H
+#define _ANDROID_UTILS_PATH_H
+
+#include <android/utils/system.h>
+#include <stdint.h>  /* for uint64_t */
+
+/** MISC FILE AND DIRECTORY HANDLING
+ **/
+
+/* O_BINARY is required in the MS C library to avoid opening file
+ * in text mode (the default, ahhhhh)
+ */
+#if !defined(_WIN32) && !defined(O_BINARY)
+#  define  O_BINARY  0
+#endif
+
+/* define  PATH_SEP as a string containing the directory separateor */
+#ifdef _WIN32
+#  define  PATH_SEP   "\\"
+#else
+#  define  PATH_SEP   "/"
+#endif
+
+/* get MAX_PATH, note that PATH_MAX is set to 260 on Windows for
+ * stupid backwards-compatibility reason, though any 32-bit version
+ * of the OS handles much much longer paths
+ */
+#ifdef _WIN32
+#  undef   MAX_PATH
+#  define  MAX_PATH    1024
+#  undef   PATH_MAX
+#  define  PATH_MAX    MAX_PATH
+#else
+#  include <limits.h>
+#  define  MAX_PATH    PATH_MAX
+#endif
+
+/* checks that a given file exists */
+extern ABool  path_exists( const char*  path );
+
+/* checks that a path points to a regular file */
+extern ABool  path_is_regular( const char*  path );
+
+/* checks that a path points to a directory */
+extern ABool  path_is_dir( const char*  path );
+
+/* checks that one can read/write a given (regular) file */
+extern ABool  path_can_read( const char*  path );
+extern ABool  path_can_write( const char*  path );
+
+/* try to make a directory */
+extern APosixStatus   path_mkdir( const char*  path, int  mode );
+
+/* ensure that a given directory exists, create it if not, 
+   0 on success, -1 on error */
+extern APosixStatus   path_mkdir_if_needed( const char*  path, int  mode );
+
+/* return the size of a given file in '*psize'. returns 0 on
+ * success, -1 on failure (error code in errno) */
+extern APosixStatus   path_get_size( const char*  path, uint64_t  *psize );
+
+/*  path_parent() can be used to return the n-level parent of a given directory
+ *  this understands . and .. when encountered in the input path.
+ *
+ *  the returned string must be freed by the caller.
+ */
+extern char*  path_parent( const char*  path, int  levels );
+
+/** OTHER FILE UTILITIES
+ **
+ **  path_empty_file() creates an empty file at a given path location.
+ **  if the file already exists, it is truncated without warning
+ **
+ **  path_copy_file() copies one file into another.
+ **
+ **  unlink_file() is equivalent to unlink() on Unix, on Windows,
+ **  it will handle the case where _unlink() fails because the file is
+ **  read-only by trying to change its access rights then calling _unlink()
+ **  again.
+ **
+ **  these functions return 0 on success, and -1 on error
+ **
+ **  load_text_file() reads a file into a heap-allocated memory block,
+ **  and appends a 0 to it. the caller must free it
+ **/
+
+/* creates an empty file at a given location. If the file already
+ * exists, it is truncated without warning. returns 0 on success,
+ * or -1 on failure.
+ */
+extern APosixStatus   path_empty_file( const char*  path );
+
+/* copies on file into another one. 0 on success, -1 on failure
+ * (error code in errno). Does not work on directories */
+extern APosixStatus   path_copy_file( const char*  dest, const char*  source );
+
+/* unlink/delete a given file. Note that on Win32, this will
+ * fail if the program has an opened handle to the file
+ */
+extern APosixStatus   path_delete_file( const char*  path );
+
+/* try to load a given file into a heap-allocated block.
+ * if 'pSize' is not NULL, this will set the file's size in '*pSize'
+ * note that this actually zero-terminates the file for convenience.
+ * In case of failure, NULL is returned and the error code is in errno
+ */
+extern void*          path_load_file( const char*  path, size_t  *pSize );
+
+/* */
+
+#endif /* _ANDROID_UTILS_PATH_H */
diff --git a/android/utils/reflist.c b/android/utils/reflist.c
new file mode 100644
index 0000000..bc604cd
--- /dev/null
+++ b/android/utils/reflist.c
@@ -0,0 +1,203 @@
+/* Copyright (C) 2007-2008 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/utils/reflist.h"
+#include <stdlib.h>
+#include <string.h>
+
+void
+areflist_setEmpty(ARefList*  l)
+{
+    if (l->iteration > 0) {
+        /* deferred empty, set all items to NULL
+         * to stop iterations */
+        void**  items = areflist_items(l);
+        memset(items, 0, l->count*sizeof(items[0]));
+        l->iteration |= 1;
+    } else {
+        /* direct empty */
+        if (l->max > 1) {
+            free(l->u.items);
+            l->max = 1;
+        }
+    }
+    l->count = 0;
+}
+
+int
+areflist_indexOf(ARefList*  l, void*  item)
+{
+    if (item) {
+        void**  items = (l->max == 1) ? &l->u.item0 : l->u.items;
+        void**  end   = items + l->count;
+        void**  ii    = items;
+
+        for ( ; ii < end; ii += 1 )
+            if (*ii == item)
+                return (ii - items);
+    }
+    return -1;
+}
+
+static void
+areflist_grow(ARefList*  l, int  count)
+{
+    int   newcount = l->count + count;
+    if (newcount > l->max) {
+        int  oldmax = l->max == 1 ? 0 : l->max;
+        int  newmax = oldmax;
+        void**  olditems = l->max == 1 ? NULL : l->u.items;
+        void**  newitems;
+
+        while (oldmax < newcount)
+            oldmax += (oldmax >> 1) + 4;
+
+        newitems = realloc(olditems, newmax*sizeof(newitems[0]));
+
+        l->u.items = newitems;
+        l->max     = (uint16_t) newmax;
+    }
+}
+
+
+void
+areflist_add(ARefList*  l, void*  item)
+{
+    if (item) {
+        void**  items;
+
+        if (l->count >= l->max) {
+            areflist_grow(l, 1);
+        }
+        items = areflist_items(l);
+        items[l->count] = item;
+        l->count += 1;
+    }
+}
+
+void*
+areflist_pop(ARefList*  l)
+{
+    void*   item = NULL;
+    void**  items = areflist_items(l);
+
+    if (l->count > 0) {
+        if (l->iteration > 0) {
+            /* deferred deletion */
+            int  nn;
+            for (nn = l->count-1; nn > 0; nn--) {
+                item = items[nn];
+                if (item != NULL) {
+                    l->count -= 1;
+                    return item;
+                }
+            }
+        } else {
+            /* normal pop */
+            item = items[--l->count];
+            if (l->count <= 0 && l->max > 1) {
+                free(l->u.items);
+                l->max = 1;
+            }
+        }
+    }
+    return item;
+}
+
+ABool
+areflist_del(ARefList*  l, void*  item)
+{
+    if (item) {
+        int  index = areflist_indexOf(l, item);
+        if (index >= 0) {
+            void** items = areflist_items(l);
+
+            if (l->iteration > 0) {
+                /* deferred deletion */
+                items[index]  = NULL;
+                l->iteration |= 1;
+            } else {
+                /* direct deletion */
+                if (l->max > 1) {
+                    memmove(items + index, items + index + 1, l->count - index - 1);
+                    if (--l->count == 0) {
+                        free(l->u.items);
+                        l->max = 1;
+                    }
+                } else {
+                    l->u.item0 = NULL;
+                    l->count   = 0;
+                }
+            }
+            return 1;
+        }
+    }
+    return 0;
+}
+
+void
+_areflist_remove_deferred(ARefList*  l)
+{
+    if (l->iteration & 1) {
+        /* remove all NULL elements from the array */
+        void**  items = areflist_items(l);
+        int     rr = 0;
+        int     ww = 0;
+        for ( ; rr < l->count; rr++ ) {
+            if (items[rr] != NULL)
+                items[ww++] = items[rr];
+        }
+        l->count = (int16_t) ww;
+
+        /* if the list is empty, release its array */
+        if (l->count == 0 && l->max > 1) {
+            free(l->u.items);
+            l->max = 1;
+        }
+    }
+    l->iteration = 0;
+}
+
+void  
+areflist_copy(ARefList*  dst, ARefList*  src)
+{
+    dst[0] = src[0];
+
+    if (src->max > 1) {
+        dst->u.items = malloc( dst->count*sizeof(void*) );
+        dst->max     = dst->count;
+    }
+}
+
+void*
+areflist_get(ARefList*  l, int  n)
+{
+    if ((unsigned)n >= (unsigned)l->count)
+        return NULL;
+
+    if (l->max == 1)
+        return l->u.item0;
+
+    return l->u.items[n];
+}
+
+void**
+areflist_at(ARefList*  l, int  n)
+{
+    void**  items;
+
+    if ((unsigned)n >= (unsigned)l->count)
+        return NULL;
+
+    items = (l->max == 1) ? &l->u.item0 : l->u.items;
+
+    return items + n;
+}
diff --git a/android/utils/reflist.h b/android/utils/reflist.h
new file mode 100644
index 0000000..dffaef8
--- /dev/null
+++ b/android/utils/reflist.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2007-2008 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.
+*/
+#ifndef _ANDROID_UTILS_REFLIST_H
+#define _ANDROID_UTILS_REFLIST_H
+
+#include "android/utils/system.h"
+
+/* definitions for a smart list of references to generic objects.
+ * supports safe deletion and addition while they are being iterated
+ * with AREFLIST_FOREACH() macro
+ */
+
+typedef struct ARefList {
+    uint16_t   count, max;
+    uint16_t   iteration;
+    union {
+        struct ARefList*  next;
+        void*             item0;
+        void**            items;
+    } u;
+} ARefList;
+
+AINLINED void  
+areflist_init(ARefList*  l)
+{
+    l->count     = 0;
+    l->max       = 1;
+    l->iteration = 0;
+}
+
+void  areflist_setEmpty(ARefList*  l);
+
+AINLINED void
+areflist_done(ARefList*  l)
+{
+    areflist_setEmpty(l);
+}
+
+AINLINED ABool
+areflist_isEmpty(ARefList*  l)
+{
+    return (l->count == 0);
+}
+
+int    areflist_indexOf(ARefList*  l, void*  item);
+
+AINLINED ABool 
+areflist_has(ARefList*  l, void*  item)
+{
+    return areflist_indexOf(l, item) >= 0;
+}
+
+/* if 'item' is not NULL, append it to the list. An item
+ * can be added several times to a list */
+void    areflist_add(ARefList*  l, void*  item);
+
+/* if 'item' is not NULL, try to remove it from the list */
+/* returns TRUE iff the item was found in the list */
+ABool   areflist_del(ARefList*  l, void*  item);
+
+AINLINED void
+areflist_push(ARefList*  l, void*  item)
+{
+    areflist_add(l, item);
+}
+
+void*  areflist_pop(ARefList*  l);
+
+AINLINED void**
+areflist_items(ARefList*  l)
+{
+    return (l->max == 1) ? &l->u.item0 : l->u.items;
+}
+
+AINLINED int
+areflist_count(ARefList*  l)
+{
+    return l->count;
+}
+
+/* return a pointer to the n-th list array entry, 
+   or NULL in case of invalid index */
+void**  areflist_at(ARefList*  l, int  n);
+
+/* return the n-th array entry, or NULL in case of invalid index */
+void*   areflist_get(ARefList*  l, int  n);
+
+/* used internally */
+void    _areflist_remove_deferred(ARefList*  l);
+
+#define  AREFLIST_FOREACH(list_,item_,statement_) \
+    ({ ARefList*  _reflist   = (list_); \
+       int        _reflist_i = 0; \
+       int        _reflist_n = _reflist->count; \
+       _reflist->iteration += 2; \
+       for ( ; _reflist_i < _reflist_n; _reflist_i++ ) { \
+           void**  __reflist_at   = areflist_at(_reflist, _reflist_i); \
+           void*  item_ = *__reflist_at; \
+           if (item_ != NULL) { \
+               statement_; \
+           } \
+       } \
+       _reflist->iteration -= 2; \
+       if (_reflist->iteration == 1) \
+           _areflist_remove_deferred(_reflist); \
+    })
+
+/* use this to delete the currently iterated element */
+#define  AREFLIST_DEL_ITERATED()  \
+    ({ *_reflist_at = NULL; \
+       _reflist->iteration |= 1; })
+
+/* use this to replace the currently iterated element */
+#define  AREFLIST_SET_ITERATED(item) \
+    ({ *_reflist_at = (item); \
+       if (item == NULL) _reflist->iteration |= 1; })
+
+void  areflist_copy(ARefList*  dst, ARefList*  src);
+
+#endif /* _ANDROID_UTILS_REFLIST_H */
diff --git a/android/utils/stralloc.c b/android/utils/stralloc.c
new file mode 100644
index 0000000..2a924e4
--- /dev/null
+++ b/android/utils/stralloc.c
@@ -0,0 +1,300 @@
+/* Copyright (C) 2007-2008 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/utils/stralloc.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+extern void
+stralloc_tabular( stralloc_t*  out, 
+                  const char** strings, int  count,
+                  const char*  prefix,  int  width )
+{
+    int  nrows, ncols, r, c, n, maxw = 0;
+
+    for (n = 0; n < count; n++) {
+        int  len = strlen(strings[n]);
+        if (len > maxw)
+            maxw = len;
+    }
+    maxw += 2;
+    ncols = width/maxw;
+    nrows = (count + ncols-1)/ncols;
+
+    for (r = 0; r < nrows; r++) {
+        stralloc_add_str( out, prefix );
+        for (c = 0; c < ncols; c++) {
+            int  index = c*nrows + r;
+            if (index >= count) {
+                break;
+            }
+            stralloc_add_format( out, "%-*s", maxw, strings[index] );
+        }
+        stralloc_add_str( out, "\n" );
+    }
+}
+
+/** DYNAMIC STRINGS
+ **/
+
+extern void
+stralloc_reset( stralloc_t*  s )
+{
+    free(s->s);
+    s->s = NULL;
+    s->n = 0;
+    s->a = 0;
+}
+
+extern void
+stralloc_ready( stralloc_t*  s, unsigned int  len )
+{
+    unsigned  old_max = s->a;
+    unsigned  new_max = old_max;
+
+    while (new_max < len) {
+        unsigned  new_max2 = new_max + (new_max >> 1) + 16;
+        if (new_max2 < new_max)
+            new_max2 = UINT_MAX;
+        new_max = new_max2;
+    }
+
+    s->s = realloc( s->s, new_max );
+    if (s->s == NULL) {
+        derror( "%s: not enough memory to reallocate %ld bytes",
+                __FUNCTION__, new_max );
+        exit(1);
+    }
+    s->a = new_max;
+}
+
+extern void
+stralloc_readyplus( stralloc_t*  s, unsigned int  len )
+{
+    unsigned  len2 = s->n + len;
+
+    if (len2 < s->n) { /* overflow ? */
+        derror("%s: trying to grow by too many bytes: %ld",
+               __FUNCTION__, len);
+        exit(1);
+    }
+    stralloc_ready( s, len2 );
+}
+
+extern void
+stralloc_copy( stralloc_t*  s, stralloc_t*  from )
+{
+    stralloc_ready(s, from->n);
+    memcpy( s->s, from->s, from->n );
+    s->n = from->n;
+}
+
+extern void
+stralloc_append( stralloc_t*  s, stralloc_t*  from )
+{
+    stralloc_readyplus( s, from->n );
+    memcpy( s->s + s->n, from->s, from->n );
+    s->n += from->n;
+}
+
+extern void
+stralloc_add_c( stralloc_t*  s, int  c )
+{
+    stralloc_add_bytes( s, (char*)&c, 1 );
+}
+
+extern void
+stralloc_add_str( stralloc_t*  s, const char*  str )
+{
+    stralloc_add_bytes( s, str, strlen(str) );
+}
+
+extern void
+stralloc_add_bytes( stralloc_t*  s, const void*  from, unsigned len )
+{
+    stralloc_readyplus( s, len );
+    memcpy( s->s + s->n, from, len );
+    s->n += len;
+}
+
+extern char*
+stralloc_cstr( stralloc_t*  s )
+{
+    stralloc_readyplus( s, 1 );
+    s->s[s->n] = 0;
+    return s->s;
+}
+
+extern char*
+stralloc_to_tempstr( stralloc_t*  s )
+{
+    char*  q = tempstr_get( s->n );
+
+    memcpy( q, s->s, s->n );
+    q[s->n] = 0;
+    return q;
+}
+
+extern void
+stralloc_formatv( stralloc_t*  s, const char*  fmt, va_list  args )
+{
+    stralloc_reset(s);
+    stralloc_ready(s,10);
+
+    while (1) {
+        int      n;
+        va_list  args2;
+
+        va_copy(args2, args);
+        n = vsnprintf( s->s, s->a, fmt, args2 );
+        va_end(args2);
+
+        /* funky old C libraries returns -1 when truncation occurs */
+        if (n > -1 && n < s->a) {
+            s->n = n;
+            break;
+        }
+        if (n > -1) {  /* we now precisely what we need */
+            stralloc_ready( s, n+1 );
+        } else {
+            stralloc_ready( s, s->a*2 );
+        }
+    }
+}
+
+
+extern void
+stralloc_format( stralloc_t*  s, const char*  fmt, ... )
+{
+    va_list  args;
+    va_start(args, fmt);
+    stralloc_formatv(s, fmt, args);
+    va_end(args);
+}
+
+extern void
+stralloc_add_formatv( stralloc_t*  s, const char*  fmt, va_list  args )
+{
+    STRALLOC_DEFINE(s2);
+    stralloc_formatv(s2, fmt, args);
+    stralloc_append( s, s2 );
+    stralloc_reset( s2 );
+}
+
+extern void
+stralloc_add_format( stralloc_t*  s, const char*  fmt, ... )
+{
+    va_list  args;
+    va_start(args, fmt);
+    stralloc_add_formatv( s, fmt, args );
+    va_end(args);
+}
+
+extern void
+stralloc_add_quote_c( stralloc_t*  s, int  c )
+{
+    stralloc_add_quote_bytes( s, (char*)&c, 1 );
+}
+
+extern void
+stralloc_add_quote_str( stralloc_t*  s, const char*  str )
+{
+    stralloc_add_quote_bytes( s, str, strlen(str) );
+}
+
+extern void
+stralloc_add_quote_bytes( stralloc_t*  s, const void*  from, unsigned  len )
+{
+    uint8_t*   p   = (uint8_t*) from;
+    uint8_t*   end = p + len;
+
+    for ( ; p < end; p++ ) {
+        int  c = p[0];
+
+        if (c == '\\') {
+            stralloc_add_str( s, "\\\\" );
+        } else if (c >= ' ' && c < 128) {
+            stralloc_add_c( s, c );
+        } else if (c == '\n') {
+            stralloc_add_str( s, "\\n" );
+        } else if (c == '\t') {
+            stralloc_add_str( s, "\\t" );
+        } else if (c == '\r') {
+            stralloc_add_str( s, "\\r" );
+        } else {
+            stralloc_add_format( s, "\\x%02x", c );
+        }
+    }
+}
+
+extern void
+stralloc_add_hex( stralloc_t*  s, unsigned  value, int  num_digits )
+{
+    const char   hexdigits[16] = "0123456789abcdef";
+    int          nn;
+
+    if (num_digits <= 0)
+        return;
+
+    stralloc_readyplus(s, num_digits);
+    for (nn = num_digits-1; nn >= 0; nn--) {
+        s->s[s->n+nn] = hexdigits[value & 15];
+        value >>= 4;
+    }
+    s->n += num_digits;
+}
+
+extern void
+stralloc_add_hexdump( stralloc_t*  s, void*  base, int  size, const char*  prefix )
+{
+    uint8_t*   p          = (uint8_t*)base;
+    const int  max_count  = 16;
+    int        prefix_len = strlen(prefix);
+
+    while (size > 0) {
+        int          count = size > max_count ? max_count : size;
+        int          count2;
+        int          n;
+
+        stralloc_add_bytes( s, prefix, prefix_len );
+        stralloc_add_hex( s, p[0], 2 );
+
+        for (n = 1; n < count; n++) {
+            stralloc_add_c( s, ' ' );
+            stralloc_add_hex( s, p[n], 2 );
+        }
+
+        count2 = 4 + 3*(max_count - count);
+        stralloc_readyplus( s, count2 );
+        memset( s->s + s->n, ' ', count2 );
+        s->n += count2;
+
+        stralloc_readyplus(s, count+1);
+        for (n = 0; n < count; n++) {
+            int  c = p[n];
+
+            if (c < 32 || c > 127)
+                c = '.';
+
+            s->s[s->n++] = c;
+        }
+        s->s[s->n++] = '\n';
+
+        size -= count;
+        p    += count;
+    }
+}
+
diff --git a/android/utils/stralloc.h b/android/utils/stralloc.h
new file mode 100644
index 0000000..4d17060
--- /dev/null
+++ b/android/utils/stralloc.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2007-2008 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.
+*/
+
+#ifndef _ANDROID_UTILS_STRALLOC_H
+#define _ANDROID_UTILS_STRALLOC_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+/** DYNAMIC STRINGS
+ **/
+
+typedef struct {
+    char*     s;
+    unsigned  n;
+    unsigned  a;
+} stralloc_t;
+
+#define  STRALLOC_INIT        { NULL, 0, 0 }
+#define  STRALLOC_DEFINE(s)   stralloc_t   s[1] = { STRALLOC_INIT }
+
+extern void   stralloc_reset( stralloc_t*  s );
+extern void   stralloc_ready( stralloc_t*  s, unsigned  len );
+extern void   stralloc_readyplus( stralloc_t*  s, unsigned  len );
+
+extern void   stralloc_copy( stralloc_t*  s, stralloc_t*  from );
+extern void   stralloc_append( stralloc_t*  s, stralloc_t*  from );
+
+extern void   stralloc_add_c( stralloc_t*  s, int  c );
+extern void   stralloc_add_str( stralloc_t*  s, const char*  str );
+extern void   stralloc_add_bytes( stralloc_t*  s, const void*  from, unsigned  len );
+
+extern char*  stralloc_cstr( stralloc_t*  s );
+
+extern void   stralloc_format( stralloc_t*  s, const char*  fmt, ... );
+extern void   stralloc_formatv( stralloc_t*  s, const char*  fmt, va_list  args );
+extern void   stralloc_add_format( stralloc_t*  s, const char*  fmt, ... );
+
+extern void   stralloc_add_quote_c( stralloc_t*  s, int  c );
+extern void   stralloc_add_quote_str( stralloc_t*  s, const char*  str );
+extern void   stralloc_add_quote_bytes( stralloc_t*  s, const void*  from, unsigned   len );
+
+extern void   stralloc_add_hex( stralloc_t*  s, unsigned  value, int  num_digits );
+extern void   stralloc_add_hexdump( stralloc_t*  s, void*  base, int  size, const char*  prefix );
+
+extern void   stralloc_tabular( stralloc_t*  s, const char** strings, int  count,
+                                                const char*  prefix,  int  width );
+
+extern char*  stralloc_to_tempstr( stralloc_t*  s );
+
+#endif /* ANDROID_UTILS_STRALLOC_H */
diff --git a/android/utils/system.c b/android/utils/system.c
new file mode 100644
index 0000000..e09fd6b
--- /dev/null
+++ b/android/utils/system.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2008 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/utils/system.h"
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>  /* for Sleep */
+#else
+#  include <unistd.h>  /* for usleep */
+#endif
+
+void*
+android_alloc( size_t  size )
+{
+    void*   block;
+
+    if (size == 0)
+        return NULL;
+
+    block = malloc(size);
+    if (block != NULL)
+        return block;
+
+    fprintf(stderr, "PANIC: not enough memory\n");
+    exit(1);
+    return NULL;
+}
+
+void*
+android_alloc0( size_t  size )
+{
+    void*   block;
+
+    if (size == 0)
+        return NULL;
+
+    block = calloc(1, size);
+    if (block != NULL)
+        return block;
+
+    fprintf(stderr, "PANIC: not enough memory\n");
+    exit(1);
+    return NULL;
+}
+
+void*
+android_realloc( void*  block, size_t  size )
+{
+    void*   block2;
+
+    if (size == 0) {
+        free(block);
+        return NULL;
+    }
+    block2 = realloc(block, size);
+    if (block2 != NULL)
+        return block2;
+
+    fprintf(stderr, "PANIC: not enough memory to reallocate %d bytes\n", size);
+    exit(1);
+    return NULL;
+}
+
+void
+android_free( void*  block )
+{
+    if (block)
+        free(block);
+}
+
+char*
+android_strdup( const char*  str )
+{
+    int    len;
+    char*  copy;
+
+    if (str == NULL)
+        return NULL;
+
+    len  = strlen(str);
+    copy = malloc(len+1);
+    memcpy(copy, str, len);
+    copy[len] = 0;
+
+    return copy;
+}
+
+#ifdef _WIN32
+char*
+win32_strsep(char**  pline, const char*  delim)
+{
+    char*  line = *pline;
+    char*  p    = line;
+
+    if (p == NULL)
+        return NULL;
+
+    for (;;) {
+        int          c = *p++;
+        const char*  q = delim;
+
+        if (c == 0) {
+            p = NULL;
+            break;
+        }
+
+        while (*q) {
+            if (*q == c) {
+                p[-1] = 0;
+                goto Exit;
+            }
+            q++;
+        }
+    }
+Exit:	
+    *pline = p;
+    return line;
+}
+#endif
+
+
+void
+disable_sigalrm( signal_state_t  *state )
+{
+#ifdef _WIN32
+    (void)state;
+#else
+    sigset_t  set;
+
+    sigemptyset(&set);
+    sigaddset(&set, SIGALRM);
+    pthread_sigmask (SIG_BLOCK, &set, &state->old);
+#endif
+}
+
+void
+restore_sigalrm( signal_state_t  *state )
+{
+#ifdef _WIN32
+    (void)state;
+#else
+    pthread_sigmask (SIG_SETMASK, &state->old, NULL);
+#endif
+}
+
+void
+sleep_ms( int  timeout_ms )
+{
+#ifdef _WIN32
+    if (timeout_ms <= 0)
+        return;
+
+    Sleep( timeout_ms );
+#else
+    if (timeout_ms <= 0)
+        return;
+
+    BEGIN_NOSIGALRM
+    usleep( timeout_ms*1000 );
+    END_NOSIGALRM
+#endif
+}
diff --git a/android/utils/system.h b/android/utils/system.h
new file mode 100644
index 0000000..804aa7d
--- /dev/null
+++ b/android/utils/system.h
@@ -0,0 +1,161 @@
+/* Copyright (C) 2008 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.
+*/
+#ifndef _ANDROID_UTILS_SYSTEM_H
+#define _ANDROID_UTILS_SYSTEM_H
+
+#include <string.h>
+#include <stdint.h>
+
+/* the following functions perform 'checked allocations', i.e.
+ * they abort if there is not enough memory.
+ */
+
+/* checked malloc, only returns NULL if size is 0 */
+void*  android_alloc( size_t  size );
+
+/* checked calloc, only returns NULL if size is 0 */
+void*  android_alloc0( size_t  size );
+
+/* checked realloc, only returns NULL if size if 0 */
+void*  android_realloc( void*  block, size_t  size );
+
+/* free memory block */
+void   android_free( void*  block );
+
+/* convenience macros */
+
+#define  AZERO(p)             memset((char*)(p),0,sizeof(*(p)))
+#define  ANEW(p)              (p = android_alloc(sizeof(*p)))
+#define  ANEW0(p)             (p = android_alloc0(sizeof(*p)))
+#define  AFREE(p)             android_free(p)
+
+#define  AMEM_ZERO(dst,size)      memset((char*)(dst), 0, (size_t)(size))
+#define  AMEM_COPY(dst,src,size)  memcpy((char*)(dst),(const char*)(src),(size_t)(size))
+#define  AMEM_MOVE(dst,src,size)  memmove((char*)(dst),(const char*)(src),(size_t)(size))
+
+#define  AARRAY_NEW(p,count)          ((p) = android_alloc(sizeof(*p)*(count)))
+#define  AARRAY_NEW0(p,count)         ((p) = android_alloc0(sizeof(*p)*(count)))
+
+#define  AARRAY_RENEW(p,count)        ((p) = android_realloc((p),sizeof(*(p))*(count)))
+
+#define  AARRAY_COPY(dst,src,count)   AMEM_COPY(dst,src,(count)*sizeof((dst)[0]))
+#define  AARRAY_MOVE(dst,src,count)   AMEM_MOVE(dst,src,(count)*sizeof((dst)[0]))
+#define  AARRAY_ZERO(dst,count)       AMEM_ZERO(dst,(count)*sizeof((dst)[0]))
+
+#define  AARRAY_STATIC_LEN(a)         (sizeof((a))/sizeof((a)[0]))
+
+#define  AINLINED  static __inline__
+
+/* unlike strdup(), this accepts NULL as valid input (and will return NULL then) */
+char*   android_strdup(const char*  src);
+
+#define  ASTRDUP(str)  android_strdup(str)
+
+/* used for functions that return a Posix-style status code, i.e.
+ * 0 means success, -1 means failure with the error code in 'errno'
+ */
+typedef int  APosixStatus;
+
+/* used for functions that return or accept a boolean type */
+typedef int  ABool;
+
+/** Stringification macro
+ **/
+#ifndef STRINGIFY
+#define  _STRINGIFY(x)  #x
+#define  STRINGIFY(x)  _STRINGIFY(x)
+#endif
+
+/** Concatenation macros
+ **/
+#ifndef GLUE
+#define  _GLUE(x,y)  x##y
+#define  GLUE(x,y)   _GLUE(x,y)
+
+#define  _GLUE3(x,y,z)  x##y##z
+#define  GLUE3(x,y,z)    _GLUE3(x,y,z)
+#endif
+
+/** Handle strsep() on Win32
+ **/
+#ifdef _WIN32
+#  undef   strsep
+#  define  strsep    win32_strsep
+extern char*  win32_strsep(char**  pline, const char*  delim);
+#endif
+
+/** Handle strcasecmp on Windows
+ **/
+#ifdef _WIN32
+#  define  strcasecmp  stricmp
+#endif
+
+/** EINTR HANDLING
+ **
+ ** since QEMU uses SIGALRM pretty extensively, having a system call returning
+ ** EINTR on Unix happens very frequently. provide a simple macro to guard against
+ ** this.
+ **/
+
+#ifdef _WIN32
+#  define   CHECKED(ret, call)    (ret) = (call)
+#else
+#  define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+#endif
+
+/** SIGNAL HANDLING
+ **
+ ** the following can be used to block SIGALRM for a given period of time.
+ ** use with caution, the QEMU execution loop uses SIGALRM extensively
+ **
+ **/
+#ifdef _WIN32
+typedef struct { int  dumy; }      signal_state_t;
+#else
+#include <signal.h>
+typedef struct { sigset_t  old; }  signal_state_t;
+#endif
+
+extern  void   disable_sigalrm( signal_state_t  *state );
+extern  void   restore_sigalrm( signal_state_t  *state );
+
+#ifdef _WIN32
+
+#define   BEGIN_NOSIGALRM  \
+    {
+
+#define   END_NOSIGALRM  \
+    }
+
+#else /* !WIN32 */
+
+#define   BEGIN_NOSIGALRM  \
+    { signal_state_t  __sigalrm_state; \
+      disable_sigalrm( &__sigalrm_state );
+
+#define   END_NOSIGALRM  \
+      restore_sigalrm( &__sigalrm_state );  \
+    }
+
+#endif /* !WIN32 */
+
+/** TIME HANDLING
+ **
+ ** sleep for a given time in milliseconds. note: this uses
+ ** disable_sigalrm()/restore_sigalrm()
+ **/
+
+extern  void   sleep_ms( int  timeout );
+
+/* */
+
+#endif /* _ANDROID_UTILS_SYSTEM_H */
diff --git a/android/utils/tempfile.c b/android/utils/tempfile.c
new file mode 100644
index 0000000..6374c12
--- /dev/null
+++ b/android/utils/tempfile.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 2007-2008 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/utils/tempfile.h"
+#include "android/utils/bufprint.h"
+#include "android/utils/debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+#else
+#  include <unistd.h>
+#endif
+
+#define  D(...)  ((void)0)
+
+/** TEMP FILE SUPPORT
+ **
+ ** simple interface to create an empty temporary file on the system.
+ **
+ ** create the file with tempfile_create(), which returns a reference to a TempFile
+ ** object, or NULL if your system is so weird it doesn't have a temporary directory.
+ **
+ ** you can then call tempfile_path() to retrieve the TempFile's real path to open
+ ** it. the returned path is owned by the TempFile object and should not be freed.
+ **
+ ** all temporary files are destroyed when the program quits, unless you explicitely
+ ** close them before that with tempfile_close()
+ **/
+
+struct TempFile
+{
+    const char*  name;
+    TempFile*    next;
+};
+
+static void       tempfile_atexit();
+static TempFile*  _all_tempfiles;
+
+TempFile*
+tempfile_create( void )
+{
+    TempFile*    tempfile;
+    const char*  tempname = NULL;
+
+#ifdef _WIN32
+    char  temp_namebuff[MAX_PATH];
+    char  temp_dir[MAX_PATH];
+    char  *p = temp_dir, *end = p + sizeof(temp_dir);
+    UINT  retval;
+
+    p = bufprint_temp_dir( p, end );
+    if (p >= end) {
+        D( "TEMP directory path is too long" );
+        return NULL;
+    }
+
+    retval = GetTempFileName(temp_dir, "TMP", 0, temp_namebuff);
+    if (retval == 0) {
+        D( "can't create temporary file in '%s'", temp_dir );
+        return NULL;
+    }
+
+    tempname = temp_namebuff;
+#else
+#define  TEMPLATE  "/tmp/.android-emulator-XXXXXX"
+    int   tempfd = -1;
+    char  template[512];
+    char  *p = template, *end = p + sizeof(template);
+
+    p = bufprint_temp_file( p, end, "emulator-XXXXXX" );
+    if (p >= end) {
+        D( "Xcannot create temporary file in /tmp/android !!" );
+        return NULL;
+    }
+
+    D( "template: %s", template );
+    tempfd = mkstemp( template );
+    if (tempfd < 0) {
+        D("cannot create temporary file in /tmp/android !!");
+        return NULL;
+    }
+    close(tempfd);
+    tempname = template;
+#endif
+    tempfile = malloc( sizeof(*tempfile) + strlen(tempname) + 1 );
+    tempfile->name = (char*)(tempfile + 1);
+    strcpy( (char*)tempfile->name, tempname );
+
+    tempfile->next = _all_tempfiles;
+    _all_tempfiles = tempfile;
+
+    if ( !tempfile->next ) {
+        atexit( tempfile_atexit );
+    }
+
+    return tempfile;
+}
+
+const char*
+tempfile_path(TempFile*  temp)
+{
+    return temp ? temp->name : NULL;
+}
+
+void
+tempfile_close(TempFile*  tempfile)
+{
+#ifdef _WIN32
+    DeleteFile(tempfile->name);
+#else
+    unlink(tempfile->name);
+#endif
+}
+
+/** TEMP FILE CLEANUP
+ **
+ **/
+
+/* we don't expect to use many temporary files */
+#define MAX_ATEXIT_FDS  16
+
+typedef struct {
+    int   count;
+    int   fds[ MAX_ATEXIT_FDS ];
+} AtExitFds;
+
+static void
+atexit_fds_add( AtExitFds*  t, int  fd )
+{
+    if (t->count < MAX_ATEXIT_FDS)
+        t->fds[t->count++] = fd;
+    else {
+        dwarning("%s: over %d calls. Program exit may not cleanup all temporary files",
+            __FUNCTION__, MAX_ATEXIT_FDS);
+    }
+}
+
+static void
+atexit_fds_del( AtExitFds*  t, int  fd )
+{
+    int  nn;
+    for (nn = 0; nn < t->count; nn++)
+        if (t->fds[nn] == fd) {
+            /* move the last element to the current position */
+            t->count  -= 1;
+            t->fds[nn] = t->fds[t->count];
+            break;
+        }
+}
+
+static void
+atexit_fds_close_all( AtExitFds*  t )
+{
+    int  nn;
+    for (nn = 0; nn < t->count; nn++)
+        close(t->fds[nn]);
+}
+
+static AtExitFds   _atexit_fds[1];
+
+void
+atexit_close_fd(int  fd)
+{
+    if (fd >= 0)
+        atexit_fds_add(_atexit_fds, fd);
+}
+
+void
+atexit_close_fd_remove(int  fd)
+{
+    if (fd >= 0)
+        atexit_fds_del(_atexit_fds, fd);
+}
+
+static void
+tempfile_atexit( void )
+{
+    TempFile*  tempfile;
+
+    atexit_fds_close_all( _atexit_fds );
+
+    for (tempfile = _all_tempfiles; tempfile; tempfile = tempfile->next)
+        tempfile_close(tempfile);
+}
diff --git a/android/utils/tempfile.h b/android/utils/tempfile.h
new file mode 100644
index 0000000..4264a84
--- /dev/null
+++ b/android/utils/tempfile.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2007-2008 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.
+*/
+
+#ifndef _ANDROID_UTILS_TEMPFILE_H
+#define _ANDROID_UTILS_TEMPFILE_H
+
+/** TEMP FILE SUPPORT
+ **
+ ** simple interface to create an empty temporary file on the system.
+ **
+ ** create the file with tempfile_create(), which returns a reference to a TempFile
+ ** object, or NULL if your system is so weird it doesn't have a temporary directory.
+ **
+ ** you can then call tempfile_path() to retrieve the TempFile's real path to open
+ ** it. the returned path is owned by the TempFile object and should not be freed.
+ **
+ ** all temporary files are destroyed when the program quits, unless you explicitely
+ ** close them before that with tempfile_close()
+ **/
+
+typedef struct TempFile   TempFile;
+
+extern  TempFile*    tempfile_create( void );
+extern  const char*  tempfile_path( TempFile*  temp );
+extern  void         tempfile_close( TempFile*  temp );
+
+/** TEMP FILE CLEANUP
+ **
+ ** We delete all temporary files in atexit()-registered callbacks.
+ ** however, the Win32 DeleteFile is unable to remove a file unless
+ ** all HANDLEs to it are closed in the terminating process.
+ **
+ ** Call 'atexit_close_fd' on a newly open-ed file descriptor to indicate
+ ** that you want it closed in atexit() time. You should always call
+ ** this function unless you're certain that the corresponding file
+ ** cannot be temporary.
+ **
+ ** Call 'atexit_close_fd_remove' before explicitely closing a 'fd'
+ **/
+extern void          atexit_close_fd(int  fd);
+extern void          atexit_close_fd_remove(int  fd);
+
+#endif /* _ANDROID_UTILS_TEMPFILE_H */
diff --git a/android/utils/timezone.c b/android/utils/timezone.c
new file mode 100644
index 0000000..b5588a3
--- /dev/null
+++ b/android/utils/timezone.c
@@ -0,0 +1,721 @@
+/* Copyright (C) 2007-2008 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/utils/debug.h"
+#include "android/utils/timezone.h"
+#include "android/utils/bufprint.h"
+#include "android/android.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "qemu-common.h"
+
+#define  DEBUG  1
+
+#if 1
+#  define  D_ACTIVE   VERBOSE_CHECK(timezone)
+#else
+#  define  D_ACTIVE   DEBUG
+#endif
+
+#if DEBUG
+#  define  D(...)  do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+#  define  D(...)  ((void)0)
+#endif
+
+
+
+static const char* get_zoneinfo_timezone( void );  /* forward */
+
+static char         android_timezone0[256];
+static const char*  android_timezone;
+static int          android_timezone_init;
+
+static int
+check_timezone_is_zoneinfo(const char*  tz)
+{
+    const char*  slash1 = NULL, *slash2 = NULL;
+
+    if (tz == NULL)
+        return 0;
+
+    /* the name must be of the form Area/Location or Area/Location/SubLocation */
+    slash1 = strchr( tz, '/' );
+    if (slash1 == NULL || slash1[1] == 0)
+        return 0;
+
+    slash2 = strchr( slash1+1, '/');
+    if (slash2 != NULL) {
+        if (slash2[1] == 0 || strchr(slash2+1, '/') != NULL)
+            return 0;
+    }
+
+    return 1;
+}
+
+int
+timezone_set( const char*  tzname )
+{
+    int   len;
+
+    if ( !check_timezone_is_zoneinfo(tzname) )
+        return -1;
+
+    len = strlen(tzname);
+    if (len > sizeof(android_timezone0)-1)
+        return -1;
+
+    strcpy( android_timezone0, tzname );
+    android_timezone      = android_timezone0;
+    android_timezone_init = 1;
+
+    return 0;
+}
+
+
+char*
+bufprint_zoneinfo_timezone( char*  p, char*  end )
+{
+    const char*  tz = get_zoneinfo_timezone();
+
+    if (tz == NULL || !check_timezone_is_zoneinfo(tz))
+        return bufprint(p, end, "Unknown/Unknown");
+    else
+        return bufprint(p, end, "%s", tz);
+}
+
+/* on OS X, the timezone directory is always /usr/share/zoneinfo
+ * this makes things easy.
+ */
+#ifdef __APPLE__
+
+#include <unistd.h>
+#include <limits.h>
+#define  LOCALTIME_FILE  "/etc/localtime"
+#define  ZONEINFO_DIR    "/usr/share/zoneinfo/"
+static const char*
+get_zoneinfo_timezone( void )
+{
+    if (!android_timezone_init) {
+        const char*  tz = getenv("TZ");
+        char         buff[PATH_MAX+1];
+
+        android_timezone_init = 1;
+        if (tz == NULL) {
+            int   len = readlink(LOCALTIME_FILE, buff, sizeof(buff));
+            if (len < 0) {
+                dprint( "### WARNING: Could not read %s, something is very wrong on your system",
+                        LOCALTIME_FILE);
+                return NULL;
+            }
+
+            buff[len] = 0;
+            D("%s: %s points to %s\n", __FUNCTION__, LOCALTIME_FILE, buff);
+            if ( memcmp(buff, ZONEINFO_DIR, sizeof(ZONEINFO_DIR)-1) ) {
+                dprint( "### WARNING: %s does not point to %s, can't determine zoneinfo timezone name",
+                        LOCALTIME_FILE, ZONEINFO_DIR );
+                return NULL;
+            }
+            tz = buff + sizeof(ZONEINFO_DIR)-1;
+            if ( !check_timezone_is_zoneinfo(tz) ) {
+                dprint( "### WARNING: %s does not point to zoneinfo-compatible timezone name\n", LOCALTIME_FILE );
+                return NULL;
+            }
+        }
+        pstrcpy( android_timezone0, sizeof(android_timezone0), tz );
+        android_timezone = android_timezone0;
+    }
+    D( "found timezone %s", android_timezone );
+    return android_timezone;
+}
+
+#endif  /* __APPLE__ */
+
+/* on Linux, with glibc2, the zoneinfo directory can be changed with TZDIR environment variable
+ * but should be /usr/share/zoneinfo by default. /etc/localtime is not guaranteed to exist on
+ * all platforms, so if it doesn't, try $TZDIR/localtime, then /usr/share/zoneinfo/locatime
+ * ugly, isn't it ?
+ *
+ * besides, modern Linux distribution don't make /etc/localtime a symlink but a straight copy of
+ * the original timezone file. the only way to know which zoneinfo name to retrieve is to compare
+ * it with all files in $TZDIR (at least those that match Area/Location or Area/Location/SubLocation
+ */
+#ifdef __linux__
+
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#define  ZONEINFO_DIR  "/usr/share/zoneinfo/"
+#define  LOCALTIME_FILE1  "/etc/localtime"
+
+typedef struct {
+    const char*   localtime;
+    struct stat   localtime_st;
+    char*         path_end;
+    char*         path_root;
+    char          path[ PATH_MAX ];
+} ScanDataRec;
+
+static int
+compare_timezone_to_localtime( ScanDataRec*  scan,
+                               const char*   path )
+{
+    struct  stat  st;
+    int           fd1, fd2, result = 0;
+
+    D( "%s: comparing %s:", __FUNCTION__, path );
+
+    if ( stat( path, &st ) < 0 ) {
+        D( " can't stat: %s\n", strerror(errno) );
+        return 0;
+    }
+
+    if ( st.st_size != scan->localtime_st.st_size ) {
+        D( " size mistmatch (%lld != %lld)\n", st.st_size, scan->localtime_st.st_size );
+        return 0;
+    }
+
+    fd1 = open( scan->localtime, O_RDONLY );
+    if (fd1 < 0) {
+        D(" can't open %s: %s\n", scan->localtime, strerror(errno) );
+        return 0;
+    }
+    fd2 = open( path, O_RDONLY );
+    if (fd2 < 0) {
+        D(" can't open %s: %s\n", path, strerror(errno) );
+        close(fd1);
+        return 0;
+    }
+    do {
+        off_t  nn;
+
+        for (nn = 0; nn < st.st_size; nn++) {
+            char  temp[2];
+            int   ret;
+
+            do { ret = read(fd1, &temp[0], 1); } while (ret < 0 && errno == EINTR);
+            if (ret < 0) break;
+
+            do { ret = read(fd2, &temp[1], 1); } while (ret < 0 && errno == EINTR);
+            if (ret < 0) break;
+
+            if (temp[0] != temp[1])
+                break;
+        }
+
+        result = (nn == st.st_size);
+
+    } while (0);
+
+    D( result ? " MATCH\n" : "no match\n" );
+
+    close(fd2);
+    close(fd1);
+
+    return result;
+}
+
+static const char*
+scan_timezone_dir( ScanDataRec*  scan,
+                   char*         top,
+                   int           depth )
+{
+    DIR*         d = opendir( scan->path );
+    const char*  result = NULL;
+
+    D( "%s: entering '%s\n", __FUNCTION__, scan->path );
+    if (d != NULL) {
+        struct  dirent*  ent;
+        while ((ent = readdir(d)) != NULL) {
+            struct stat   ent_st;
+            char*         p = top;
+
+            if  (ent->d_name[0] == '.')  /* avoid hidden and special files */
+                continue;
+
+            p = bufprint( p, scan->path_end, "/%s", ent->d_name );
+            if (p >= scan->path_end)
+                continue;
+
+            //D( "%s: scanning '%s'\n", __FUNCTION__, scan->path );
+
+            if ( stat( scan->path, &ent_st ) < 0 )
+                continue;
+
+            if ( S_ISDIR(ent_st.st_mode) && depth < 2 )
+            {
+                //D( "%s: directory '%s'\n", __FUNCTION__, scan->path );
+                result = scan_timezone_dir( scan, p, depth + 1 );
+                if (result != NULL)
+                    break;
+            }
+            else if ( S_ISREG(ent_st.st_mode) && (depth >= 1 && depth <= 2) )
+            {
+                char*   name = scan->path_root + 1;
+
+                if ( check_timezone_is_zoneinfo( name ) )
+                {
+                    if (compare_timezone_to_localtime( scan, scan->path ))
+                    {
+                        result = strdup( name );
+                        D( "%s: found '%s'\n", __FUNCTION__, result );
+                        break;
+                    }
+                }
+                else
+                {
+                    //D( "%s: ignoring '%s'\n", __FUNCTION__, scan->path );
+                }
+            }
+        }
+        closedir(d);
+    }
+    return  result;
+}
+
+static const char*
+get_zoneinfo_timezone( void )
+{
+    if (!android_timezone_init)
+    {
+        const char*  tz = getenv( "TZ" );
+
+        android_timezone_init = 1;
+
+        if ( tz != NULL && !check_timezone_is_zoneinfo(tz) ) {
+            D( "%s: ignoring non zoneinfo formatted TZ environment variable: '%s'\n",
+               __FUNCTION__, tz );
+            tz = NULL;
+        }
+
+        if (tz == NULL) {
+            char*        tzdir     = NULL;
+            int          tzdirlen  = 0;
+            char*        localtime = NULL;
+            int          len;
+            char         temp[ PATH_MAX ];
+
+            /* determine the correct timezone directory */
+            {
+                const char*  env = getenv("TZDIR");
+                const char*  zoneinfo_dir = ZONEINFO_DIR;
+
+                if (env == NULL)
+                    env = zoneinfo_dir;
+
+                if ( access( env, R_OK ) != 0 ) {
+                    if ( env == zoneinfo_dir ) {
+                        fprintf( stderr,
+                                 "### WARNING: could not find %s directory. unable to determine host timezone\n", env );
+                    } else {
+                        D( "%s: TZDIR does not point to valid directory, using %s instead\n",
+                           __FUNCTION__, zoneinfo_dir );
+                        env = zoneinfo_dir;
+                    }
+                    return NULL;
+                }
+                tzdir = strdup(env);
+            }
+
+            /* remove trailing slash, if any */
+            len = strlen(tzdir);
+            if (len > 0 && tzdir[len-1] == '/') {
+                tzdir[len-1] = 0;
+                len         -= 1;
+            }
+            tzdirlen = len;
+            D( "%s: found timezone dir as %s\n", __FUNCTION__, tzdir );
+
+            /* try to find the localtime file */
+            localtime = LOCALTIME_FILE1;
+            if ( access( localtime, R_OK ) != 0 ) {
+                char  *p = temp, *end = p + sizeof(temp);
+
+                p = bufprint( p, end, "%s/%s", tzdir, "localtime" );
+                if (p >= end || access( temp, R_OK ) != 0 ) {
+                    fprintf( stderr, "### WARNING: could not find %s or %s. unable to determine host timezone\n",
+                                     LOCALTIME_FILE1, temp );
+                    goto Exit;
+                }
+                localtime = temp;
+            }
+            localtime = strdup(localtime);
+            D( "%s: found localtime file as %s\n", __FUNCTION__, localtime );
+
+#if 1
+            /* if the localtime file is a link, make a quick check */
+            len = readlink( localtime, temp, sizeof(temp)-1 );
+            if (len >= 0 && len > tzdirlen + 2) {
+                temp[len] = 0;
+
+                /* verify that the link points to tzdir/<something> where <something> is a valid zoneinfo name */
+                if ( !memcmp( temp, tzdir, tzdirlen ) && temp[tzdirlen] == '/' ) {
+                    if ( check_timezone_is_zoneinfo( temp + tzdirlen + 1 ) ) {
+                        /* we have it ! */
+                        tz = temp + tzdirlen + 1;
+                        D( "%s: found zoneinfo timezone %s from %s symlink\n", __FUNCTION__, tz, localtime );
+                        goto Exit;
+                    }
+                    D( "%s: %s link points to non-zoneinfo filename %s, comparing contents\n",
+                       __FUNCTION__, localtime, temp );
+                }
+            }
+#endif
+
+            /* otherwise, parse all files under tzdir and see if we have something that looks like it */
+            {
+                ScanDataRec  scan[1];
+
+                if ( stat( localtime, &scan->localtime_st ) < 0 ) {
+                    fprintf( stderr, "### WARNING: can't access '%s', unable to determine host timezone\n",
+                             localtime );
+                    goto Exit;
+                }
+
+                scan->localtime = localtime;
+                scan->path_end  = scan->path + sizeof(scan->path);
+                scan->path_root = bufprint( scan->path, scan->path_end, "%s", tzdir );
+
+                tz = scan_timezone_dir( scan, scan->path_root, 0 );
+            }
+
+        Exit:
+            if (tzdir)
+                free(tzdir);
+            if (localtime)
+                free(localtime);
+
+            if (tz == NULL)
+                return NULL;
+
+            pstrcpy( android_timezone0, sizeof(android_timezone0), tz );
+            android_timezone = android_timezone0;
+        }
+        D( "found timezone %s\n", android_timezone );
+    }
+    return android_timezone;
+}
+
+#endif /* __linux__ */
+
+
+/* on Windows, we need to translate the Windows timezone into a ZoneInfo one */
+#ifdef _WIN32
+#include <time.h>
+
+typedef struct {
+    const char*  win_name;
+    const char*  zoneinfo_name;
+} Win32Timezone;
+
+/* table generated from http://unicode.org/cldr/data/diff/supplemental/windows_tzid.html */
+static const Win32Timezone  _win32_timezones[] = {
+    { "AUS Central Standard Time"             , "Australia/Darwin" },
+    { "AUS Eastern Standard Time"             , "Australia/Sydney" },
+    { "Acre Standard Time"                    , "America/Rio_Branco" },
+    { "Afghanistan Standard Time"             , "Asia/Kabul" },
+    { "Africa_Central Standard Time"          , "Africa/Kigali" },
+    { "Africa_Eastern Standard Time"          , "Africa/Kampala" },
+    { "Africa_FarWestern Standard Time"       , "Africa/El_Aaiun" },
+    { "Africa_Southern Standard Time"         , "Africa/Johannesburg" },
+    { "Africa_Western Standard Time"          , "Africa/Niamey" },
+    { "Aktyubinsk Standard Time"              , "Asia/Aqtobe" },
+    { "Alaska Standard Time"                  , "America/Juneau" },
+    { "Alaska_Hawaii Standard Time"           , "America/Anchorage" },
+    { "Alaskan Standard Time"                 , "America/Anchorage" },
+    { "Almaty Standard Time"                  , "Asia/Almaty" },
+    { "Amazon Standard Time"                  , "America/Manaus" },
+    { "America_Central Standard Time"         , "America/Winnipeg" },
+    { "America_Eastern Standard Time"         , "America/Panama" },
+    { "America_Mountain Standard Time"        , "America/Edmonton" },
+    { "America_Pacific Standard Time"         , "America/Vancouver" },
+    { "Anadyr Standard Time"                  , "Asia/Anadyr" },
+    { "Aqtau Standard Time"                   , "Asia/Aqtau" },
+    { "Aqtobe Standard Time"                  , "Asia/Aqtobe" },
+    { "Arab Standard Time"                    , "Asia/Riyadh" },
+    { "Arabian Standard Time"                 , "Asia/Bahrain" },
+    { "Arabic Standard Time"                  , "Asia/Baghdad" },
+    { "Argentina Standard Time"               , "America/Buenos_Aires" },
+    { "Argentina_Western Standard Time"       , "America/Mendoza" },
+    { "Armenia Standard Time"                 , "Asia/Yerevan" },
+    { "Ashkhabad Standard Time"               , "Asia/Ashgabat" },
+    { "Atlantic Standard Time"                , "America/Curacao" },
+    { "Australia_Central Standard Time"       , "Australia/Adelaide" },
+    { "Australia_CentralWestern Standard Time", "Australia/Eucla" },
+    { "Australia_Eastern Standard Time"       , "Australia/Sydney" },
+    { "Australia_Western Standard Time"       , "Australia/Perth" },
+    { "Azerbaijan Standard Time"              , "Asia/Baku" },
+    { "Azores Standard Time"                  , "Atlantic/Azores" },
+    { "Baku Standard Time"                    , "Asia/Baku" },
+    { "Bangladesh Standard Time"              , "Asia/Dhaka" },
+    { "Bering Standard Time"                  , "America/Adak" },
+    { "Bhutan Standard Time"                  , "Asia/Thimphu" },
+    { "Bolivia Standard Time"                 , "America/La_Paz" },
+    { "Borneo Standard Time"                  , "Asia/Kuching" },
+    { "Brasilia Standard Time"                , "America/Sao_Paulo" },
+    { "British Standard Time"                 , "Europe/London" },
+    { "Brunei Standard Time"                  , "Asia/Brunei" },
+    { "Canada Central Standard Time"          , "America/Regina" },
+    { "Cape Verde Standard Time"              , "Atlantic/Cape_Verde" },
+    { "Cape_Verde Standard Time"              , "Atlantic/Cape_Verde" },
+    { "Caucasus Standard Time"                , "Asia/Yerevan" },
+    { "Cen. Australia Standard Time"          , "Australia/Adelaide" },
+    { "Central Standard Time"                 , "America/Chicago" },
+    { "Central America Standard Time"         , "America/Guatemala" },
+    { "Central Asia Standard Time"            , "Asia/Dhaka" },
+    { "Central Brazilian Standard Time"       , "America/Manaus" },
+    { "Central Europe Standard Time"          , "Europe/Prague" },
+    { "Central European Standard Time"        , "Europe/Warsaw" },
+    { "Central Pacific Standard Time"         , "Pacific/Guadalcanal" },
+    { "Central Standard Time (Mexico)"        , "America/Mexico_City" },
+    { "Chamorro Standard Time"                , "Pacific/Guam" },
+    { "Changbai Standard Time"                , "Asia/Harbin" },
+    { "Chatham Standard Time"                 , "Pacific/Chatham" },
+    { "Chile Standard Time"                   , "America/Santiago" },
+    { "China Standard Time"                   , "Asia/Taipei" },
+    { "Choibalsan Standard Time"              , "Asia/Choibalsan" },
+    { "Christmas Standard Time"               , "Indian/Christmas" },
+    { "Cocos Standard Time"                   , "Indian/Cocos" },
+    { "Colombia Standard Time"                , "America/Bogota" },
+    { "Cook Standard Time"                    , "Pacific/Rarotonga" },
+    { "Cuba Standard Time"                    , "America/Havana" },
+    { "Dacca Standard Time"                   , "Asia/Dhaka" },
+    { "Dateline Standard Time"                , "Pacific/Kwajalein" },
+    { "Davis Standard Time"                   , "Antarctica/Davis" },
+    { "Dominican Standard Time"               , "America/Santo_Domingo" },
+    { "DumontDUrville Standard Time"          , "Antarctica/DumontDUrville" },
+    { "Dushanbe Standard Time"                , "Asia/Dushanbe" },
+    { "Dutch_Guiana Standard Time"            , "America/Paramaribo" },
+    { "E. Africa Standard Time"               , "Africa/Nairobi" },
+    { "E. Australia Standard Time"            , "Australia/Brisbane" },
+    { "E. Europe Standard Time"               , "Europe/Minsk" },
+    { "E. South America Standard Time"        , "America/Sao_Paulo" },
+    { "East_Timor Standard Time"              , "Asia/Dili" },
+    { "Easter Standard Time"                  , "Pacific/Easter" },
+    { "Eastern Standard Time"                 , "America/New_York" },
+    { "Ecuador Standard Time"                 , "America/Guayaquil" },
+    { "Egypt Standard Time"                   , "Africa/Cairo" },
+    { "Ekaterinburg Standard Time"            , "Asia/Yekaterinburg" },
+    { "Europe_Central Standard Time"          , "Europe/Oslo" },
+    { "Europe_Eastern Standard Time"          , "Europe/Vilnius" },
+    { "Europe_Western Standard Time"          , "Atlantic/Canary" },
+    { "FLE Standard Time"                     , "Europe/Helsinki" },
+    { "Falkland Standard Time"                , "Atlantic/Stanley" },
+    { "Fiji Standard Time"                    , "Pacific/Fiji" },
+    { "French_Guiana Standard Time"           , "America/Cayenne" },
+    { "French_Southern Standard Time"         , "Indian/Kerguelen" },
+    { "Frunze Standard Time"                  , "Asia/Bishkek" },
+    { "GMT Standard Time"                     , "Europe/Dublin" },
+    { "GTB Standard Time"                     , "Europe/Istanbul" },
+    { "Galapagos Standard Time"               , "Pacific/Galapagos" },
+    { "Gambier Standard Time"                 , "Pacific/Gambier" },
+    { "Georgia Standard Time"                 , "Asia/Tbilisi" },
+    { "Georgian Standard Time"                , "Asia/Tbilisi" },
+    { "Gilbert_Islands Standard Time"         , "Pacific/Tarawa" },
+    { "Goose_Bay Standard Time"               , "America/Goose_Bay" },
+    { "Greenland Standard Time"               , "America/Godthab" },
+    { "Greenland_Central Standard Time"       , "America/Scoresbysund" },
+    { "Greenland_Eastern Standard Time"       , "America/Scoresbysund" },
+    { "Greenland_Western Standard Time"       , "America/Godthab" },
+    { "Greenwich Standard Time"               , "Africa/Casablanca" },
+    { "Guam Standard Time"                    , "Pacific/Guam" },
+    { "Gulf Standard Time"                    , "Asia/Muscat" },
+    { "Guyana Standard Time"                  , "America/Guyana" },
+    { "Hawaii_Aleutian Standard Time"         , "Pacific/Honolulu" },
+    { "Hawaiian Standard Time"                , "Pacific/Honolulu" },
+    { "Hong_Kong Standard Time"               , "Asia/Hong_Kong" },
+    { "Hovd Standard Time"                    , "Asia/Hovd" },
+    { "India Standard Time"                   , "Asia/Calcutta" },
+    { "Indian_Ocean Standard Time"            , "Indian/Chagos" },
+    { "Indochina Standard Time"               , "Asia/Vientiane" },
+    { "Indonesia_Central Standard Time"       , "Asia/Makassar" },
+    { "Indonesia_Eastern Standard Time"       , "Asia/Jayapura" },
+    { "Indonesia_Western Standard Time"       , "Asia/Jakarta" },
+    { "Iran Standard Time"                    , "Asia/Tehran" },
+    { "Irish Standard Time"                   , "Europe/Dublin" },
+    { "Irkutsk Standard Time"                 , "Asia/Irkutsk" },
+    { "Israel Standard Time"                  , "Asia/Jerusalem" },
+    { "Japan Standard Time"                   , "Asia/Tokyo" },
+    { "Jordan Standard Time"                  , "Asia/Amman" },
+    { "Kamchatka Standard Time"               , "Asia/Kamchatka" },
+    { "Karachi Standard Time"                 , "Asia/Karachi" },
+    { "Kashgar Standard Time"                 , "Asia/Kashgar" },
+    { "Kazakhstan_Eastern Standard Time"      , "Asia/Almaty" },
+    { "Kazakhstan_Western Standard Time"      , "Asia/Aqtobe" },
+    { "Kizilorda Standard Time"               , "Asia/Qyzylorda" },
+    { "Korea Standard Time"                   , "Asia/Seoul" },
+    { "Kosrae Standard Time"                  , "Pacific/Kosrae" },
+    { "Krasnoyarsk Standard Time"             , "Asia/Krasnoyarsk" },
+    { "Kuybyshev Standard Time"               , "Europe/Samara" },
+    { "Kwajalein Standard Time"               , "Pacific/Kwajalein" },
+    { "Kyrgystan Standard Time"               , "Asia/Bishkek" },
+    { "Lanka Standard Time"                   , "Asia/Colombo" },
+    { "Liberia Standard Time"                 , "Africa/Monrovia" },
+    { "Line_Islands Standard Time"            , "Pacific/Kiritimati" },
+    { "Long_Shu Standard Time"                , "Asia/Chongqing" },
+    { "Lord_Howe Standard Time"               , "Australia/Lord_Howe" },
+    { "Macau Standard Time"                   , "Asia/Macau" },
+    { "Magadan Standard Time"                 , "Asia/Magadan" },
+    { "Malaya Standard Time"                  , "Asia/Kuala_Lumpur" },
+    { "Malaysia Standard Time"                , "Asia/Kuching" },
+    { "Maldives Standard Time"                , "Indian/Maldives" },
+    { "Marquesas Standard Time"               , "Pacific/Marquesas" },
+    { "Marshall_Islands Standard Time"        , "Pacific/Majuro" },
+    { "Mauritius Standard Time"               , "Indian/Mauritius" },
+    { "Mawson Standard Time"                  , "Antarctica/Mawson" },
+    { "Mexico Standard Time"                  , "America/Mexico_City" },
+    { "Mexico Standard Time 2 Standard Time"  , "America/Chihuahua" },
+    { "Mid-Atlantic Standard Time"            , "America/Noronha" },
+    { "Middle East Standard Time"             , "Asia/Beirut" },
+    { "Mongolia Standard Time"                , "Asia/Ulaanbaatar" },
+    { "Montevideo Standard Time"              , "America/Montevideo" },
+    { "Moscow Standard Time"                  , "Europe/Moscow" },
+    { "Mountain Standard Time"                , "America/Denver" },
+    { "Mountain Standard Time (Mexico)"       , "America/Chihuahua" },
+    { "Myanmar Standard Time"                 , "Asia/Rangoon" },
+    { "N. Central Asia Standard Time"         , "Asia/Novosibirsk" },
+    { "Namibia Standard Time"                 , "Africa/Windhoek" },
+    { "Nauru Standard Time"                   , "Pacific/Nauru" },
+    { "Nepal Standard Time"                   , "Asia/Katmandu" },
+    { "New Zealand Standard Time"             , "Pacific/Auckland" },
+    { "New_Caledonia Standard Time"           , "Pacific/Noumea" },
+    { "New_Zealand Standard Time"             , "Pacific/Auckland" },
+    { "Newfoundland Standard Time"            , "America/St_Johns" },
+    { "Niue Standard Time"                    , "Pacific/Niue" },
+    { "Norfolk Standard Time"                 , "Pacific/Norfolk" },
+    { "Noronha Standard Time"                 , "America/Noronha" },
+    { "North Asia Standard Time"              , "Asia/Krasnoyarsk" },
+    { "North Asia East Standard Time"         , "Asia/Ulaanbaatar" },
+    { "North_Mariana Standard Time"           , "Pacific/Saipan" },
+    { "Novosibirsk Standard Time"             , "Asia/Novosibirsk" },
+    { "Omsk Standard Time"                    , "Asia/Omsk" },
+    { "Oral Standard Time"                    , "Asia/Oral" },
+    { "Pacific Standard Time"                 , "America/Los_Angeles" },
+    { "Pacific SA Standard Time"              , "America/Santiago" },
+    { "Pacific Standard Time (Mexico)"        , "America/Tijuana" },
+    { "Pakistan Standard Time"                , "Asia/Karachi" },
+    { "Palau Standard Time"                   , "Pacific/Palau" },
+    { "Papua_New_Guinea Standard Time"        , "Pacific/Port_Moresby" },
+    { "Paraguay Standard Time"                , "America/Asuncion" },
+    { "Peru Standard Time"                    , "America/Lima" },
+    { "Philippines Standard Time"             , "Asia/Manila" },
+    { "Phoenix_Islands Standard Time"         , "Pacific/Enderbury" },
+    { "Pierre_Miquelon Standard Time"         , "America/Miquelon" },
+    { "Pitcairn Standard Time"                , "Pacific/Pitcairn" },
+    { "Ponape Standard Time"                  , "Pacific/Ponape" },
+    { "Qyzylorda Standard Time"               , "Asia/Qyzylorda" },
+    { "Reunion Standard Time"                 , "Indian/Reunion" },
+    { "Romance Standard Time"                 , "Europe/Paris" },
+    { "Rothera Standard Time"                 , "Antarctica/Rothera" },
+    { "Russian Standard Time"                 , "Europe/Moscow" },
+    { "SA Eastern Standard Time"              , "America/Buenos_Aires" },
+    { "SA Pacific Standard Time"              , "America/Bogota" },
+    { "SA Western Standard Time"              , "America/Caracas" },
+    { "SE Asia Standard Time"                 , "Asia/Bangkok" },
+    { "Sakhalin Standard Time"                , "Asia/Sakhalin" },
+    { "Samara Standard Time"                  , "Europe/Samara" },
+    { "Samarkand Standard Time"               , "Asia/Samarkand" },
+    { "Samoa Standard Time"                   , "Pacific/Apia" },
+    { "Seychelles Standard Time"              , "Indian/Mahe" },
+    { "Shevchenko Standard Time"              , "Asia/Aqtau" },
+    { "Singapore Standard Time"               , "Asia/Singapore" },
+    { "Solomon Standard Time"                 , "Pacific/Guadalcanal" },
+    { "South Africa Standard Time"            , "Africa/Johannesburg" },
+    { "South_Georgia Standard Time"           , "Atlantic/South_Georgia" },
+    { "Sri Lanka Standard Time"               , "Asia/Colombo" },
+    { "Suriname Standard Time"                , "America/Paramaribo" },
+    { "Sverdlovsk Standard Time"              , "Asia/Yekaterinburg" },
+    { "Syowa Standard Time"                   , "Antarctica/Syowa" },
+    { "Tahiti Standard Time"                  , "Pacific/Tahiti" },
+    { "Taipei Standard Time"                  , "Asia/Taipei" },
+    { "Tajikistan Standard Time"              , "Asia/Dushanbe" },
+    { "Tashkent Standard Time"                , "Asia/Tashkent" },
+    { "Tasmania Standard Time"                , "Australia/Hobart" },
+    { "Tbilisi Standard Time"                 , "Asia/Tbilisi" },
+    { "Tokelau Standard Time"                 , "Pacific/Fakaofo" },
+    { "Tokyo Standard Time"                   , "Asia/Tokyo" },
+    { "Tonga Standard Time"                   , "Pacific/Tongatapu" },
+    { "Truk Standard Time"                    , "Pacific/Truk" },
+    { "Turkey Standard Time"                  , "Europe/Istanbul" },
+    { "Turkmenistan Standard Time"            , "Asia/Ashgabat" },
+    { "Tuvalu Standard Time"                  , "Pacific/Funafuti" },
+    { "US Eastern Standard Time"              , "America/Indianapolis" },
+    { "US Mountain Standard Time"             , "America/Phoenix" },
+    { "Uralsk Standard Time"                  , "Asia/Oral" },
+    { "Uruguay Standard Time"                 , "America/Montevideo" },
+    { "Urumqi Standard Time"                  , "Asia/Urumqi" },
+    { "Uzbekistan Standard Time"              , "Asia/Tashkent" },
+    { "Vanuatu Standard Time"                 , "Pacific/Efate" },
+    { "Venezuela Standard Time"               , "America/Caracas" },
+    { "Vladivostok Standard Time"             , "Asia/Vladivostok" },
+    { "Volgograd Standard Time"               , "Europe/Volgograd" },
+    { "Vostok Standard Time"                  , "Antarctica/Vostok" },
+    { "W. Australia Standard Time"            , "Australia/Perth" },
+    { "W. Central Africa Standard Time"       , "Africa/Lagos" },
+    { "W. Europe Standard Time"               , "Europe/Berlin" },
+    { "Wake Standard Time"                    , "Pacific/Wake" },
+    { "Wallis Standard Time"                  , "Pacific/Wallis" },
+    { "West Asia Standard Time"               , "Asia/Karachi" },
+    { "West Pacific Standard Time"            , "Pacific/Guam" },
+    { "Yakutsk Standard Time"                 , "Asia/Yakutsk" },
+    { "Yekaterinburg Standard Time"           , "Asia/Yekaterinburg" },
+    { "Yerevan Standard Time"                 , "Asia/Yerevan" },
+    { "Yukon Standard Time"                   , "America/Yakutat" },
+    { NULL, NULL }
+};
+
+static const char*
+get_zoneinfo_timezone( void )
+{
+    if (!android_timezone_init)
+    {
+        char		          tzname[128];
+        time_t		          t = time(NULL);
+        struct tm*            tm = localtime(&t);
+        const Win32Timezone*  win32tz = _win32_timezones;
+
+        android_timezone_init = 1;
+
+        if (!tm) {
+            D("%s: could not determine current date/time\n", __FUNCTION__);
+            return NULL;
+        }
+
+        memset(tzname, 0, sizeof(tzname));
+        strftime(tzname, sizeof(tzname) - 1, "%Z", tm);
+
+        for (win32tz = _win32_timezones; win32tz->win_name != NULL; win32tz++)
+            if ( !strcmp(win32tz->win_name, tzname) ) {
+                android_timezone = win32tz->zoneinfo_name;
+                goto Exit;
+            }
+
+#if 0  /* TODO */
+    /* we didn't find it, this may come from localized versions of Windows. we're going to explore the registry,
+    * as the code in Postgresql does...
+    */
+#endif
+        D( "%s: could not determine current timezone\n", __FUNCTION__ );
+        return NULL;
+    }
+Exit:
+    D( "emulator: found timezone %s\n", android_timezone );
+    return android_timezone;
+}
+
+#endif /* _WIN32 */
+
diff --git a/android/utils/timezone.h b/android/utils/timezone.h
new file mode 100644
index 0000000..bf5f731
--- /dev/null
+++ b/android/utils/timezone.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2007-2008 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.
+*/
+#ifndef _ANDROID_UTILS_TIMEZONE_H
+#define _ANDROID_UTILS_TIMEZONE_H
+
+/* try to set the default host timezone, returns 0 on success, or -1 if
+ * 'tzname' is not in zoneinfo format (e.g. Area/Location)
+ */
+extern int  timezone_set( const char*  tzname );
+
+/* append the current host "zoneinfo" timezone name to a given buffer. note
+ * that this is something like "America/Los_Angeles", and not the human-friendly "PST"
+ * this is required by the Android emulated system...
+ *
+ * the implementation of this function is really tricky and is OS-dependent
+ * on Unix systems, it needs to cater to the TZ environment variable, uhhh
+ *
+ * if TZ is defined to something like "CET" or "PST", this will return the name "Unknown/Unknown"
+ */
+extern char*  bufprint_zoneinfo_timezone( char*  buffer, char*  end );
+
+#endif /* _ANDROID_UTILS_TIMEZONE_H */