am 9775ffe5: Merge "Update SDK files to API 12/Android 3.1" into honeycomb-mr1

* commit '9775ffe5fd3b8498137edf59c7570c4639a73763':
  Update SDK files to API 12/Android 3.1
diff --git a/apps/SpareParts/res/xml/spare_parts.xml b/apps/SpareParts/res/xml/spare_parts.xml
index 524092e..0d06e26 100644
--- a/apps/SpareParts/res/xml/spare_parts.xml
+++ b/apps/SpareParts/res/xml/spare_parts.xml
@@ -26,7 +26,7 @@
                 android:summary="@string/summary_battery_history">
             <intent android:action="android.intent.action.MAIN"
                     android:targetPackage="com.android.settings"
-                    android:targetClass="com.android.settings.battery_history.BatteryHistory" />
+                    android:targetClass="com.android.settings.fuelgauge.PowerUsageSummary" />
         </PreferenceScreen>
         
         <PreferenceScreen android:key="battery_information_settings"
diff --git a/build/sdk.atree b/build/sdk.atree
index d098400..fa8fd40 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -71,10 +71,10 @@
 external/clang/LICENSE.TXT       platforms/${PLATFORM_NAME}/renderscript/clang-include/LICENSE.TXT
 
 # System images + Kernel
-system.img                              platforms/${PLATFORM_NAME}/images/system.img
-ramdisk.img                             platforms/${PLATFORM_NAME}/images/ramdisk.img
-userdata.img                            platforms/${PLATFORM_NAME}/images/userdata.img
-prebuilt/android-arm/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/kernel-qemu
+system.img                              platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/system.img
+ramdisk.img                             platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/ramdisk.img
+userdata.img                            platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/userdata.img
+prebuilt/android-${TARGET_ARCH}/kernel/kernel-qemu platforms/${PLATFORM_NAME}/images/${TARGET_CPU_ABI}/kernel-qemu
 
 # emulator skins from sdk.git
 #development/tools/emulator/skins/QVGA      platforms/${PLATFORM_NAME}/skins/QVGA
diff --git a/ndk/platforms/android-3/include/stdint.h b/ndk/platforms/android-3/include/stdint.h
index 237baa2..e791475 100644
--- a/ndk/platforms/android-3/include/stdint.h
+++ b/ndk/platforms/android-3/include/stdint.h
@@ -41,11 +41,6 @@
 #  define  __STDINT_MACROS
 #endif
 
-/* the definitions of STDINT_LIMITS depend on those of STDINT_MACROS */
-#if defined __STDINT_LIMITS && !defined __STDINT_MACROS
-#  define  __STDINT_MACROS
-#endif
-
 #if !defined __STRICT_ANSI__ || __STDC_VERSION__ >= 199901L
 #  define __STDC_INT64__
 #endif
@@ -185,13 +180,14 @@
 #  define UINT_FAST64_MAX UINT64_MAX
 #endif
 
+#define __INT64_C(c)     c ## LL
+#define __UINT64_C(c)     c ## ULL
+
 #ifdef __STDINT_MACROS
-#  define __INT64_C(c)     c ## LL
 #  define INT64_C(c)       __INT64_C(c)
 #  define INT_LEAST64_C(c) INT64_C(c)
 #  define INT_FAST64_C(c)  INT64_C(c)
 
-#  define __UINT64_C(c)     c ## ULL
 #  define UINT64_C(c)       __UINT64_C(c)
 #  define UINT_LEAST64_C(c) UINT64_C(c)
 #  define UINT_FAST64_C(c)  UINT64_C(c)
@@ -211,14 +207,20 @@
 typedef int           intptr_t;
 typedef unsigned int  uintptr_t;
 
+#ifdef __STDINT_LIMITS
 #  define INTPTR_MIN    INT32_MIN
 #  define INTPTR_MAX    INT32_MAX
 #  define UINTPTR_MAX   UINT32_MAX
+#  define PTRDIFF_MIN   INT32_MIN
+#  define PTRDIFF_MAX   INT32_MAX
+#endif
+
+#ifdef __STDINT_MACROS
 #  define INTPTR_C(c)   INT32_C(c)
 #  define UINTPTR_C(c)  UINT32_C(c)
 #  define PTRDIFF_C(c)  INT32_C(c)
-#  define PTRDIFF_MIN   INT32_MIN
-#  define PTRDIFF_MAX   INT32_MAX
+#endif
+
 
 
 /*
@@ -230,24 +232,32 @@
 typedef uint64_t uintmax_t;
 typedef int64_t  intmax_t;
 
-#define INTMAX_MIN	INT64_MIN
-#define INTMAX_MAX	INT64_MAX
-#define UINTMAX_MAX	UINT64_MAX
+#ifdef __STDINT_LIMITS
+#  define INTMAX_MIN	INT64_MIN
+#  define INTMAX_MAX	INT64_MAX
+#  define UINTMAX_MAX	UINT64_MAX
+#endif
 
-#define INTMAX_C(c)	INT64_C(c)
-#define UINTMAX_C(c)	UINT64_C(c)
+#ifdef __STDINT_MACROS
+#  define INTMAX_C(c)	INT64_C(c)
+#  define UINTMAX_C(c)	UINT64_C(c)
+#endif
 
 #else /* !__STDC_INT64__ */
 
 typedef uint32_t  uintmax_t;
 typedef int32_t   intmax_t;
 
-#define  INTMAX_MIN    INT32_MIN
-#define  INTMAX_MAX    INT32_MAX
-#define  UINTMAX_MAX   UINT32_MAX
+#ifdef __STDINT_LIMITS
+#  define  INTMAX_MIN    INT32_MIN
+#  define  INTMAX_MAX    INT32_MAX
+#  define  UINTMAX_MAX   UINT32_MAX
+#endif
 
-#define INTMAX_C(c)	INT32_C(c)
-#define UINTMAX_C(c)	UINT32_C(c)
+#ifdef __STDINT_MACROS
+#  define INTMAX_C(c)	INT32_C(c)
+#  define UINTMAX_C(c)	UINT32_C(c)
+#endif
 
 #endif /* !__STDC_INT64__ */
 
diff --git a/ndk/platforms/android-3/include/unistd.h b/ndk/platforms/android-3/include/unistd.h
index 6d0515a..25fc334 100644
--- a/ndk/platforms/android-3/include/unistd.h
+++ b/ndk/platforms/android-3/include/unistd.h
@@ -126,7 +126,7 @@
 extern ssize_t read(int, void *, size_t);
 extern ssize_t write(int, const void *, size_t);
 extern ssize_t pread(int, void *, size_t, off_t);
-extern ssize_t pwrite(int, void *, size_t, off_t);
+extern ssize_t pwrite(int, const void *, size_t, off_t);
 
 extern int dup(int);
 extern int dup2(int, int);
diff --git a/ndk/platforms/android-8/include/unistd.h b/ndk/platforms/android-8/include/unistd.h
index d64c971..863d56d 100644
--- a/ndk/platforms/android-8/include/unistd.h
+++ b/ndk/platforms/android-8/include/unistd.h
@@ -130,7 +130,7 @@
 extern ssize_t read(int, void *, size_t);
 extern ssize_t write(int, const void *, size_t);
 extern ssize_t pread(int, void *, size_t, off_t);
-extern ssize_t pwrite(int, void *, size_t, off_t);
+extern ssize_t pwrite(int, const void *, size_t, off_t);
 
 extern int dup(int);
 extern int dup2(int, int);
diff --git a/ndk/platforms/android-9/include/android/input.h b/ndk/platforms/android-9/include/android/input.h
index 7df13c3..9449574 100644
--- a/ndk/platforms/android-9/include/android/input.h
+++ b/ndk/platforms/android-9/include/android/input.h
@@ -485,7 +485,7 @@
 
 /* Get the current pressure of this event for the given pointer index.
  * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
- * however values higher than 1 may be generated depending on the calibration of
+ * although values higher than 1 may be generated depending on the calibration of
  * the input device. */
 float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index);
 
@@ -545,7 +545,8 @@
  * and views.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index);
+float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
 
 /* Get the historical raw Y coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
@@ -554,7 +555,8 @@
  * and views.
  * Whole numbers are pixels; the value may have a fraction for input devices
  * that are sub-pixel precise. */
-float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index);
+float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
 
 /* Get the historical X coordinate of this event for the given pointer index that
  * occurred between this event and the previous motion event.
@@ -573,7 +575,7 @@
 /* Get the historical pressure of this event for the given pointer index that
  * occurred between this event and the previous motion event.
  * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
- * however values higher than 1 may be generated depending on the calibration of
+ * although values higher than 1 may be generated depending on the calibration of
  * the input device. */
 float AMotionEvent_getHistoricalPressure(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
diff --git a/ndk/platforms/android-9/include/pthread.h b/ndk/platforms/android-9/include/pthread.h
index 1e80b12..5e87043 100644
--- a/ndk/platforms/android-9/include/pthread.h
+++ b/ndk/platforms/android-9/include/pthread.h
@@ -235,7 +235,7 @@
     void*            reserved[4];  /* for future extensibility */
 } pthread_rwlock_t;
 
-#define PTHREAD_RWLOCK_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, 0, NULL, 0, 0 }
+#define PTHREAD_RWLOCK_INITIALIZER  { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0, 0, 0, { NULL, NULL, NULL, NULL } }
 
 int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
 int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
diff --git a/ndk/platforms/android-9/include/unistd.h b/ndk/platforms/android-9/include/unistd.h
index 29154a2..21154ad 100644
--- a/ndk/platforms/android-9/include/unistd.h
+++ b/ndk/platforms/android-9/include/unistd.h
@@ -133,7 +133,7 @@
 extern ssize_t read(int, void *, size_t);
 extern ssize_t write(int, const void *, size_t);
 extern ssize_t pread(int, void *, size_t, off_t);
-extern ssize_t pwrite(int, void *, size_t, off_t);
+extern ssize_t pwrite(int, const void *, size_t, off_t);
 
 extern int dup(int);
 extern int dup2(int, int);
diff --git a/pdk/docs/compatibility/ndef-push-protocol.pdf b/pdk/docs/compatibility/ndef-push-protocol.pdf
new file mode 100644
index 0000000..2300a6b
--- /dev/null
+++ b/pdk/docs/compatibility/ndef-push-protocol.pdf
@@ -0,0 +1,471 @@
+%PDF-1.4

+%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com

+% 'BasicFonts': class PDFDictionary 

+1 0 obj

+% The standard fonts dictionary

+<< /F1 2 0 R

+ /F2 3 0 R

+ /F3 13 0 R >>

+endobj

+% 'F1': class PDFType1Font 

+2 0 obj

+% Font Helvetica

+<< /BaseFont /Helvetica

+ /Encoding /WinAnsiEncoding

+ /Name /F1

+ /Subtype /Type1

+ /Type /Font >>

+endobj

+% 'F2': class PDFType1Font 

+3 0 obj

+% Font Helvetica-Bold

+<< /BaseFont /Helvetica-Bold

+ /Encoding /WinAnsiEncoding

+ /Name /F2

+ /Subtype /Type1

+ /Type /Font >>

+endobj

+% 'Annot.NUMBER1': class LinkAnnotation 

+4 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 14 0 R

+ /XYZ

+ 55

+ 511.3263

+ 0 ]

+ /Rect [ 70

+ 613.115

+ 132.5125

+ 624.365 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER2': class LinkAnnotation 

+5 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 14 0 R

+ /XYZ

+ 55

+ 439.0138

+ 0 ]

+ /Rect [ 70

+ 601.865

+ 109.5925

+ 613.115 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER3': class LinkAnnotation 

+6 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 14 0 R

+ /XYZ

+ 55

+ 344.0763

+ 0 ]

+ /Rect [ 70

+ 590.615

+ 120.0175

+ 601.865 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER4': class LinkAnnotation 

+7 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 14 0 R

+ /XYZ

+ 55

+ 307.7975

+ 0 ]

+ /Rect [ 85

+ 577.365

+ 158.365

+ 588.615 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER5': class LinkAnnotation 

+8 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 14 0 R

+ /XYZ

+ 55

+ 230.6725

+ 0 ]

+ /Rect [ 85

+ 566.115

+ 124.1875

+ 577.365 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER6': class LinkAnnotation 

+9 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 15 0 R

+ /XYZ

+ 55

+ 667.0475

+ 0 ]

+ /Rect [ 85

+ 554.865

+ 139.6

+ 566.115 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER7': class LinkAnnotation 

+10 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 15 0 R

+ /XYZ

+ 55

+ 518.6725

+ 0 ]

+ /Rect [ 85

+ 543.615

+ 144.1975

+ 554.865 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER8': class LinkAnnotation 

+11 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 15 0 R

+ /XYZ

+ 55

+ 328.7975

+ 0 ]

+ /Rect [ 85

+ 532.365

+ 121.6825

+ 543.615 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'Annot.NUMBER9': class LinkAnnotation 

+12 0 obj

+<< /Border [ 0

+ 0

+ 0 ]

+ /Contents ()

+ /Dest [ 15 0 R

+ /XYZ

+ 55

+ 219.6725

+ 0 ]

+ /Rect [ 85

+ 521.115

+ 118.765

+ 532.365 ]

+ /Subtype /Link

+ /Type /Annot >>

+endobj

+% 'F3': class PDFType1Font 

+13 0 obj

+% Font Times-Roman

+<< /BaseFont /Times-Roman

+ /Encoding /WinAnsiEncoding

+ /Name /F3

+ /Subtype /Type1

+ /Type /Font >>

+endobj

+% 'Page1': class PDFPage 

+14 0 obj

+% Page dictionary

+<< /Annots [ 4 0 R

+ 5 0 R

+ 6 0 R

+ 7 0 R

+ 8 0 R

+ 9 0 R

+ 10 0 R

+ 11 0 R

+ 12 0 R ]

+ /Contents 32 0 R

+ /MediaBox [ 0

+ 0

+ 612

+ 792 ]

+ /Parent 31 0 R

+ /Resources << /Font 1 0 R

+ /ProcSet [ /PDF

+ /Text

+ /ImageB

+ /ImageC

+ /ImageI ] >>

+ /Rotate 0

+ /Trans <<  >>

+ /Type /Page >>

+endobj

+% 'Page2': class PDFPage 

+15 0 obj

+% Page dictionary

+<< /Contents 33 0 R

+ /MediaBox [ 0

+ 0

+ 612

+ 792 ]

+ /Parent 31 0 R

+ /Resources << /Font 1 0 R

+ /ProcSet [ /PDF

+ /Text

+ /ImageB

+ /ImageC

+ /ImageI ] >>

+ /Rotate 0

+ /Trans <<  >>

+ /Type /Page >>

+endobj

+% 'Page3': class PDFPage 

+16 0 obj

+% Page dictionary

+<< /Contents 34 0 R

+ /MediaBox [ 0

+ 0

+ 612

+ 792 ]

+ /Parent 31 0 R

+ /Resources << /Font 1 0 R

+ /ProcSet [ /PDF

+ /Text

+ /ImageB

+ /ImageC

+ /ImageI ] >>

+ /Rotate 0

+ /Trans <<  >>

+ /Type /Page >>

+endobj

+% 'R17': class PDFCatalog 

+17 0 obj

+% Document Root

+<< /Outlines 19 0 R

+ /PageMode /UseNone

+ /Pages 31 0 R

+ /Type /Catalog >>

+endobj

+% 'R18': class PDFInfo 

+18 0 obj

+<< /Author ()

+ /CreationDate (D:20110303200815+08'00')

+ /Keywords ()

+ /Producer (pisa HTML to PDF <http://www.htmltopdf.org>)

+ /Subject ()

+ /Title (Android NDEF Push Protocol Specification) >>

+endobj

+% 'R19': class PDFOutlines 

+19 0 obj

+<< /Count 3

+ /First 20 0 R

+ /Last 20 0 R

+ /Type /Outlines >>

+endobj

+% 'Outline.0': class OutlineEntryObject 

+20 0 obj

+<< /Count -4

+ /Dest [ 14 0 R

+ /Fit ]

+ /First 21 0 R

+ /Last 24 0 R

+ /Parent 19 0 R

+ /Title (Android NDEF Push Protocol Specification) >>

+endobj

+% 'Outline.2.0': class OutlineEntryObject 

+21 0 obj

+<< /Dest [ 14 0 R

+ /Fit ]

+ /Next 22 0 R

+ /Parent 20 0 R

+ /Title (Table of Contents) >>

+endobj

+% 'Outline.2.1': class OutlineEntryObject 

+22 0 obj

+<< /Dest [ 14 0 R

+ /Fit ]

+ /Next 23 0 R

+ /Parent 20 0 R

+ /Prev 21 0 R

+ /Title (1. Revision History) >>

+endobj

+% 'Outline.2.2': class OutlineEntryObject 

+23 0 obj

+<< /Dest [ 14 0 R

+ /Fit ]

+ /Next 24 0 R

+ /Parent 20 0 R

+ /Prev 22 0 R

+ /Title (2. Overview) >>

+endobj

+% 'Outline.2.3': class OutlineEntryObject 

+24 0 obj

+<< /Count -6

+ /Dest [ 14 0 R

+ /Fit ]

+ /First 25 0 R

+ /Last 30 0 R

+ /Parent 20 0 R

+ /Prev 23 0 R

+ /Title (3. Data Format) >>

+endobj

+% 'Outline.3.0': class OutlineEntryObject 

+25 0 obj

+<< /Dest [ 14 0 R

+ /Fit ]

+ /Next 26 0 R

+ /Parent 24 0 R

+ /Title (3.1. Protocol Versions) >>

+endobj

+% 'Outline.3.1': class OutlineEntryObject 

+26 0 obj

+<< /Dest [ 14 0 R

+ /Fit ]

+ /Next 27 0 R

+ /Parent 24 0 R

+ /Prev 25 0 R

+ /Title (3.2. Header) >>

+endobj

+% 'Outline.3.2': class OutlineEntryObject 

+27 0 obj

+<< /Dest [ 15 0 R

+ /Fit ]

+ /Next 28 0 R

+ /Parent 24 0 R

+ /Prev 26 0 R

+ /Title (3.3. NDEF Entry) >>

+endobj

+% 'Outline.3.3': class OutlineEntryObject 

+28 0 obj

+<< /Dest [ 15 0 R

+ /Fit ]

+ /Next 29 0 R

+ /Parent 24 0 R

+ /Prev 27 0 R

+ /Title (3.4. Action Codes) >>

+endobj

+% 'Outline.3.4': class OutlineEntryObject 

+29 0 obj

+<< /Dest [ 15 0 R

+ /Fit ]

+ /Next 30 0 R

+ /Parent 24 0 R

+ /Prev 28 0 R

+ /Title (3.5. Server) >>

+endobj

+% 'Outline.3.5': class OutlineEntryObject 

+30 0 obj

+<< /Dest [ 15 0 R

+ /Fit ]

+ /Parent 24 0 R

+ /Prev 29 0 R

+ /Title (3.6. Client) >>

+endobj

+% 'R31': class PDFPages 

+31 0 obj

+% page tree

+<< /Count 3

+ /Kids [ 14 0 R

+ 15 0 R

+ 16 0 R ]

+ /Type /Pages >>

+endobj

+% 'R32': class PDFStream 

+32 0 obj

+% page stream

+<< /Filter [ /ASCII85Decode

+ /FlateDecode ]

+ /Length 2055 >>

+stream

+GauHM=]68"&:UO7s3Qg;.k&i9p:fX=c#/ZFPB^$6<I#1b^lu0=]JF%:rr%"5F*fNA!%?htI=,dXC39mb*5@4,^"<=tS&:^g!Q'Ha%1%_L0Y`3tq<?#9qF>)UXok!/Hl$p?ir[Lp5/qtf$d47Akm:N.Kd33a4;[-!&;&jtg*_qFF3,`[hsi:gM,uD2$1hN2pFlC+hu(BY-5^+BX;?h'%ej/BTUp'8(gKgj`<+G;nhsam;6Y`"+"f0S[S'XTMk`+46u2S+<K#c^=NE=T_B-X<\=PWfp-A6sraa/7!aPP'_f"/OSrstKV8Ms%Z5$'@q:[%,X#ND(@,ad4cR^]e3Od9cCHQVV"&4f%@r9oSnYX@C[[?1<J>^V\pgqN`7U2o9T$-H-K'3Eq7q&F71`;;$SN+Xc3-q%8YJ6X"KXCL)KM>b#hLLZo,b\ZQGJ$^Opc)nc?&,shX"lN)l7jZ-lFDi]^DtXYPsD(Jc'dC;LkIcV%)/`iTJuj[OJGa$YCfp[RDN*a>7CMdX*>_b6_Baji.F]L>Xn6QVT4k;q]f>m*k+?l#L=lO/@_ea;%3+$)-'s>7X8_k'LMu&%VJi)Q.T+9ImC3SV?si(qBO[HWYIF;*YNcMRj^bf3\eNth..^4LC#\e9R&s.RJF.9P4TCk)>-kKV2G/hOAS'L?A*#W6Z(s>Ge9VbMeQV!#2Hg!^*0,(gj9IdY6.HQO5R<"iBt0RW=i[lBc[H,YulJ7Ef1j\RnF]]OhU7cb%4rLK5PtPMoH+s$m3(Jh3QgP3kju;2N:q$nAWSD_CVV)6*fnB$UI\4+qD'Ab73k;S23oIip![1Y[fiP^6c\.cl+:daHlr%HPiQ0>XP$PC=\HnJj0O^:\<u#QOh>j.K:'s"'l#a'X_&#E6!@UaZn;C2u.PR7P_VTf$"msST`7ugMH%/h)_B3duWuFU\p3Y51?W48la@r:U]YM[Rd_">b>=O=&J=?@%Y]X-s$"Ein-%uQr"a';P?Oj_1g1=[b<&WhCWTA`rrZr&4uFV%3mPRE1Nje,EutC@ao]Ao8.25?D(tFf(<I0"l&S#FJqJW;r?NR)Lb11YJ8l:g:rnflaVG7I@e]4]Rh7,#t_AS@ZS%D-a.a13X%'qdV):Ej42]W)&u\n@R]ii/dAeY>2h)Laf#W-LQ+n=H)ojMN]*i<:i[X/'ZnHN8lmJp1:)^hrYB7ZM\QA/U=M86SCA&>*Yk!>IM7Aad8#;_[cShi?6h(D`Mn8NU5N!PC^\Q>R6n46DPK0c!*9T$rq\MX\OIAA`4JiUT?R^F`klNYrmTW:[7En%7+KL[M>FGS+[UsL9TER)pG,k:c9$psKDCCV]j=26"<YU%*Lnd8=Qq:TD_J5qmM7;jhA55$fsOE_8njC?U6:)nX\-BfaY.Ts>+4,!#d&q#7`\lURnShSEop.RJ0(cN1C'WaYI!I3"k.XL?p<rL%_k,jVmeXO`3YI$M:<\pDLrEamB`W#km_bX0U+GXffU9,4G(M`K8c-'/>CBiV?%;$&>Uh4f%=8?'MjP<aD]b=80/.Nk*@s<,_^#VA.b59f\7]oI`Y&'2[sFPaK$gY@q^ZR%\AeZ*C-(%F[9k[hNoQ-70*jO,K.>)rs>Gf=OSAtpK/js<3THa:QgDjdIVFdhWBm8-2_KWMs^Ol4sp7\l!,U#qK0lV*@d8UhG_)m-FG2"N)N(DR_">(hpLSioYQ%t^G=cRa#;Yso/;Zum`5%-=c`:#GTP_cRdTO1@9qZ*nT)N.iO`@``]aCdp>9@3YF88@1@g2`OZYk$ibmI7j9b"sD>"'MX6I,to2C<D!MsQ0[iA'Q%Mh'lrai0kYGAH>]M`c8YBh?kCIl+gP3S["MNY5nq=-QG]$RJ70)SJWf%$.@4jfM:>ne)NrJ'6VATqZK2u:/?@'qe*8G<sAgic=cMnG\d'M=dXT!@jSg_4gX,<V*Udir/nPY"k<Q1CeB*+dYWM,&th.'496%?I>T9,tS1%`YeNClRT)9Y'gklb5I*pbb*AX#$nqQE-!oX6%KnJ^kFMG"_KTh`9PM`f#Du'<u^b]s6gL07_N8rrBb=mfr~>endstream

+endobj

+% 'R33': class PDFStream 

+33 0 obj

+% page stream

+<< /Filter [ /ASCII85Decode

+ /FlateDecode ]

+ /Length 2836 >>

+stream

+Gb"/*=``=W&q3VVr^/nr[N($W%Vso`5'CQha_'+mXdZ88@7WpUL5/)lp?:CP2o#Nk5`/NDW]\4CC^Fc3)BW.BrYg^t2L[aYG7XlSZ@qt5%QH'l=5ZcR#qS<V_t*2aDt:pt`2=8f?#)XC0o^>]hDo/:27G`hS\iS)2lP9+-CS-tZRIG8E#]7t;*W;b\#)!Y/\eVL>e*)8ngc9k+_UgLrd65'r73c<2Rb8L9W:9PqYnkEa-KA<[=shI4^*EGYe7l-a=dAB;Pq?ti`ML(kuj#Vi7tl);4i%%(R@@uJku+OO2-o@j%KlfdR3oY'Qeob2BI;"=9MAQEsA`*(VY@=P*#PIlk7.d#n);33Eri6JmT19AsqRk!qtN[;m,Kpf:6arLb0#0M?eTj'%bdS"[)\0Nkl*a,4M?DIkT^fX2^hGq\iYQSSJoGr1.5W-IEn"C&EJq6]d$2:pnqm[qV/7cl*0F+ZZrBmUWS)SCJ@Okb#sFs1F.j-i<!egTp(e3Q3utQ9'*1)<-C[+P=.D9*.R).!-XSWfP\_1>d[2<r5bEZ\MPLJI`n;6,pC^>mfc5NnD[=\;C[oVT!u&"jH1G%dh%2r?j0l/hE.9`qXIAp.+U?D,Yd*>Np(^mZ?FKJ.e"3DV6X2gS;+cB6MbfW8>S)8[ClfotErP@>Be)VSs5i*UD+!j\+X6g;\?\7UeeVF$tA`8l2.^#E_d#$ETu&3Qe>/CAeCDp41tuqDbY3cjjTG]sUAqD7W6gm70=fLp_L4P-GO.)`&n)p3mmAmF%n?Yn,p'SLQ_gK0AM8bH14>B&t-E2.I+RYt[fFT$fWb4e9f7D@Y^&D9Wl<'e!_Gc+JjsDAbA*=Qrt[<<pSCYfKT53E)pQHn"6^EQg,%aB:o^3Ju6$SucK[hCq14A1:&Z-<0E+KmRVLrYdk)GeO4@#Fi"jSmM:<QK-'t^*j\RT*MQHMAo0G3[q\++4XFSUg6=h[a3X*eD]a0h:IGHW3"tEL->Ho#q(#7s!Yu/OT\G)b670/qfcX^DX4*DeF%URJW>a9,7T"U)p9100ICs>(k%0/MZ_[1A9:iF2jAJ6E`!9]OGl#)n/Cqn#hIlLq7V;Uo(\&DZHbD(]M*%Q'W^FD[nAi;P*3`7?@q-<TMWHJatl_o[lBVlpr@V+FW(1()7t"?c:gK!0onGIp)?Dk0gCt/P.#eWAre:#o,E"NE_5r8Q"N#oosE3kXX0c5F;L1\TO&j!jtVY@Z(-S)n3QYZ<3:M+M=Hlf;$K3dUINZ-`gLL^-\?b-qbTD7S#`mJ7*`uImP2-!0n?mu+h=nVHV?#6*83T9,[:!8NN;0$6eeNF%n1o:!QUca'klT!8=Q^Il5<T[*J_1H/s7ctH:HFo6U:'>9%%9`n&S[O#gg8"HP+du)DLRC;R*^YW5i4sF=['._J@Z'(H`,S>4LYZOI_:$6AKQ6<]2r>>c4SsKE`2c-4BPL`KH).TGN7(#*\;qOK3P(90+lZ`NW&/DO4ocacVuf![9'c`CJWM7GXBECq-R1pk^t$>2\H0:J5.^gFNf<8JP"q$@!%"5K"V/!2_k%XKjYe+1Alpr0]k=Y:]M[c<alN,cn`;g8bPi9rHa!r(QZ<[*>M%)(?7^V+!G!NA45uAO5R`CBCBteV4Rk+Eqk:%=6gk]8SV6,/A:4#-kpuOKCK>bV8,-k!qI?6=HrD#1#\dJ?Y':K_FHn+0GK8_YTiTfu%QkTt7=F(YPXcE":qrBf607DrG"4n6;^ZWEbUH*;I#M)&"QJ7M*YY<bc-#fcqj2`F45QX<e!`]T&!a,3GL^K@H*Al[!6-jtp<cK\BQ,#.(EVLc>a"&MSMGN2+RYj/Or6'\Tiq3Mt)&hRfE9^/M(rkI9fQ*ZM''OJUng@,^i[:=:fdLK0Nj>-]#jN)^t@UW;&to$dicH/Dp#W/e6jME3FY\nE7dN;2:=&a@dAgK-!>:!,#7E^1fq`n\0Xf:jT]I5U\9lI8t)8`%6l-RJ4AVS?C@0Zb9W$BpYM%+3TPs5l&UEe4=kDJe3Cr?rog-mSX<,@%=/i7[f%rcq-C;gJk3(rP9:hjmN'ff&E3:4(Wql;BfU6+3dE.V!6HEdYoK_4jq(j@P.4$kbd:`,%!#6<VGu/(ned/].E9j<@,lQ2`-SVH#h0nPfq10=poI3D8s#80\LkhklX%"cP[0\6gOugRZt2H!6rJNfZgaH->1kl'(L,&IY*#edm?h$`,^0M=D?_/8juSL<5>o,hFTJQ,tPlqGp`nrE#/rW&YTrK+4]JP411U`DB'rq2$LHHJ'u08`V+U0BI:>:ZI?9[9*N^.ORcNKIJbukD3"jL5`aIGFE08`l8\6Fn'P&fH\A@j_@+HpF/&!f<P>jRF&B]L5HVkegj@qiJU>VcAf3LJmoLD#2E^sc)E[uiDl_Q=-X_K9SmM"DI6L=\dln/]7dUVC"?u&mtS1</eEME(>ML2L>+SV?`moa5P)6"9]R$?\Cea,_s%N;!'WR&]t8dhXR5#TW`rLMP[]i`B?9;)Y8DJuP`r@>`eBLh5%R#YBFbMQSl'IJ5Hi"t5Crk$o8'--](X`TN-LB,nRdOe39a8.+.:TN=qGcj?C`*<NcI7faLim8*sOooGGc"M+Sk!6*IbZLi%LBHYO@DK_h#X#eF-qOL5c#0a?6^O'U*V:90K"O5P'GG8q-u7C(I>G)jVkp4iP'(q/@N%)%<]?&SR2Q&]D=`78+cqKf^FXRQld<pd)su`\Q!81I\?UI0Rg/KBj/?4MZ^e7LP(`\?/_7a(Vnno^Um384A!Y$qMXLA.p_mi-@d(k*aC+LhbEjbNQ\i"E_MRkaJK\Qsi`400b[["mQSrcBQI^WWu^Pqr[o_[4AE~>endstream

+endobj

+% 'R34': class PDFStream 

+34 0 obj

+% page stream

+<< /Filter [ /ASCII85Decode

+ /FlateDecode ]

+ /Length 266 >>

+stream

+Gau0;_+qm%%)#a-5J/3`&aHH#G+QWIgL7sH5Y4+>e0V3@5l5oV^l[Ki%GA%gp[%Wj6C!.CFU)<r\6BP9K6Ntle_i=Q\L`b$l"f)(crsS9G(/A&>In4b<\r/.mq%V\l.a:Z`S>tS+B"%kqNI[SB!SLY%*uGP?%ZM"2q`VKo6=uX^Q5Y2rnhL905u=e5%=-Y^^.Y=@hdgpENolm0!mAXm[K#E&@Ab/]X6mM_?@&0Lr"cdD_d:#ph<F_dlEVa]'>?+;&16&d9s?~>endstream

+endobj

+xref

+0 35

+0000000000 65535 f

+0000000113 00000 n

+0000000234 00000 n

+0000000399 00000 n

+0000000587 00000 n

+0000000814 00000 n

+0000001041 00000 n

+0000001268 00000 n

+0000001494 00000 n

+0000001721 00000 n

+0000001945 00000 n

+0000002173 00000 n

+0000002401 00000 n

+0000002615 00000 n

+0000002783 00000 n

+0000003140 00000 n

+0000003410 00000 n

+0000003681 00000 n

+0000003819 00000 n

+0000004065 00000 n

+0000004190 00000 n

+0000004395 00000 n

+0000004549 00000 n

+0000004720 00000 n

+0000004883 00000 n

+0000005077 00000 n

+0000005236 00000 n

+0000005399 00000 n

+0000005566 00000 n

+0000005735 00000 n

+0000005898 00000 n

+0000006028 00000 n

+0000006154 00000 n

+0000008352 00000 n

+0000011331 00000 n

+trailer

+<< /ID 

+ % ReportLab generated PDF document -- digest (http://www.reportlab.com) 

+ [(L\026\316.\265\347\223\365\204y\010\361\341\344\330\360) (L\026\316.\265\347\223\365\204y\010\361\341\344\330\360)] 

+

+ /Info 18 0 R

+ /Root 17 0 R

+ /Size 35 >>

+startxref

+11712

+%%EOF

diff --git a/tools/emulator/opengl/host/tools/emugen/Android.mk b/tools/emulator/opengl/host/tools/emugen/Android.mk
new file mode 100644
index 0000000..fcd7b24
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/Android.mk
@@ -0,0 +1,10 @@
+
+LOCAL_PATH:=$(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := debug
+LOCAL_SRC_FILES := ApiGen.cpp EntryPoint.cpp main.cpp strUtils.cpp TypeFactory.cpp
+LOCAL_MODULE := emugen
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
new file mode 100644
index 0000000..9b7949d
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -0,0 +1,805 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "ApiGen.h"
+#include "EntryPoint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+#include <errno.h>
+#include <sys/types.h>
+
+
+EntryPoint * ApiGen::findEntryByName(const std::string & name)
+{
+    EntryPoint * entry = NULL;
+
+    size_t n = this->size();
+    for (size_t i = 0; i < n; i++) {
+        if (at(i).name() == name) {
+            entry = &(at(i));
+            break;
+        }
+    }
+    return entry;
+}
+
+void ApiGen::printHeader(FILE *fp) const
+{
+    fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
+    fprintf(fp, "// generated by 'emugen'\n");
+}
+
+int ApiGen::genProcTypes(const std::string &filename, SideType side)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    printHeader(fp);
+
+    fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "#define __%s_%s_proc_t_h\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "\n\n");
+    fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+
+        fprintf(fp, "typedef ");
+        e->retval().printType(fp);
+        fprintf(fp, " (* %s_%s_proc_t) (", e->name().c_str(), sideString(side));
+        if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
+        if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
+
+        VarsArray & evars = e->vars();
+        size_t n = evars.size();
+
+        for (size_t j = 0; j < n; j++) {
+            if (!evars[j].isVoid()) {
+                if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
+                evars[j].printType(fp);
+            }
+        }
+        fprintf(fp, ");\n");
+    }
+    fprintf(fp, "\n\n#endif\n");
+    return 0;
+}
+
+int ApiGen::genContext(const std::string & filename, SideType side)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    printHeader(fp);
+
+    fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+    fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+
+    //  fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+    fprintf(fp, "\n#include \"%s_%s_proc.h\"\n", m_basename.c_str(), sideString(side));
+
+    StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
+    for (size_t i = 0; i < contextHeaders.size(); i++) {
+        fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
+    }
+    fprintf(fp, "\n");
+
+    fprintf(fp, "\nstruct %s_%s_context_t {\n\n", m_basename.c_str(), sideString(side));
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+    }
+    // accessors
+    fprintf(fp, "\t//Accessors \n");
+
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        const char *n = e->name().c_str();
+        const char *s = sideString(side);
+        fprintf(fp, "\tvirtual %s_%s_proc_t set_%s(%s_%s_proc_t f) { %s_%s_proc_t retval = %s; %s = f; return retval;}\n", n, s, n, n, s, n, s,  n, n);
+    }
+
+    // virtual destructor
+    fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
+    // accessor
+    if (side == CLIENT_SIDE) {
+        fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
+                m_basename.c_str(), sideString(side));
+        fprintf(fp, "\tvoid setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
+    }
+
+    fprintf(fp, "};\n");
+
+    fprintf(fp, "\n#endif\n");
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genClientEntryPoints(const std::string & filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return errno;
+    }
+
+    printHeader(fp);
+    fprintf(fp, "#include <stdio.h>\n");
+    fprintf(fp, "#include <stdlib.h>\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(CLIENT_SIDE));
+    fprintf(fp, "\n");
+
+    fprintf(fp, "extern \"C\" {\n");
+
+    for (size_t i = 0; i < size(); i++) {
+        fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
+    }
+    fprintf(fp, "};\n\n");
+
+    fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
+            m_basename.c_str(), sideString(CLIENT_SIDE));
+
+    fprintf(fp,
+            "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n\n",
+            m_basename.c_str(), sideString(CLIENT_SIDE));
+
+
+    for (size_t i = 0; i < size(); i++) {
+        EntryPoint *e = &at(i);
+        e->print(fp);
+        fprintf(fp, "{\n");
+        fprintf(fp, "\t %s_%s_context_t * ctx = getCurrentContext(); \n",
+                m_basename.c_str(), sideString(CLIENT_SIDE));
+
+        bool shouldReturn = !e->retval().isVoid();
+
+        fprintf(fp, "\t %sctx->%s(ctx",
+                shouldReturn ? "return " : "",
+                e->name().c_str());
+        size_t nvars = e->vars().size();
+
+        for (size_t j = 0; j < nvars; j++) {
+            if (!e->vars()[j].isVoid()) {
+                fprintf(fp, ", %s", e->vars()[j].name().c_str());
+            }
+        }
+        fprintf(fp, ");\n");
+        fprintf(fp, "}\n\n");
+    }
+    fclose(fp);
+    return 0;
+}
+
+
+int ApiGen::genOpcodes(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return errno;
+    }
+
+    printHeader(fp);
+    fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
+    fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
+    for (size_t i = 0; i < size(); i++) {
+        fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
+    }
+    fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
+    fprintf(fp,"\n\n#endif\n");
+    fclose(fp);
+    return 0;
+
+}
+int ApiGen::genAttributesTemplate(const std::string &filename )
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    for (size_t i = 0; i < size(); i++) {
+        if (at(i).hasPointers()) {
+            fprintf(fp, "#");
+            at(i).print(fp);
+            fprintf(fp, "%s\n\n", at(i).name().c_str());
+        }
+    }
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genEncoderHeader(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+    std::string classname = m_basename + "_encoder_context_t";
+
+    fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+    fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+    fprintf(fp, "#include \"IOStream.h\"\n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
+
+    for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
+        fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
+    }
+    fprintf(fp, "\n");
+
+    fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+            classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
+    fprintf(fp, "\tIOStream *m_stream;\n\n");
+
+    fprintf(fp, "\t%s(IOStream *stream);\n\n", classname.c_str());
+    fprintf(fp, "\n};\n\n");
+
+    fprintf(fp,"extern \"C\" {\n");
+
+    for (size_t i = 0; i < size(); i++) {
+        fprintf(fp, "\t");
+        at(i).print(fp, false, "_enc", /* classname + "::" */"", "void *self");
+        fprintf(fp, ";\n");
+    }
+    fprintf(fp, "};\n");
+    fprintf(fp, "#endif");
+
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genEncoderImpl(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+    fprintf(fp, "\n\n#include <string.h>\n");
+    fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+    fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
+    fprintf(fp, "#include <stdio.h>\n");
+    std::string classname = m_basename + "_encoder_context_t";
+    size_t n = size();
+
+    // unsupport printout
+    fprintf(fp, "static void enc_unsupported()\n{\n\tfprintf(stderr, \"Function is unsupported\\n\");\n}\n\n");
+
+    // entry points;
+    for (size_t i = 0; i < n; i++) {
+        EntryPoint *e = &at(i);
+
+        if (e->unsupported()) continue;
+
+
+        e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
+        fprintf(fp, "{\n");
+
+        fprintf(fp, "\n\t%s *ctx = (%s *)self;\n\n",
+                classname.c_str(),
+                classname.c_str());
+
+        // size calculation ;
+        fprintf(fp, "\t size_t packetSize = ");
+
+        VarsArray & evars = e->vars();
+        size_t nvars = evars.size();
+        size_t npointers = 0;
+        for (size_t j = 0; j < nvars; j++) {
+            fprintf(fp, "%s ", j == 0 ? "" : " +");
+            if (evars[j].isPointer()) {
+                npointers++;
+
+                if (evars[j].lenExpression() == "") {
+                    fprintf(stderr, "%s: data len is undefined for '%s'\n",
+                            e->name().c_str(), evars[j].name().c_str());
+                }
+
+                if (evars[j].nullAllowed()) {
+                    fprintf(fp, "(%s != NULL ? %s : 0)",
+                            evars[j].name().c_str(),
+                            evars[j].lenExpression().c_str());
+                } else {
+                    if (evars[j].pointerDir() == Var::POINTER_IN ||
+                        evars[j].pointerDir() == Var::POINTER_INOUT) {
+                        fprintf(fp, "%s", evars[j].lenExpression().c_str());
+                    } else {
+                        fprintf(fp, "0");
+                    }
+                }
+            } else {
+                fprintf(fp, "%u", (unsigned int) evars[j].type()->bytes());
+            }
+        }
+        fprintf(fp, " %s 8 + %u * 4;\n", nvars != 0 ? "+" : "", (unsigned int) npointers);
+
+        // allocate buffer from the stream;
+        fprintf(fp, "\t unsigned char *ptr = ctx->m_stream->alloc(packetSize);\n\n");
+
+        // encode into the stream;
+        fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n",  e->name().c_str());
+        fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize;  ptr += 4;\n\n");
+
+        // out variables
+        for (size_t j = 0; j < nvars; j++) {
+            if (evars[j].isPointer()) {
+                // encode a pointer header
+                if (evars[j].nullAllowed()) {
+                    fprintf(fp, "\t*(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n",
+                            evars[j].name().c_str(), evars[j].lenExpression().c_str());
+                } else {
+                    fprintf(fp, "\t*(unsigned int *)(ptr) = %s; ptr += 4; \n",
+                            evars[j].lenExpression().c_str());
+                }
+
+                Var::PointerDir dir = evars[j].pointerDir();
+                if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
+                    if (evars[j].nullAllowed()) {
+                        fprintf(fp, "\tif (%s != NULL) ", evars[j].name().c_str());
+                    } else {
+                        fprintf(fp, "\t");
+                    }
+
+                    if (evars[j].packExpression().size() != 0) {
+                        fprintf(fp, "%s;", evars[j].packExpression().c_str());
+                    } else {
+                        fprintf(fp, "memcpy(ptr, %s, %s);",
+                                evars[j].name().c_str(),
+                                evars[j].lenExpression().c_str());
+                    }
+
+                    fprintf(fp, "ptr += %s;\n", evars[j].lenExpression().c_str());
+                }
+            } else {
+                // encode a non pointer variable
+                if (!evars[j].isVoid()) {
+                    fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
+                            evars[j].type()->name().c_str(), evars[j].name().c_str(),
+                            (uint) evars[j].type()->bytes());
+                }
+            }
+        }
+        // in variables;
+        for (size_t j = 0; j < nvars; j++) {
+            if (evars[j].isPointer()) {
+                Var::PointerDir dir = evars[j].pointerDir();
+                if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
+                    if (evars[j].nullAllowed()) {
+                        fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n",
+                                evars[j].name().c_str(),
+                                evars[j].name().c_str(),
+                                evars[j].lenExpression().c_str());
+                    } else {
+                        fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n",
+                                evars[j].name().c_str(),
+                                evars[j].lenExpression().c_str());
+                    }
+                }
+            }
+        }
+        // todo - return value for pointers
+        if (e->retval().isPointer()) {
+            fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
+                    e->name().c_str());
+            fprintf(fp, "\t return NULL;\n");
+        } else if (e->retval().type()->name() != "void") {
+            fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
+            fprintf(fp, "\tctx->m_stream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
+            fprintf(fp, "\treturn retval;\n");
+        }
+        fprintf(fp, "}\n\n");
+    }
+
+    // constructor
+    fprintf(fp, "%s::%s(IOStream *stream)\n{\n", classname.c_str(), classname.c_str());
+    fprintf(fp, "\tm_stream = stream;\n\n");
+
+    for (size_t i = 0; i < n; i++) {
+        EntryPoint *e = &at(i);
+        if (e->unsupported()) {
+            fprintf(fp, "\tset_%s((%s_%s_proc_t)(enc_unsupported));\n", e->name().c_str(), e->name().c_str(), sideString(CLIENT_SIDE));
+        } else {
+            fprintf(fp, "\tset_%s(%s_enc);\n", e->name().c_str(), e->name().c_str());
+        }
+        /**
+           if (e->unsupsported()) {
+           fprintf(fp, "\tmemcpy((void *)(&%s), (const void *)(&enc_unsupported), sizeof(%s));\n",
+           e->name().c_str(),
+           e->name().c_str());
+           } else {
+           fprintf(fp, "\t%s = %s_enc;\n", e->name().c_str(), e->name().c_str());
+           }
+        **/
+    }
+    fprintf(fp, "}\n\n");
+
+    fclose(fp);
+    return 0;
+}
+
+
+int ApiGen::genDecoderHeader(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+    std::string classname = m_basename + "_decoder_context_t";
+
+    fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+    fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+    fprintf(fp, "#include \"IOStream.h\" \n");
+    fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
+
+    for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
+        fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
+    }
+    fprintf(fp, "\n");
+
+    fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+            classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
+    fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream);\n");
+    fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
+    fprintf(fp, "\n};\n\n");
+    fprintf(fp, "#endif");
+
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::genDecoderImpl(const std::string &filename)
+{
+    FILE *fp = fopen(filename.c_str(), "wt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+
+    printHeader(fp);
+
+    std::string classname = m_basename + "_decoder_context_t";
+
+    size_t n = size();
+
+    fprintf(fp, "\n\n#include <string.h>\n");
+    fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+    fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
+    fprintf(fp, "#include <stdio.h>\n");
+
+    // init function;
+    fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str());
+    fprintf(fp, "\tvoid *ptr;\n\n");
+    for (size_t i = 0; i < n; i++) {
+        EntryPoint *e = &at(i);
+        fprintf(fp, "\tptr = getProc(\"%s\", userData); set_%s((%s_%s_proc_t)ptr);\n",
+                e->name().c_str(),
+                e->name().c_str(),
+                e->name().c_str(),
+                sideString(SERVER_SIDE));
+
+    }
+    fprintf(fp, "\treturn 0;\n");
+    fprintf(fp, "}\n\n");
+
+    // decoder switch;
+    fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
+    fprintf(fp,
+            "                           \n\
+\tsize_t pos = 0;\n\
+\tif (len < 8) return pos; \n\
+\tunsigned char *ptr = (unsigned char *)buf;\n\
+\tbool unknownOpcode = false;  \n\
+\twhile ((len - pos >= 8) && !unknownOpcode) {   \n\
+\t\tvoid *params[%u]; \n\
+\t\tint opcode = *(int *)ptr;   \n\
+\t\tunsigned int packetLen = *(int *)(ptr + 4);\n\
+\t\tif (len - pos < packetLen)  return pos; \n\
+\t\tswitch(opcode) {\n",
+            (uint) m_maxEntryPointsParams);
+
+    for (size_t f = 0; f < n; f++) {
+        enum Pass_t { PASS_TmpBuffAlloc = 0, PASS_MemAlloc, PASS_DebugPrint, PASS_FunctionCall, PASS_Epilog, PASS_LAST };
+        EntryPoint *e = &at(f);
+
+        // construct a printout string;
+        std::string printString = "";
+        for (size_t i = 0; i < e->vars().size(); i++) {
+            Var *v = &e->vars()[i];
+            if (!v->isVoid())  printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
+        }
+        printString += "";
+        // TODO - add for return value;
+
+        fprintf(fp, "\t\t\tcase OP_%s:\n", e->name().c_str());
+        fprintf(fp, "\t\t\t{\n");
+
+        bool totalTmpBuffExist = false;
+        std::string totalTmpBuffOffset = "0";
+        std::string *tmpBufOffset = new std::string[e->vars().size()];
+
+        // construct retval type string
+        std::string retvalType;
+        if (!e->retval().isVoid()) {
+            retvalType = e->retval().type()->name();
+            if (e->retval().isPointer()) retvalType += "*";
+        }
+
+        for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) {
+            if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) {
+                fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
+                        totalTmpBuffOffset.c_str());
+            }
+
+
+            if (pass == PASS_FunctionCall) {
+                fprintf(fp, "\t\t\tthis->%s(", e->name().c_str());
+                if (e->customDecoder()) {
+                    fprintf(fp, "this"); // add a context to the call
+                }
+            } else if (pass == PASS_DebugPrint) {
+                fprintf(fp, "#ifdef DEBUG_PRINTOUT\n");
+                fprintf(fp, "\t\t\tfprintf(stderr,\"%s(%s)\\n\"", e->name().c_str(), printString.c_str());
+                if (e->vars().size() > 0 && !e->vars()[0].isVoid()) fprintf(fp, ",");
+            }
+
+            std::string varoffset = "8"; // skip the header
+            VarsArray & evars = e->vars();
+            // allocate memory for out pointers;
+            for (size_t j = 0; j < evars.size(); j++) {
+                Var *v = & evars[j];
+                if (!v->isVoid()) {
+                    if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) fprintf(fp, ", ");
+                    if (pass == PASS_DebugPrint && j != 0) fprintf(fp, ", ");
+
+                    if (!v->isPointer()) {
+                        if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) {
+                            fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str());
+                        }
+                        varoffset += " + " + toString(v->type()->bytes());
+                    } else {
+                        if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) {
+                            if (pass == PASS_MemAlloc && v->pointerDir() == Var::POINTER_INOUT) {
+                                fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
+                                        (uint) j, varoffset.c_str());
+                                fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
+                                        (uint) j, varoffset.c_str());
+                            }
+                            if (pass == PASS_FunctionCall) {
+                                fprintf(fp, "(%s *)(ptr + %s + 4)",
+                                        v->type()->name().c_str(), varoffset.c_str());
+                            } else if (pass == PASS_DebugPrint) {
+                                fprintf(fp, "(%s *)(ptr + %s + 4), *(unsigned int *)(ptr + %s)",
+                                        v->type()->name().c_str(), varoffset.c_str(),
+                                        varoffset.c_str());
+                            }
+                            varoffset += " + 4 + *(size_t *)(ptr +" + varoffset + ")";
+                        } else { // in pointer;
+                            if (pass == PASS_TmpBuffAlloc) {
+                                fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
+                                        (uint) j, varoffset.c_str());
+                                if (!totalTmpBuffExist)
+                                    fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (uint)j);
+                                else
+                                    fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (uint)j);
+                                tmpBufOffset[j] = totalTmpBuffOffset;
+                                char tmpPtrName[16];
+                                sprintf(tmpPtrName,"tmpPtr%u", (uint)j);
+                                totalTmpBuffOffset += std::string(tmpPtrName);
+                                totalTmpBuffExist = true;
+                            } else if (pass == PASS_MemAlloc) {
+                                fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
+                                        (uint)j, tmpBufOffset[j].c_str());
+                            } else if (pass == PASS_FunctionCall) {
+                                fprintf(fp, "(%s *)(tmpPtr%u)", v->type()->name().c_str(), (uint) j);
+                            } else if (pass == PASS_DebugPrint) {
+                                fprintf(fp, "(%s *)(tmpPtr%u), *(unsigned int *)(ptr + %s)",
+                                        v->type()->name().c_str(), (uint) j,
+                                        varoffset.c_str());
+                            }
+                            varoffset += " + 4";
+                        }
+                    }
+                }
+            }
+
+            if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n");
+            if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n");
+
+            if (pass == PASS_TmpBuffAlloc) {
+                if (!e->retval().isVoid() && !e->retval().isPointer()) {
+                    if (!totalTmpBuffExist)
+                        fprintf(fp, "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", retvalType.c_str());
+                    else
+                        fprintf(fp, "\t\t\ttotalTmpSize += sizeof(%s);\n", retvalType.c_str());
+
+                    totalTmpBuffExist = true;
+                }
+                if (totalTmpBuffExist) {
+                    fprintf(fp, "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
+                }
+            }
+
+            if (pass == PASS_Epilog) {
+                // send back out pointers data as well as retval
+                if (totalTmpBuffExist) {
+                    fprintf(fp, "\t\t\tstream->flush();\n");
+                }
+
+                fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n");
+                fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n");
+            }
+
+        } // pass;
+        fprintf(fp, "\t\t\t}\n");
+        fprintf(fp, "\t\t\tbreak;\n");
+
+        delete [] tmpBufOffset;
+    }
+    fprintf(fp, "\t\t\tdefault:\n");
+    fprintf(fp, "\t\t\t\tunknownOpcode = true;\n");
+    fprintf(fp, "\t\t} //switch\n");
+    fprintf(fp, "\t} // while\n");
+    fprintf(fp, "\treturn pos;\n");
+    fprintf(fp, "}\n");
+
+    fclose(fp);
+    return 0;
+}
+
+int ApiGen::readSpec(const std::string & filename)
+{
+    FILE *specfp = fopen(filename.c_str(), "rt");
+    if (specfp == NULL) {
+        return -1;
+    }
+
+    char line[1000];
+    unsigned int lc = 0;
+    while (fgets(line, sizeof(line), specfp) != NULL) {
+        lc++;
+        EntryPoint ref;
+        if (ref.parse(lc, std::string(line))) {
+            push_back(ref);
+            updateMaxEntryPointsParams(ref.vars().size());
+        }
+    }
+    fclose(specfp);
+    return 0;
+}
+
+int ApiGen::readAttributes(const std::string & attribFilename)
+{
+    enum { ST_NAME, ST_ATT } state;
+
+    FILE *fp = fopen(attribFilename.c_str(), "rt");
+    if (fp == NULL) {
+        perror(attribFilename.c_str());
+        return -1;
+    }
+    char buf[1000];
+
+    state = ST_NAME;
+    EntryPoint *currentEntry = NULL;
+    size_t lc = 0;
+    bool globalAttributes = false;
+    while (fgets(buf, sizeof(buf), fp) != NULL) {
+        lc++;
+        std::string line(buf);
+        if (line.size() == 0) continue; // could that happen?
+
+        if (line.at(0) == '#') continue; // comment
+
+        size_t first = line.find_first_not_of(" \t\n");
+        if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
+
+        line = trim(line);
+        if (line.size() == 0 || line.at(0) == '#') continue;
+
+        switch(state) {
+        case ST_NAME:
+            if (line == "GLOBAL") {
+                globalAttributes = true;
+            } else {
+                globalAttributes = false;
+                currentEntry = findEntryByName(line);
+                if (currentEntry == NULL) {
+                    fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
+                }
+            }
+            state = ST_ATT;
+            break;
+        case ST_ATT:
+            if (globalAttributes) {
+                setGlobalAttribute(line, lc);
+            } else  if (currentEntry != NULL) {
+                currentEntry->setAttribute(line, lc);
+            }
+            break;
+        }
+    }
+    return 0;
+}
+
+
+int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
+{
+    size_t pos = 0;
+    size_t last;
+    std::string token = getNextToken(line, pos, &last, WHITESPACE);
+    pos = last;
+
+    if (token == "base_opcode") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        if (str.size() == 0) {
+            fprintf(stderr, "line %u: missing value for base_opcode\n", (uint) lc);
+        } else {
+            setBaseOpcode(atoi(str.c_str()));
+        }
+    } else  if (token == "encoder_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            encoderHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    } else if (token == "client_context_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            clientContextHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    } else if (token == "server_context_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            serverContextHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    } else if (token == "decoder_headers") {
+        std::string str = getNextToken(line, pos, &last, WHITESPACE);
+        pos = last;
+        while (str.size() != 0) {
+            decoderHeaders().push_back(str);
+            str = getNextToken(line, pos, &last, WHITESPACE);
+            pos = last;
+        }
+    }
+    else {
+        fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
+    }
+
+    return 0;
+}
+
diff --git a/tools/emulator/opengl/host/tools/emugen/ApiGen.h b/tools/emulator/opengl/host/tools/emugen/ApiGen.h
new file mode 100644
index 0000000..3c7fd27
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/ApiGen.h
@@ -0,0 +1,78 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __API_GEN_H_
+#define __API_GEN_H_
+
+#include <vector>
+#include <string.h>
+#include "EntryPoint.h"
+
+
+class ApiGen : public std::vector<EntryPoint> {
+
+public:
+    typedef std::vector<std::string> StringVec;
+    typedef enum { CLIENT_SIDE, SERVER_SIDE } SideType;
+
+    ApiGen(const std::string & basename) :
+        m_basename(basename),
+        m_maxEntryPointsParams(0),
+        m_baseOpcode(0)
+    { }
+    virtual ~ApiGen() {}
+    int readSpec(const std::string & filename);
+    int readAttributes(const std::string & attribFilename);
+    size_t maxEntryPointsParams() {  return m_maxEntryPointsParams; }
+    void updateMaxEntryPointsParams(size_t val) {
+        if (m_maxEntryPointsParams == 0 || val > m_maxEntryPointsParams) m_maxEntryPointsParams = val;
+    }
+    int baseOpcode() { return m_baseOpcode; }
+    void setBaseOpcode(int base) { m_baseOpcode = base; }
+
+    const char *sideString(SideType side) { return (side == CLIENT_SIDE) ? "client" : "server"; }
+
+    StringVec & clientContextHeaders() { return m_clientContextHeaders; }
+    StringVec & encoderHeaders() { return m_encoderHeaders; }
+    StringVec & serverContextHeaders() { return m_serverContextHeaders; }
+    StringVec & decoderHeaders() { return m_decoderHeaders; }
+
+    EntryPoint * findEntryByName(const std::string & name);
+    int genOpcodes(const std::string &filename);
+    int genAttributesTemplate(const std::string &filename);
+    int genProcTypes(const std::string &filename, SideType side);
+
+    int genContext(const std::string &filename, SideType side);
+    int genClientEntryPoints(const std::string &filename);
+
+    int genEncoderHeader(const std::string &filename);
+    int genEncoderImpl(const std::string &filename);
+
+    int genDecoderHeader(const std::string &filename);
+    int genDecoderImpl(const std::string &filename);
+
+protected:
+    virtual void printHeader(FILE *fp) const;
+    std::string m_basename;
+    StringVec m_clientContextHeaders;
+    StringVec m_encoderHeaders;
+    StringVec m_serverContextHeaders;
+    StringVec m_decoderHeaders;
+    size_t m_maxEntryPointsParams; // record the maximum number of parameters in the entry points;
+    int m_baseOpcode;
+    int setGlobalAttribute(const std::string & line, size_t lc);
+};
+
+#endif
diff --git a/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
new file mode 100644
index 0000000..d9b5499
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/EntryPoint.cpp
@@ -0,0 +1,335 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdio.h>
+#include "EntryPoint.h"
+#include <string>
+#include "TypeFactory.h"
+#include "strUtils.h"
+#include <sstream>
+
+
+EntryPoint::EntryPoint()
+{
+    reset();
+}
+
+EntryPoint::~EntryPoint()
+{
+}
+
+void EntryPoint::reset()
+{
+    m_unsupported = false;
+    m_customDecoder = false;
+    m_vars.empty();
+}
+
+bool parseTypeField(const std::string & f, std::string *vartype, bool *pointer_type, std::string *varname)
+{
+    size_t pos = 0, last;
+    bool done = false;
+
+
+    *vartype = "";
+    if (varname != NULL) *varname = "";
+    *pointer_type = false;
+
+    enum { ST_TYPE, ST_NAME, ST_END } state = ST_TYPE;
+
+    while(!done) {
+
+        std::string str = getNextToken(f, pos, &last, WHITESPACE);
+        if (str.size() == 0) break;
+
+        switch(state) {
+        case ST_TYPE:
+            if (str == "const") {
+                pos = last;
+            } else {
+                // must be a type name;
+                *vartype = str;
+                // do we have an astriks at the end of the name?
+                if (vartype->at(vartype->size() - 1) == '*') {
+                    *pointer_type = true;
+                    // remove the astriks
+                    (*vartype)[vartype->size() - 1] = ' ';
+                    *vartype = trim(*vartype);
+                }
+                state = ST_NAME;
+                pos = last;
+            }
+            break;
+        case ST_NAME:
+            if (str.size() == 0) {
+                done = true;
+            } else if (str == "*") {
+                *pointer_type = true;
+                // remove the leading astriks;
+                pos = last;
+            } else if (varname == NULL) {
+                done = true;
+            } else {
+                if (str[0] == '*') {
+                    *pointer_type = true;
+                    str[0] = ' ';
+                    str = trim(str);
+                }
+                *varname = str;
+                done = true;
+            }
+            break;
+        case ST_END:
+            break;
+        }
+    }
+    return true;
+}
+
+// return true for valid line (need to get into the entry points list)
+bool EntryPoint::parse(unsigned int lc, const std::string & str)
+{
+    size_t pos, last;
+    std::string field;
+
+    reset();
+    std::string linestr = trim(str);
+
+    if (linestr.size() == 0) return false;
+    if (linestr.at(0) == '#') return false;
+
+    // skip PREFIX
+    field = getNextToken(linestr, 0, &last, "(");
+    pos = last + 1;
+    // return type
+    field = getNextToken(linestr, pos, &last, ",)");
+    std::string retTypeName;
+    bool pointer_type;
+    if (!parseTypeField(field, &retTypeName, &pointer_type, NULL)) {
+        fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
+        return false;
+    }
+    pos = last + 1;
+    const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName);
+    if (theType->name() == "UNKNOWN") {
+        fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
+    }
+
+    m_retval.init(std::string(""), theType, pointer_type, std::string(""), Var::POINTER_OUT, std::string(""));
+
+    // function name
+    m_name = getNextToken(linestr, pos, &last, ",)");
+    pos = last + 1;
+
+    // parameters;
+    int nvars = 0;
+    while (pos < linestr.size() - 1) {
+        field = getNextToken(linestr, pos, &last, ",)");
+        std::string vartype, varname;
+        if (!parseTypeField(field, &vartype, &pointer_type, &varname)) {
+            fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
+            return false;
+        }
+        nvars++;
+        const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype);
+        if (v->id() == 0) {
+            fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str());
+        } else {
+            if (varname == "" &&
+                !(v->name() == "void" && !pointer_type)) {
+                std::ostringstream oss;
+                oss << "var" << nvars;
+                varname = oss.str();
+            }
+
+            m_vars.push_back(Var(varname, v, pointer_type, std::string(""), Var::POINTER_IN, ""));
+        }
+        pos = last + 1;
+    }
+    return true;
+}
+
+void EntryPoint::print(FILE *fp, bool newline,
+                       const std::string & name_suffix,
+                       const std::string & name_prefix,
+                       const std::string & ctx_param ) const
+{
+    fprintf(fp, "%s%s %s%s%s(",
+            m_retval.type()->name().c_str(),
+            m_retval.isPointer() ? "*" : "",
+            name_prefix.c_str(),
+            m_name.c_str(),
+            name_suffix.c_str());
+
+    if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str());
+
+    for (size_t i = 0; i < m_vars.size(); i++) {
+        if (m_vars[i].isVoid()) continue;
+        if (i != 0 || ctx_param != "") fprintf(fp, ", ");
+        fprintf(fp, "%s %s%s", m_vars[i].type()->name().c_str(),
+                m_vars[i].isPointer() ? "*" : "",
+                m_vars[i].name().c_str());
+    }
+    fprintf(fp, ")%s", newline? "\n" : "");
+}
+
+Var * EntryPoint::var(const std::string & name)
+{
+    Var *v = NULL;
+    for (size_t i = 0; i < m_vars.size(); i++) {
+        if (m_vars[i].name() == name) {
+            v = &m_vars[i];
+            break;
+        }
+    }
+    return v;
+}
+
+bool EntryPoint::hasPointers()
+{
+    bool pointers = false;
+    if (m_retval.isPointer()) pointers = true;
+    if (!pointers) {
+        for (size_t i = 0; i < m_vars.size(); i++) {
+            if (m_vars[i].isPointer()) {
+                pointers = true;
+                break;
+            }
+        }
+    }
+    return pointers;
+}
+
+int EntryPoint::setAttribute(const std::string &line, size_t lc)
+{
+    size_t pos = 0;
+    size_t last;
+    std::string token = getNextToken(line, 0, &last, WHITESPACE);
+
+    if (token == "len") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+        if (varname.size() == 0) {
+            fprintf(stderr, "ERROR: %u: Missing variable name in 'len' attribute\n", (unsigned int)lc);
+            return -1;
+        }
+        Var * v = var(varname);
+        if (v == NULL) {
+            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+                    (unsigned int)lc, varname.c_str(), name().c_str());
+            return -2;
+        }
+        // set the size expression into var
+        pos = last;
+        v->setLenExpression(line.substr(pos));
+    } else if (token == "dir") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        if (varname.size() == 0) {
+            fprintf(stderr, "ERROR: %u: Missing variable name in 'dir' attribute\n", (unsigned int)lc);
+            return -1;
+        }
+        Var * v = var(varname);
+        if (v == NULL) {
+            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+                    (unsigned int)lc, varname.c_str(), name().c_str());
+            return -2;
+        }
+
+        pos = last;
+        std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE);
+        if (pointerDirStr.size() == 0) {
+            fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc);
+            return -3;
+        }
+
+        if (pointerDirStr == "out") {
+            v->setPointerDir(Var::POINTER_OUT);
+        } else if (pointerDirStr == "inout") {
+            v->setPointerDir(Var::POINTER_INOUT);
+        } else if (pointerDirStr == "in") {
+            v->setPointerDir(Var::POINTER_IN);
+        } else {
+            fprintf(stderr, "ERROR: %u: unknow pointer direction %s\n", (unsigned int)lc, pointerDirStr.c_str());
+        }
+    } else if (token == "var_flag") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+        if (varname.size() == 0) {
+            fprintf(stderr, "ERROR: %u: Missing variable name in 'var_flag' attribute\n", (unsigned int)lc);
+            return -1;
+        }
+        Var * v = var(varname);
+        if (v == NULL) {
+            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+                    (unsigned int)lc, varname.c_str(), name().c_str());
+            return -2;
+        }
+        pos = last;
+        std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+        if (flag.size() == 0) {
+            fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+            return -3;
+        }
+
+        if (flag == "nullAllowed") {
+            if (v->isPointer()) {
+                v->setNullAllowed(true);
+            } else {
+                fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
+                        (unsigned int) lc, v->name().c_str());
+            }
+        } else {
+            fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+        }
+    } else if (token == "custom_pack") {
+        pos = last;
+        std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+        if (varname.size() == 0) {
+            fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_pack' attribute\n", (unsigned int)lc);
+            return -1;
+        }
+        Var * v = var(varname);
+        if (v == NULL) {
+            fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+                    (unsigned int)lc, varname.c_str(), name().c_str());
+            return -2;
+        }
+        // set the size expression into var
+        pos = last;
+        v->setPackExpression(line.substr(pos));
+    } else if (token == "flag") {
+        pos = last;
+        std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+        if (flag.size() == 0) {
+            fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+            return -4;
+        }
+
+        if (flag == "unsupported") {
+            setUnsupported(true);
+        } else if (flag == "custom_decoder") {
+            setCustomDecoder(true);
+        } else {
+            fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str());
+        }
+    } else {
+        fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str());
+    }
+
+    return 0;
+}
diff --git a/tools/emulator/opengl/host/tools/emugen/EntryPoint.h b/tools/emulator/opengl/host/tools/emugen/EntryPoint.h
new file mode 100644
index 0000000..c417bda
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/EntryPoint.h
@@ -0,0 +1,64 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __EntryPoint__H__
+#define __EntryPoint__H__
+
+#include <string>
+#include <vector>
+#include <stdio.h>
+
+#include "Var.h"
+
+//---------------------------------------------------
+
+typedef std::vector<Var> VarsArray;
+
+class EntryPoint {
+public:
+    EntryPoint();
+    virtual ~EntryPoint();
+    bool parse(unsigned int lc, const std::string & str);
+    void reset(); // reset the class to empty;
+    void print(FILE *fp = stdout, bool newline = true,
+               const std::string & name_suffix = std::string(""),
+               const std::string & name_prefix = std::string(""),
+               const std::string & ctx_param = std::string("")) const;
+    const std::string & name() const { return m_name; }
+    VarsArray & vars() { return m_vars; }
+    Var & retval() { return m_retval; }
+    Var * var(const std::string & name);
+    bool hasPointers();
+    bool unsupported() const { return m_unsupported; }
+    void setUnsupported(bool state) { m_unsupported = state; }
+    bool customDecoder() { return m_customDecoder; }
+    void setCustomDecoder(bool state) { m_customDecoder = state; }
+    int setAttribute(const std::string &line, size_t lc);
+
+private:
+    enum { PR_RETVAL = 0, PR_NAME, PR_VARS, PR_DONE } prState;
+    std::string m_name;
+    Var m_retval;
+    VarsArray m_vars;
+    bool m_unsupported;
+    bool m_customDecoder;
+
+    void err(unsigned int lc, const char *msg) {
+        fprintf(stderr, "line %d: %s\n", lc, msg);
+    }
+};
+
+
+#endif
diff --git a/tools/emulator/opengl/host/tools/emugen/README b/tools/emulator/opengl/host/tools/emugen/README
new file mode 100644
index 0000000..18c3edb
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/README
@@ -0,0 +1,292 @@
+Introduction:
+
+The emugen tool is a tool to generate a wire protocol implementation
+based on provided API.  The tool generates c++ encoder code that takes
+API calls and encodes them into the wire and decoder code that decodes
+the wire stream and calls server matching API.
+
+The following paragraphs includes the following:
+    * Wire Protocol Description
+    * Input files description & format
+    * Generated code description.
+
+
+Note: In this document, the caller is referred to as Encoder or Client
+and the callee is referred to as the Decoder or Server. These terms
+are used interchangeably by the context.
+
+
+
+Wire Protocol packet structure:
+
+A general Encoder->Decoder packet is structured as following:
+struct Packet {
+	unsigned int opcode;
+	unsigned int packet_len;
+	… parameter 1
+	… parameter 2
+};
+A general Decoder->Encoder reply is expected to be received in the
+context of the ‘call’ that triggered it, thus it includes the reply
+data only, with no context headers. In precise term terms, a reply
+packet will look like:
+
+struct {
+	...// reply data
+};
+
+consider the following function call:
+int foo(int p1, short s1)
+will be encoded into :
+{
+	101, // foo opcode
+	14, // sizeof(opcode) + sizeof(packet_len) + sizeof(int) + sizeof(short)
+	p1, // 4 bytes
+	s1 // 4 bytes
+}
+
+Since ‘foo’ returns value, the caller is expected to read back the return packet from the server->client stream. The return value in this example is in thus the return packet is:
+{
+	int retval;
+}
+
+
+Pointer decoding:
+
+The wire protocol also allows exchanging of pointer data
+(arrays). Pointers are defined with directions:
+
+	in : Data is sent from the caller to the calle
+	out: Data is sent from the callee to the caller
+	in_out: data is sent from the caller and return in place.
+
+‘in’ and ‘in_out’ encoded with their len:
+{
+	unsinged int pointer_data_len;
+	unsigned char data[pointer_data_len];… // pointer data
+}
+
+‘out’ pointers are encoded by data length only:
+{
+unsigned int pointer_data_len;
+}
+
+‘out’ and ‘in_out’ pointer’s data is returned in the return
+packet. For example, consider the following call:
+
+int foo(int n, int *ptr); // assume that ‘data’ is in_out pointer which contains ‘n’ ints
+
+The caller packet will have the following form:
+{
+	101, // foo opcode
+	xx, sizeof(opcode) + sizeof(datalen) + sizeof(int) + sizeof(unsigned int) + n * sizeof(int);
+	n, // the n parameter
+	n * sizeof(int), // size of the data in ptr
+	… // n* sizeof(int) bytes
+}
+
+The return packet is;
+{
+	…. // n * sizeof(int) bytes of data return in ptr
+	retval // sizeof(int) - the return value of the function;
+}
+
+Endianess
+
+The Wire protocol is designed to impose minimum overhead on the client
+side. Thus, the data endianness that is sent across the wire is
+determined by the ‘client’ side. It is up to the server side to
+determine the client endianess and marshal the packets as required.
+
+
+
+Emugen input files - protocol specification
+
+The protocol generated by emugen consists of two input files:
+
+1. basename.in - A sepcification of the protocol RPC procedures. This
+part of the specification is expected to be generated automatically
+from c/c++ header files or similar.
+
+‘basename’ is the basename for the protocol and will be used to prefix
+the files that are generated for this protocol.  A line in the .in
+file has the following format:
+
+[prefix](retvalType, FuncName, <param type> [param name],...)
+where 
+	retvalType - The function return value type
+	FuncName - function name
+	<param type> mandatory parameter type
+	[param name] - optional parameter name
+Examples:
+GL_ENTRY(void, glVertex1f, float v) 
+XXX(int *, foo, int n, float, short)
+XXX(void, glFlush, void)
+
+Note: Empty lines in the file are ignored. A line starts with # is a comment
+
+2. basename.attrib - Attributes information of the API. 
+This file includes additional flags, pointers datalen information and
+global attributes of the protocol. For uptodate format of the file,
+please refer to the specification file in the project source
+tree. The format of the .attrib file is described below.
+
+3. basename.types - Types information
+
+This files describes the types that are described by the API. A type
+is defined as follows:
+<type name> <size in bits> <print format string>
+where:
+<type name> is the name of the type as described in the API
+<size in bits> 0, 8, 16, 32 sizes are accepted
+<print format string> a string to format the value of the type, as acceted by printf(3)
+
+example:
+GLint 32 %d
+
+Encoder generated code files 
+
+In order to generate the encoder files, one should run the ‘emugen’
+tool as follows:
+
+emugen -i <input directory> -E <encoder files output directory> <basename>
+where:
+	<input directory> containes the api specification files  (basename.in + basename.attrib)
+	<encoder directory> - a directory name to generate the encoder output files
+	basename - The basename for the api.
+
+Assuming the basename is ‘api’, The following files are generated:
+
+api_opcodes.h - defines the protocol opcodes. The first opcode value
+is 0, unless defined otherwise in the .attrib file
+
+api_entry.cpp - defines entry points for the functions that are
+defined by the protocol. this File also includes a function call
+‘setContextAccessor(void *(*f)()). This function should be used to
+provide a callback function that is used by the functions to access
+the encoder context. For example, such callback could fetch the
+context from a Thread Local Storage (TLS) location.
+
+api_client_proc.h - type defintions for the protocol procedures. 
+
+api_client_context.h - defines the client side dispatch table data
+structure that stores the encoding functions. This data structure also
+includes ‘accessors’ methods such that library user can override
+default entries for special case handling.
+
+api_enc.h - This header file defines the encoder data strcuture. The
+encoder data structure inherits its functionality from the
+‘client_context’ class above and adds encoding and streaming
+functionality.
+
+api_enc.cpp - Encoder implementation. 
+
+5.1.2.2 Decoder generated files
+In order to generate the decoder files, one should run the ‘emugen’
+tool as follows:
+emugen -i <input directory> -D <decoder files output directory> basename
+where:
+	<input directory> containes the api specification files  (basename.in + basename.attrib)
+	<decoder directory> - a directory name to generate the decoder output files
+	basename - The basename for the api.
+
+With resepct to the example above, Emugen will generate the following
+files:
+
+api_opcodes.h - Protocol opcodes
+
+api_server_proc.h - type definitions for the server side procedures
+
+api_server_context.h - dispatch table the encoder functions
+
+api_dec.h - Decoder header file
+
+api_dec.cpp - Decoder implementation. In addtion, this file includes
+an intiailization function that uses a user provided callback to
+initialize the API server implementation. An example for such
+initialization is loading a set of functions from a shared library
+module.
+
+.attrib file format description:
+
+The .attrib file is an input file to emugen and is used to provide
+ additional information that is required for the code generation.
+The file format is as follows:
+
+a line that starts with # is ignored (comment)
+a empty line just whitespace of (" " "\t" "\n") is ignored.
+
+The file is divided into 'sections', each describes a specific API
+function call. A section starts with the name of the function in
+column 0.
+
+A section that starts with the reserved word 'GLOBAL' provides global
+attributes.
+
+below are few sections examples:
+
+GLOBAL
+  encoder_headers string.h kuku.h
+
+glVertex3fv
+	len data (size)
+glTexImage2D
+       len pixels (pixels == NULL? 0 : (format_pixel_size(internalformat) * width * height * type_size(type)))
+
+
+Global section flags description:
+
+base_opcode
+    set the base opcode value for this api
+    format: base_opcode 100
+
+encoder_headers
+    a list of headers that will be included in the encoder header file
+    format: encoder_headers <stdio.h> "kuku.h"
+
+client_context_headers
+    a list of headers that will be included in the client context header file
+    format: client_context_headers <stdio.h> "kuku.h"
+
+decoder_headers
+    a list of headers that will be included in the decoder header file
+    format: decoder_headers <stdio.h> "kuku.h"
+
+server_context_headers
+    a list of headers that will be included in the server context header file
+    format: server_context_headers <stdio.h> "kuku.h"
+
+
+Entry point flags description:
+
+ len
+	desciption : provide an expression to calcualte an expression data len
+	format: len <var name> <c expression that calcluates the data len>
+
+custom_pack
+	description: provide an expression to pack data into the stream.
+	format: custom_pack <var name> <c++ expression that pack data from var into the stream>
+	The stream is represented by a (unsigned char *)ptr. The expression may also refer
+	to other function parameters. In addition, the expression may refer to 'void *self' which
+	is the encoding context as provided by the caller.
+
+ dir
+	description : set a pointer direction (in - for data that goes
+	to the codec, out from data that returns from the codec.
+     	format: dir <varname> <[in | out | inout]>
+
+ var_flag 
+ 	 description : set variable flags
+ 	 format: var_flag <varname> < nullAllowed | ... >
+
+ flag
+	description: set entry point flag; 
+	format: flag < unsupported | ... >
+	supported flags are:
+	unsupported - The encoder side implementation is pointed to "unsuppored reporting function". 
+	custom_decoder - The decoder is expected to be provided with
+		       	 custom implementation. The call to the
+		       	 deocder function includes a pointer to the
+		       	 context
+
+
diff --git a/tools/emulator/opengl/host/tools/emugen/TypeFactory.cpp b/tools/emulator/opengl/host/tools/emugen/TypeFactory.cpp
new file mode 100644
index 0000000..709807e
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/TypeFactory.cpp
@@ -0,0 +1,135 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "TypeFactory.h"
+#include "VarType.h"
+#include <string>
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+
+
+TypeFactory * TypeFactory::m_instance = NULL;
+
+static Var0 g_var0;
+static Var8 g_var8;
+static Var16 g_var16;
+static Var32 g_var32;
+
+typedef std::map<std::string, VarType> TypeMap;
+static  TypeMap g_varMap;
+static bool g_initialized = false;
+static int g_typeId = 0;
+
+
+static VarConverter * getVarConverter(int size)
+{
+    VarConverter *v = NULL;
+
+    switch(size) {
+    case 0: v =  &g_var0; break;
+    case 8: v =  &g_var8; break;
+    case 16:    v =  &g_var16; break;
+    case 32:    v =  &g_var32; break;
+    }
+    return v;
+}
+
+#define ADD_TYPE(name, size, printformat)                                           \
+    g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, &g_var##size,printformat)));
+
+void TypeFactory::initBaseTypes()
+{
+    g_initialized = true;
+    ADD_TYPE("UNKNOWN", 0, "0x%x");
+    ADD_TYPE("void", 0, "0x%x");
+    ADD_TYPE("char", 8, "%c");
+    ADD_TYPE("int", 32, "%d");
+    ADD_TYPE("float", 32, "%d");
+    ADD_TYPE("short", 16, "%d");
+}
+
+int TypeFactory::initFromFile(const std::string &filename)
+{
+    if (!g_initialized) {
+        initBaseTypes();
+    }
+
+    FILE *fp = fopen(filename.c_str(), "rt");
+    if (fp == NULL) {
+        perror(filename.c_str());
+        return -1;
+    }
+    char line[1000];
+    int lc = 0;
+    while(fgets(line, sizeof(line), fp) != NULL) {
+        lc++;
+        std::string str = trim(line);
+        if (str.size() == 0 || str.at(0) == '#') {
+            continue;
+        }
+        size_t pos = 0, last;
+        std::string name;
+        name = getNextToken(str, pos, &last, WHITESPACE);
+        if (name.size() == 0) {
+            fprintf(stderr, "Error: %d : missing type name\n", lc);
+            return -2;
+        }
+        pos = last + 1;
+        std::string size;
+        size = getNextToken(str, pos, &last, WHITESPACE);
+        if (size.size() == 0) {
+            fprintf(stderr, "Error: %d : missing type width\n", lc);
+            return -2;
+        }
+        pos = last + 1;
+        std::string printString;
+        printString = getNextToken(str, pos, &last, WHITESPACE);
+        if (printString.size() == 0) {
+            fprintf(stderr, "Error: %d : missing print-string\n", lc);
+            return -2;
+        }
+
+        VarConverter *v = getVarConverter(atoi(size.c_str()));
+        if (v == NULL) {
+            fprintf(stderr, "Error: %d : unknown var width: %d\n", lc, atoi(size.c_str()));
+            return -1;
+        }
+
+        if (getVarTypeByName(name)->id() != 0) {
+            fprintf(stderr,
+                    "Warining: %d : type %s is already known, definition in line %d is taken\n",
+                    lc, name.c_str(), lc);
+        }
+        g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, v ,printString)));
+    }
+    g_initialized = true;
+    return 0;
+}
+
+
+const VarType * TypeFactory::getVarTypeByName(const std::string & type)
+{
+    if (!g_initialized) {
+        initBaseTypes();
+    }
+    TypeMap::iterator i = g_varMap.find(type);
+    if (i == g_varMap.end()) {
+        i = g_varMap.find("UNKNOWN");
+    }
+    return &(i->second);
+}
+
diff --git a/tools/emulator/opengl/host/tools/emugen/TypeFactory.h b/tools/emulator/opengl/host/tools/emugen/TypeFactory.h
new file mode 100644
index 0000000..deee2ca
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/TypeFactory.h
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __TYPE__FACTORY__H__
+#define __TYPE__FACTORY__H__
+
+#include <string>
+#include "VarType.h"
+
+class TypeFactory {
+public:
+    static TypeFactory *instance() {
+        if (m_instance == NULL) {
+            m_instance = new TypeFactory;
+        }
+        return m_instance;
+    }
+    const VarType * getVarTypeByName(const std::string &type);
+    int  initFromFile(const std::string &filename);
+private:
+    static TypeFactory *m_instance;
+    void initBaseTypes();
+    TypeFactory() {}
+};
+#endif
diff --git a/tools/emulator/opengl/host/tools/emugen/Var.h b/tools/emulator/opengl/host/tools/emugen/Var.h
new file mode 100644
index 0000000..ef9f7c2
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/Var.h
@@ -0,0 +1,94 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __VAR__H__
+#define __VAR__H__
+
+#include "VarType.h"
+#include <string>
+#include <stdio.h>
+
+class Var {
+public:
+    // pointer data direction - from the client point of view.
+    typedef enum { POINTER_OUT = 0x1, POINTER_IN = 0x2, POINTER_INOUT = 0x3 } PointerDir;
+    Var() :
+        m_name(""),
+        m_type(NULL),
+        m_pointer(false),
+        m_lenExpression(""),
+        m_pointerDir(POINTER_IN),
+        m_nullAllowed(false),
+        m_packExpression("")
+
+    {
+    }
+
+    Var(const std::string & name,
+        const VarType * vartype,
+        bool isPointer,
+        const std::string & lenExpression,
+        PointerDir dir,
+        const std::string &packExpression) :
+        m_name(name),
+        m_type(const_cast<VarType *>(vartype)),
+        m_pointer(isPointer),
+        m_lenExpression(lenExpression),
+        m_pointerDir(dir),
+        m_nullAllowed(false),
+        m_packExpression(packExpression)
+    {
+    }
+
+    void init(const std::string name, const VarType * vartype,
+              bool isPointer, std::string lenExpression,
+              PointerDir dir, std::string packExpression) {
+        m_name = name;
+        m_type = vartype;
+        m_pointer = isPointer;
+        m_lenExpression = lenExpression;
+        m_packExpression = packExpression;
+        m_pointerDir = dir;
+        m_nullAllowed = false;
+
+    }
+
+    const std::string & name() const { return m_name; }
+    const VarType * type() const { return m_type; }
+    bool isPointer() const { return m_pointer; }
+    bool isVoid() const { return ((m_type->bytes() == 0) && (m_pointer == false)); }
+    const std::string & lenExpression() const { return m_lenExpression; }
+    const std::string & packExpression() const { return(m_packExpression); }
+    void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
+    void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
+    void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
+    PointerDir pointerDir() { return m_pointerDir; }
+    void setNullAllowed(bool state) { m_nullAllowed = state; }
+    bool nullAllowed() const { return m_nullAllowed; }
+    void printType(FILE *fp) { fprintf(fp, "%s%s", m_type->name().c_str(), m_pointer ? "*" : ""); }
+    void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
+
+private:
+    std::string m_name;
+    const VarType * m_type;
+    bool m_pointer; // is this variable a pointer;
+    std::string m_lenExpression; // an expression to calcualte a pointer data size
+    PointerDir m_pointerDir;
+    bool m_nullAllowed;
+    std::string m_packExpression; // an expression to pack data into the stream
+
+};
+
+#endif
diff --git a/tools/emulator/opengl/host/tools/emugen/VarType.h b/tools/emulator/opengl/host/tools/emugen/VarType.h
new file mode 100644
index 0000000..a0718bb
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/VarType.h
@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __VARTYPE__H__
+#define __VARTYPE__H__
+
+#include <string>
+
+class VarConverter {
+public:
+    VarConverter(size_t bytes) : m_bytes(bytes) {}
+    size_t bytes() const { return m_bytes; }
+private:
+    size_t m_bytes;
+};
+
+class Var8 : public VarConverter {
+public:
+    Var8() : VarConverter(1) {}
+};
+
+class Var16 : public VarConverter {
+public:
+    Var16() : VarConverter(2) {}
+};
+
+class Var32 : public VarConverter {
+public:
+    Var32() : VarConverter(4) {}
+};
+
+class Var0 : public VarConverter {
+public:
+    Var0() : VarConverter(0) {}
+};
+
+
+class VarType {
+public:
+    VarType() :
+        m_id(0), m_name("default_constructed"), m_converter(NULL), m_printFomrat("0x%x")
+    {
+    }
+
+    VarType(size_t id, const std::string & name, const VarConverter * converter, const std::string & printFormat ) :
+        m_id(id), m_name(name), m_converter(const_cast<VarConverter *>(converter)), m_printFomrat(printFormat)
+    {
+    }
+
+    ~VarType()
+    {
+    }
+    const std::string & name() const { return m_name; }
+    const std::string & printFormat() const { return m_printFomrat; }
+    size_t bytes() const { return m_converter->bytes(); }
+    size_t id() const { return m_id; }
+private:
+    size_t m_id;
+    std::string m_name;
+    VarConverter * m_converter;
+    std::string m_printFomrat;
+};
+
+#endif
diff --git a/tools/emulator/opengl/host/tools/emugen/errors.h b/tools/emulator/opengl/host/tools/emugen/errors.h
new file mode 100644
index 0000000..d09c292
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/errors.h
@@ -0,0 +1,24 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef _ERRORS_H_
+#define _ERRORS_H_
+
+#define BAD_USAGE -1
+#define BAD_SPEC_FILE -2
+#define BAD_TYPES_FILE -3
+#define BAD_ATTRIBUTES_FILE -4
+
+#endif
diff --git a/tools/emulator/opengl/host/tools/emugen/main.cpp b/tools/emulator/opengl/host/tools/emugen/main.cpp
new file mode 100644
index 0000000..aefba0a
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/main.cpp
@@ -0,0 +1,147 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "errors.h"
+#include "EntryPoint.h"
+#include "strUtils.h"
+#include "ApiGen.h"
+#include "TypeFactory.h"
+
+const std::string SPEC_EXTENSION = std::string(".in");
+const std::string ATTRIB_EXTENSION = std::string(".attrib");
+const std::string TYPES_EXTENTION = std::string(".types");
+
+
+void usage(const char *filename)
+{
+    fprintf(stderr, "Usage: %s [options] <base name>\n", filename);
+    fprintf(stderr, "\t-h: This message\n");
+    fprintf(stderr, "\t-E <dir>: generate encoder into dir\n");
+    fprintf(stderr, "\t-D <dir>: generate decoder into dir\n");
+    fprintf(stderr, "\t-i: input dir, local directory by default\n");
+    fprintf(stderr, "\t-T : generate attribute template into the input directory\n\t\tno other files are generated\n");
+}
+
+int main(int argc, char *argv[])
+{
+    std::string encoderDir = "";
+    std::string decoderDir = "";
+    std::string inDir = ".";
+    bool generateAttributesTemplate = false;
+
+    int c;
+    while((c = getopt(argc, argv, "TE:D:i:h")) != -1) {
+        switch(c) {
+        case 'T':
+            generateAttributesTemplate = true;
+            break;
+        case 'h':
+            usage(argv[0]);
+            exit(0);
+            break;
+        case 'E':
+            encoderDir = std::string(optarg);
+            break;
+        case 'D':
+            decoderDir = std::string(optarg);
+            break;
+        case 'i':
+            inDir = std::string(optarg);
+            break;
+        case ':':
+            fprintf(stderr, "Missing argument !!\n");
+            // fall through
+        default:
+            usage(argv[0]);
+            exit(0);
+        }
+    }
+
+    if (optind >= argc) {
+        fprintf(stderr, "Usage: %s [options] <base name> \n", argv[0]);
+        return BAD_USAGE;
+    }
+
+    if (encoderDir.size() == 0 && decoderDir.size() == 0 && generateAttributesTemplate == false) {
+        fprintf(stderr, "No output specified - aborting\n");
+        return BAD_USAGE;
+    }
+
+    std::string baseName = std::string(argv[optind]);
+    ApiGen apiEntries(baseName);
+
+    // init types;
+    std::string typesFilename = inDir + "/" + baseName + TYPES_EXTENTION;
+
+    if (TypeFactory::instance()->initFromFile(typesFilename) < 0) {
+        fprintf(stderr, "missing or error reading types file: %s...ignored\n", typesFilename.c_str());
+    }
+
+    std::string filename = inDir + "/" + baseName + SPEC_EXTENSION;
+    if (apiEntries.readSpec(filename) < 0) {
+        perror(filename.c_str());
+        return BAD_SPEC_FILE;
+    }
+
+
+    if (generateAttributesTemplate) {
+        apiEntries.genAttributesTemplate(inDir + "/" + baseName + ATTRIB_EXTENSION);
+        exit(0);
+    }
+
+    std::string attribFileName = inDir + "/" + baseName + ATTRIB_EXTENSION;
+    if (apiEntries.readAttributes(attribFileName) < 0) {
+        perror(attribFileName.c_str());
+        fprintf(stderr, "failed to parse attributes\n");
+        exit(1);
+    }
+
+    if (encoderDir.size() != 0) {
+
+        apiEntries.genOpcodes(encoderDir + "/" + baseName + "_opcodes.h");
+        apiEntries.genContext(encoderDir + "/" + baseName + "_client_context.h", ApiGen::CLIENT_SIDE);
+        apiEntries.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE);
+
+        apiEntries.genClientEntryPoints(encoderDir + "/" + baseName + "_entry.cpp");
+        apiEntries.genEncoderHeader(encoderDir + "/" + baseName + "_enc.h");
+        apiEntries.genEncoderImpl(encoderDir + "/" + baseName + "_enc.cpp");
+    }
+
+    if (decoderDir.size() != 0) {
+        //apiEntries.genEntryPoints(decoderDir + "/" + baseName + "_entry.cpp", baseName);
+        apiEntries.genOpcodes(decoderDir + "/" + baseName + "_opcodes.h");
+        apiEntries.genProcTypes(decoderDir + "/" + baseName + "_server_proc.h", ApiGen::SERVER_SIDE);
+        apiEntries.genContext(decoderDir + "/" + baseName + "_server_context.h", ApiGen::SERVER_SIDE);
+        apiEntries.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h");
+        apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp");
+        // generate the encoder type;
+
+    }
+#ifdef DEBUG_DUMP
+    int withPointers = 0;
+    printf("%d functions found\n", int(apiEntries.size()));
+    for (int i = 0; i < apiEntries.size(); i++) {
+        if (apiEntries[i].hasPointers()) {
+            withPointers++;
+            apiEntries[i].print();
+        }
+    }
+    fprintf(stdout, "%d entries has poitners\n", withPointers);
+#endif
+
+}
+
diff --git a/tools/emulator/opengl/host/tools/emugen/strUtils.cpp b/tools/emulator/opengl/host/tools/emugen/strUtils.cpp
new file mode 100644
index 0000000..357054b
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/strUtils.cpp
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "strUtils.h"
+
+using namespace std;
+
+
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim)
+{
+    if (str.size() == 0 || pos >= str.size()) return "";
+
+    pos = str.find_first_not_of(WHITESPACE, pos);
+    if (pos == std::string::npos) return "";
+
+    *last = str.find_first_of(delim, pos);
+    if (*last == std::string::npos) *last = str.size();
+    std::string retval = str.substr(pos, *last - pos);
+    retval = trim(retval);
+    return retval;
+}
+
+
+std::string trim(const string & str)
+{
+  string result;
+  string::size_type start = str.find_first_not_of(WHITESPACE, 0);
+  string::size_type end = str.find_last_not_of(WHITESPACE);
+  if (start == string::npos || end == string::npos) {
+    result = string("");
+  } else {
+    result = str.substr(start, end - start + 1);
+  }
+  return result;
+}
+
+
diff --git a/tools/emulator/opengl/host/tools/emugen/strUtils.h b/tools/emulator/opengl/host/tools/emugen/strUtils.h
new file mode 100644
index 0000000..3fa0908
--- /dev/null
+++ b/tools/emulator/opengl/host/tools/emugen/strUtils.h
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef STR_UTILS_H_
+#define STR_UTILS_H_
+
+#include <string>
+#include <sstream>
+
+#define WHITESPACE " \t\n"
+
+std::string trim(const std::string & str);
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim);
+template <class T> std::string inline toString(const T& t) {
+    std::stringstream ss;
+    ss << t;
+    return ss.str();
+
+}
+
+#endif
diff --git a/tools/emulator/system/gps/Android.mk b/tools/emulator/system/gps/Android.mk
new file mode 100644
index 0000000..41bdc64
--- /dev/null
+++ b/tools/emulator/system/gps/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# We're moving the emulator-specific platform libs to
+# development.git/tools/emulator/. The following test is to ensure
+# smooth builds even if the tree contains both versions.
+#
+ifndef BUILD_EMULATOR_GPS_MODULE
+BUILD_EMULATOR_GPS_MODULE := true
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_PRODUCT),sim)
+# HAL module implemenation, not prelinked and stored in
+# hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.so
+include $(CLEAR_VARS)
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_CFLAGS += -DQEMU_HARDWARE
+LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
+LOCAL_SRC_FILES := gps_qemu.c
+LOCAL_MODULE := gps.goldfish
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_SHARED_LIBRARY)
+endif
+
+endif # BUILD_EMULATOR_GPS_MODULE
diff --git a/tools/emulator/system/gps/gps_qemu.c b/tools/emulator/system/gps/gps_qemu.c
new file mode 100644
index 0000000..a4699d3
--- /dev/null
+++ b/tools/emulator/system/gps/gps_qemu.c
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* this implements a GPS hardware library for the Android emulator.
+ * the following code should be built as a shared library that will be
+ * placed into /system/lib/hw/gps.goldfish.so
+ *
+ * it will be loaded by the code in hardware/libhardware/hardware.c
+ * which is itself called from android_location_GpsLocationProvider.cpp
+ */
+
+
+#include <errno.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <math.h>
+#include <time.h>
+
+#define  LOG_TAG  "gps_qemu"
+#include <cutils/log.h>
+#include <cutils/sockets.h>
+#include <hardware/gps.h>
+#include <hardware/qemud.h>
+
+/* the name of the qemud-controlled socket */
+#define  QEMU_CHANNEL_NAME  "gps"
+
+#define  GPS_DEBUG  0
+
+#if GPS_DEBUG
+#  define  D(...)   LOGD(__VA_ARGS__)
+#else
+#  define  D(...)   ((void)0)
+#endif
+
+/*****************************************************************/
+/*****************************************************************/
+/*****                                                       *****/
+/*****       N M E A   T O K E N I Z E R                     *****/
+/*****                                                       *****/
+/*****************************************************************/
+/*****************************************************************/
+
+typedef struct {
+    const char*  p;
+    const char*  end;
+} Token;
+
+#define  MAX_NMEA_TOKENS  16
+
+typedef struct {
+    int     count;
+    Token   tokens[ MAX_NMEA_TOKENS ];
+} NmeaTokenizer;
+
+static int
+nmea_tokenizer_init( NmeaTokenizer*  t, const char*  p, const char*  end )
+{
+    int    count = 0;
+    char*  q;
+
+    // the initial '$' is optional
+    if (p < end && p[0] == '$')
+        p += 1;
+
+    // remove trailing newline
+    if (end > p && end[-1] == '\n') {
+        end -= 1;
+        if (end > p && end[-1] == '\r')
+            end -= 1;
+    }
+
+    // get rid of checksum at the end of the sentecne
+    if (end >= p+3 && end[-3] == '*') {
+        end -= 3;
+    }
+
+    while (p < end) {
+        const char*  q = p;
+
+        q = memchr(p, ',', end-p);
+        if (q == NULL)
+            q = end;
+
+        if (q > p) {
+            if (count < MAX_NMEA_TOKENS) {
+                t->tokens[count].p   = p;
+                t->tokens[count].end = q;
+                count += 1;
+            }
+        }
+        if (q < end)
+            q += 1;
+
+        p = q;
+    }
+
+    t->count = count;
+    return count;
+}
+
+static Token
+nmea_tokenizer_get( NmeaTokenizer*  t, int  index )
+{
+    Token  tok;
+    static const char*  dummy = "";
+
+    if (index < 0 || index >= t->count) {
+        tok.p = tok.end = dummy;
+    } else
+        tok = t->tokens[index];
+
+    return tok;
+}
+
+
+static int
+str2int( const char*  p, const char*  end )
+{
+    int   result = 0;
+    int   len    = end - p;
+
+    for ( ; len > 0; len--, p++ )
+    {
+        int  c;
+
+        if (p >= end)
+            goto Fail;
+
+        c = *p - '0';
+        if ((unsigned)c >= 10)
+            goto Fail;
+
+        result = result*10 + c;
+    }
+    return  result;
+
+Fail:
+    return -1;
+}
+
+static double
+str2float( const char*  p, const char*  end )
+{
+    int   result = 0;
+    int   len    = end - p;
+    char  temp[16];
+
+    if (len >= (int)sizeof(temp))
+        return 0.;
+
+    memcpy( temp, p, len );
+    temp[len] = 0;
+    return strtod( temp, NULL );
+}
+
+/*****************************************************************/
+/*****************************************************************/
+/*****                                                       *****/
+/*****       N M E A   P A R S E R                           *****/
+/*****                                                       *****/
+/*****************************************************************/
+/*****************************************************************/
+
+#define  NMEA_MAX_SIZE  83
+
+typedef struct {
+    int     pos;
+    int     overflow;
+    int     utc_year;
+    int     utc_mon;
+    int     utc_day;
+    int     utc_diff;
+    GpsLocation  fix;
+    gps_location_callback  callback;
+    char    in[ NMEA_MAX_SIZE+1 ];
+} NmeaReader;
+
+
+static void
+nmea_reader_update_utc_diff( NmeaReader*  r )
+{
+    time_t         now = time(NULL);
+    struct tm      tm_local;
+    struct tm      tm_utc;
+    long           time_local, time_utc;
+
+    gmtime_r( &now, &tm_utc );
+    localtime_r( &now, &tm_local );
+
+    time_local = tm_local.tm_sec +
+                 60*(tm_local.tm_min +
+                 60*(tm_local.tm_hour +
+                 24*(tm_local.tm_yday +
+                 365*tm_local.tm_year)));
+
+    time_utc = tm_utc.tm_sec +
+               60*(tm_utc.tm_min +
+               60*(tm_utc.tm_hour +
+               24*(tm_utc.tm_yday +
+               365*tm_utc.tm_year)));
+
+    r->utc_diff = time_utc - time_local;
+}
+
+
+static void
+nmea_reader_init( NmeaReader*  r )
+{
+    memset( r, 0, sizeof(*r) );
+
+    r->pos      = 0;
+    r->overflow = 0;
+    r->utc_year = -1;
+    r->utc_mon  = -1;
+    r->utc_day  = -1;
+    r->callback = NULL;
+    r->fix.size = sizeof(r->fix);
+
+    nmea_reader_update_utc_diff( r );
+}
+
+
+static void
+nmea_reader_set_callback( NmeaReader*  r, gps_location_callback  cb )
+{
+    r->callback = cb;
+    if (cb != NULL && r->fix.flags != 0) {
+        D("%s: sending latest fix to new callback", __FUNCTION__);
+        r->callback( &r->fix );
+        r->fix.flags = 0;
+    }
+}
+
+
+static int
+nmea_reader_update_time( NmeaReader*  r, Token  tok )
+{
+    int        hour, minute;
+    double     seconds;
+    struct tm  tm;
+    time_t     fix_time;
+
+    if (tok.p + 6 > tok.end)
+        return -1;
+
+    if (r->utc_year < 0) {
+        // no date yet, get current one
+        time_t  now = time(NULL);
+        gmtime_r( &now, &tm );
+        r->utc_year = tm.tm_year + 1900;
+        r->utc_mon  = tm.tm_mon + 1;
+        r->utc_day  = tm.tm_mday;
+    }
+
+    hour    = str2int(tok.p,   tok.p+2);
+    minute  = str2int(tok.p+2, tok.p+4);
+    seconds = str2float(tok.p+4, tok.end);
+
+    tm.tm_hour  = hour;
+    tm.tm_min   = minute;
+    tm.tm_sec   = (int) seconds;
+    tm.tm_year  = r->utc_year - 1900;
+    tm.tm_mon   = r->utc_mon - 1;
+    tm.tm_mday  = r->utc_day;
+    tm.tm_isdst = -1;
+
+    fix_time = mktime( &tm ) + r->utc_diff;
+    r->fix.timestamp = (long long)fix_time * 1000;
+    return 0;
+}
+
+static int
+nmea_reader_update_date( NmeaReader*  r, Token  date, Token  time )
+{
+    Token  tok = date;
+    int    day, mon, year;
+
+    if (tok.p + 6 != tok.end) {
+        D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
+        return -1;
+    }
+    day  = str2int(tok.p, tok.p+2);
+    mon  = str2int(tok.p+2, tok.p+4);
+    year = str2int(tok.p+4, tok.p+6) + 2000;
+
+    if ((day|mon|year) < 0) {
+        D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
+        return -1;
+    }
+
+    r->utc_year  = year;
+    r->utc_mon   = mon;
+    r->utc_day   = day;
+
+    return nmea_reader_update_time( r, time );
+}
+
+
+static double
+convert_from_hhmm( Token  tok )
+{
+    double  val     = str2float(tok.p, tok.end);
+    int     degrees = (int)(floor(val) / 100);
+    double  minutes = val - degrees*100.;
+    double  dcoord  = degrees + minutes / 60.0;
+    return dcoord;
+}
+
+
+static int
+nmea_reader_update_latlong( NmeaReader*  r,
+                            Token        latitude,
+                            char         latitudeHemi,
+                            Token        longitude,
+                            char         longitudeHemi )
+{
+    double   lat, lon;
+    Token    tok;
+
+    tok = latitude;
+    if (tok.p + 6 > tok.end) {
+        D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
+        return -1;
+    }
+    lat = convert_from_hhmm(tok);
+    if (latitudeHemi == 'S')
+        lat = -lat;
+
+    tok = longitude;
+    if (tok.p + 6 > tok.end) {
+        D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
+        return -1;
+    }
+    lon = convert_from_hhmm(tok);
+    if (longitudeHemi == 'W')
+        lon = -lon;
+
+    r->fix.flags    |= GPS_LOCATION_HAS_LAT_LONG;
+    r->fix.latitude  = lat;
+    r->fix.longitude = lon;
+    return 0;
+}
+
+
+static int
+nmea_reader_update_altitude( NmeaReader*  r,
+                             Token        altitude,
+                             Token        units )
+{
+    double  alt;
+    Token   tok = altitude;
+
+    if (tok.p >= tok.end)
+        return -1;
+
+    r->fix.flags   |= GPS_LOCATION_HAS_ALTITUDE;
+    r->fix.altitude = str2float(tok.p, tok.end);
+    return 0;
+}
+
+
+static int
+nmea_reader_update_bearing( NmeaReader*  r,
+                            Token        bearing )
+{
+    double  alt;
+    Token   tok = bearing;
+
+    if (tok.p >= tok.end)
+        return -1;
+
+    r->fix.flags   |= GPS_LOCATION_HAS_BEARING;
+    r->fix.bearing  = str2float(tok.p, tok.end);
+    return 0;
+}
+
+
+static int
+nmea_reader_update_speed( NmeaReader*  r,
+                          Token        speed )
+{
+    double  alt;
+    Token   tok = speed;
+
+    if (tok.p >= tok.end)
+        return -1;
+
+    r->fix.flags   |= GPS_LOCATION_HAS_SPEED;
+    r->fix.speed    = str2float(tok.p, tok.end);
+    return 0;
+}
+
+
+static void
+nmea_reader_parse( NmeaReader*  r )
+{
+   /* we received a complete sentence, now parse it to generate
+    * a new GPS fix...
+    */
+    NmeaTokenizer  tzer[1];
+    Token          tok;
+
+    D("Received: '%.*s'", r->pos, r->in);
+    if (r->pos < 9) {
+        D("Too short. discarded.");
+        return;
+    }
+
+    nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
+#if GPS_DEBUG
+    {
+        int  n;
+        D("Found %d tokens", tzer->count);
+        for (n = 0; n < tzer->count; n++) {
+            Token  tok = nmea_tokenizer_get(tzer,n);
+            D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
+        }
+    }
+#endif
+
+    tok = nmea_tokenizer_get(tzer, 0);
+    if (tok.p + 5 > tok.end) {
+        D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
+        return;
+    }
+
+    // ignore first two characters.
+    tok.p += 2;
+    if ( !memcmp(tok.p, "GGA", 3) ) {
+        // GPS fix
+        Token  tok_time          = nmea_tokenizer_get(tzer,1);
+        Token  tok_latitude      = nmea_tokenizer_get(tzer,2);
+        Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,3);
+        Token  tok_longitude     = nmea_tokenizer_get(tzer,4);
+        Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
+        Token  tok_altitude      = nmea_tokenizer_get(tzer,9);
+        Token  tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
+
+        nmea_reader_update_time(r, tok_time);
+        nmea_reader_update_latlong(r, tok_latitude,
+                                      tok_latitudeHemi.p[0],
+                                      tok_longitude,
+                                      tok_longitudeHemi.p[0]);
+        nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
+
+    } else if ( !memcmp(tok.p, "GSA", 3) ) {
+        // do something ?
+    } else if ( !memcmp(tok.p, "RMC", 3) ) {
+        Token  tok_time          = nmea_tokenizer_get(tzer,1);
+        Token  tok_fixStatus     = nmea_tokenizer_get(tzer,2);
+        Token  tok_latitude      = nmea_tokenizer_get(tzer,3);
+        Token  tok_latitudeHemi  = nmea_tokenizer_get(tzer,4);
+        Token  tok_longitude     = nmea_tokenizer_get(tzer,5);
+        Token  tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
+        Token  tok_speed         = nmea_tokenizer_get(tzer,7);
+        Token  tok_bearing       = nmea_tokenizer_get(tzer,8);
+        Token  tok_date          = nmea_tokenizer_get(tzer,9);
+
+        D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
+        if (tok_fixStatus.p[0] == 'A')
+        {
+            nmea_reader_update_date( r, tok_date, tok_time );
+
+            nmea_reader_update_latlong( r, tok_latitude,
+                                           tok_latitudeHemi.p[0],
+                                           tok_longitude,
+                                           tok_longitudeHemi.p[0] );
+
+            nmea_reader_update_bearing( r, tok_bearing );
+            nmea_reader_update_speed  ( r, tok_speed );
+        }
+    } else {
+        tok.p -= 2;
+        D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
+    }
+    if (r->fix.flags != 0) {
+#if GPS_DEBUG
+        char   temp[256];
+        char*  p   = temp;
+        char*  end = p + sizeof(temp);
+        struct tm   utc;
+
+        p += snprintf( p, end-p, "sending fix" );
+        if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
+            p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
+        }
+        if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
+            p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
+        }
+        if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
+            p += snprintf(p, end-p, " speed=%g", r->fix.speed);
+        }
+        if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
+            p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
+        }
+        if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
+            p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
+        }
+        gmtime_r( (time_t*) &r->fix.timestamp, &utc );
+        p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
+        D(temp);
+#endif
+        if (r->callback) {
+            r->callback( &r->fix );
+            r->fix.flags = 0;
+        }
+        else {
+            D("no callback, keeping data until needed !");
+        }
+    }
+}
+
+
+static void
+nmea_reader_addc( NmeaReader*  r, int  c )
+{
+    if (r->overflow) {
+        r->overflow = (c != '\n');
+        return;
+    }
+
+    if (r->pos >= (int) sizeof(r->in)-1 ) {
+        r->overflow = 1;
+        r->pos      = 0;
+        return;
+    }
+
+    r->in[r->pos] = (char)c;
+    r->pos       += 1;
+
+    if (c == '\n') {
+        nmea_reader_parse( r );
+        r->pos = 0;
+    }
+}
+
+
+/*****************************************************************/
+/*****************************************************************/
+/*****                                                       *****/
+/*****       C O N N E C T I O N   S T A T E                 *****/
+/*****                                                       *****/
+/*****************************************************************/
+/*****************************************************************/
+
+/* commands sent to the gps thread */
+enum {
+    CMD_QUIT  = 0,
+    CMD_START = 1,
+    CMD_STOP  = 2
+};
+
+
+/* this is the state of our connection to the qemu_gpsd daemon */
+typedef struct {
+    int                     init;
+    int                     fd;
+    GpsCallbacks            callbacks;
+    pthread_t               thread;
+    int                     control[2];
+} GpsState;
+
+static GpsState  _gps_state[1];
+
+
+static void
+gps_state_done( GpsState*  s )
+{
+    // tell the thread to quit, and wait for it
+    char   cmd = CMD_QUIT;
+    void*  dummy;
+    write( s->control[0], &cmd, 1 );
+    pthread_join(s->thread, &dummy);
+
+    // close the control socket pair
+    close( s->control[0] ); s->control[0] = -1;
+    close( s->control[1] ); s->control[1] = -1;
+
+    // close connection to the QEMU GPS daemon
+    close( s->fd ); s->fd = -1;
+    s->init = 0;
+}
+
+
+static void
+gps_state_start( GpsState*  s )
+{
+    char  cmd = CMD_START;
+    int   ret;
+
+    do { ret=write( s->control[0], &cmd, 1 ); }
+    while (ret < 0 && errno == EINTR);
+
+    if (ret != 1)
+        D("%s: could not send CMD_START command: ret=%d: %s",
+          __FUNCTION__, ret, strerror(errno));
+}
+
+
+static void
+gps_state_stop( GpsState*  s )
+{
+    char  cmd = CMD_STOP;
+    int   ret;
+
+    do { ret=write( s->control[0], &cmd, 1 ); }
+    while (ret < 0 && errno == EINTR);
+
+    if (ret != 1)
+        D("%s: could not send CMD_STOP command: ret=%d: %s",
+          __FUNCTION__, ret, strerror(errno));
+}
+
+
+static int
+epoll_register( int  epoll_fd, int  fd )
+{
+    struct epoll_event  ev;
+    int                 ret, flags;
+
+    /* important: make the fd non-blocking */
+    flags = fcntl(fd, F_GETFL);
+    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+    ev.events  = EPOLLIN;
+    ev.data.fd = fd;
+    do {
+        ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
+    } while (ret < 0 && errno == EINTR);
+    return ret;
+}
+
+
+static int
+epoll_deregister( int  epoll_fd, int  fd )
+{
+    int  ret;
+    do {
+        ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
+    } while (ret < 0 && errno == EINTR);
+    return ret;
+}
+
+/* this is the main thread, it waits for commands from gps_state_start/stop and,
+ * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
+ * that must be parsed to be converted into GPS fixes sent to the framework
+ */
+static void
+gps_state_thread( void*  arg )
+{
+    GpsState*   state = (GpsState*) arg;
+    NmeaReader  reader[1];
+    int         epoll_fd   = epoll_create(2);
+    int         started    = 0;
+    int         gps_fd     = state->fd;
+    int         control_fd = state->control[1];
+
+    nmea_reader_init( reader );
+
+    // register control file descriptors for polling
+    epoll_register( epoll_fd, control_fd );
+    epoll_register( epoll_fd, gps_fd );
+
+    D("gps thread running");
+
+    // now loop
+    for (;;) {
+        struct epoll_event   events[2];
+        int                  ne, nevents;
+
+        nevents = epoll_wait( epoll_fd, events, 2, -1 );
+        if (nevents < 0) {
+            if (errno != EINTR)
+                LOGE("epoll_wait() unexpected error: %s", strerror(errno));
+            continue;
+        }
+        D("gps thread received %d events", nevents);
+        for (ne = 0; ne < nevents; ne++) {
+            if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
+                LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
+                return;
+            }
+            if ((events[ne].events & EPOLLIN) != 0) {
+                int  fd = events[ne].data.fd;
+
+                if (fd == control_fd)
+                {
+                    char  cmd = 255;
+                    int   ret;
+                    D("gps control fd event");
+                    do {
+                        ret = read( fd, &cmd, 1 );
+                    } while (ret < 0 && errno == EINTR);
+
+                    if (cmd == CMD_QUIT) {
+                        D("gps thread quitting on demand");
+                        return;
+                    }
+                    else if (cmd == CMD_START) {
+                        if (!started) {
+                            D("gps thread starting  location_cb=%p", state->callbacks.location_cb);
+                            started = 1;
+                            nmea_reader_set_callback( reader, state->callbacks.location_cb );
+                        }
+                    }
+                    else if (cmd == CMD_STOP) {
+                        if (started) {
+                            D("gps thread stopping");
+                            started = 0;
+                            nmea_reader_set_callback( reader, NULL );
+                        }
+                    }
+                }
+                else if (fd == gps_fd)
+                {
+                    char  buff[32];
+                    D("gps fd event");
+                    for (;;) {
+                        int  nn, ret;
+
+                        ret = read( fd, buff, sizeof(buff) );
+                        if (ret < 0) {
+                            if (errno == EINTR)
+                                continue;
+                            if (errno != EWOULDBLOCK)
+                                LOGE("error while reading from gps daemon socket: %s:", strerror(errno));
+                            break;
+                        }
+                        D("received %d bytes: %.*s", ret, ret, buff);
+                        for (nn = 0; nn < ret; nn++)
+                            nmea_reader_addc( reader, buff[nn] );
+                    }
+                    D("gps fd event end");
+                }
+                else
+                {
+                    LOGE("epoll_wait() returned unkown fd %d ?", fd);
+                }
+            }
+        }
+    }
+}
+
+
+static void
+gps_state_init( GpsState*  state, GpsCallbacks* callbacks )
+{
+    state->init       = 1;
+    state->control[0] = -1;
+    state->control[1] = -1;
+    state->fd         = -1;
+
+    state->fd = qemud_channel_open(QEMU_CHANNEL_NAME);
+
+    if (state->fd < 0) {
+        D("no gps emulation detected");
+        return;
+    }
+
+    D("gps emulation will read from '%s' qemud channel", QEMU_CHANNEL_NAME );
+
+    if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
+        LOGE("could not create thread control socket pair: %s", strerror(errno));
+        goto Fail;
+    }
+
+    state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
+
+    if ( !state->thread ) {
+        LOGE("could not create gps thread: %s", strerror(errno));
+        goto Fail;
+    }
+
+    state->callbacks = *callbacks;
+
+    D("gps state initialized");
+    return;
+
+Fail:
+    gps_state_done( state );
+}
+
+
+/*****************************************************************/
+/*****************************************************************/
+/*****                                                       *****/
+/*****       I N T E R F A C E                               *****/
+/*****                                                       *****/
+/*****************************************************************/
+/*****************************************************************/
+
+
+static int
+qemu_gps_init(GpsCallbacks* callbacks)
+{
+    GpsState*  s = _gps_state;
+
+    if (!s->init)
+        gps_state_init(s, callbacks);
+
+    if (s->fd < 0)
+        return -1;
+
+    return 0;
+}
+
+static void
+qemu_gps_cleanup(void)
+{
+    GpsState*  s = _gps_state;
+
+    if (s->init)
+        gps_state_done(s);
+}
+
+
+static int
+qemu_gps_start()
+{
+    GpsState*  s = _gps_state;
+
+    if (!s->init) {
+        D("%s: called with uninitialized state !!", __FUNCTION__);
+        return -1;
+    }
+
+    D("%s: called", __FUNCTION__);
+    gps_state_start(s);
+    return 0;
+}
+
+
+static int
+qemu_gps_stop()
+{
+    GpsState*  s = _gps_state;
+
+    if (!s->init) {
+        D("%s: called with uninitialized state !!", __FUNCTION__);
+        return -1;
+    }
+
+    D("%s: called", __FUNCTION__);
+    gps_state_stop(s);
+    return 0;
+}
+
+
+static int
+qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
+{
+    return 0;
+}
+
+static int
+qemu_gps_inject_location(double latitude, double longitude, float accuracy)
+{
+    return 0;
+}
+
+static void
+qemu_gps_delete_aiding_data(GpsAidingData flags)
+{
+}
+
+static int qemu_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
+{
+    // FIXME - support fix_frequency
+    return 0;
+}
+
+static const void*
+qemu_gps_get_extension(const char* name)
+{
+    // no extensions supported
+    return NULL;
+}
+
+static const GpsInterface  qemuGpsInterface = {
+    sizeof(GpsInterface),
+    qemu_gps_init,
+    qemu_gps_start,
+    qemu_gps_stop,
+    qemu_gps_cleanup,
+    qemu_gps_inject_time,
+    qemu_gps_inject_location,
+    qemu_gps_delete_aiding_data,
+    qemu_gps_set_position_mode,
+    qemu_gps_get_extension,
+};
+
+const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
+{
+    return &qemuGpsInterface;
+}
+
+static int open_gps(const struct hw_module_t* module, char const* name,
+        struct hw_device_t** device)
+{
+    struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
+    memset(dev, 0, sizeof(*dev));
+
+    dev->common.tag = HARDWARE_DEVICE_TAG;
+    dev->common.version = 0;
+    dev->common.module = (struct hw_module_t*)module;
+//    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
+    dev->get_gps_interface = gps__get_gps_interface;
+
+    *device = (struct hw_device_t*)dev;
+    return 0;
+}
+
+
+static struct hw_module_methods_t gps_module_methods = {
+    .open = open_gps
+};
+
+const struct hw_module_t HAL_MODULE_INFO_SYM = {
+    .tag = HARDWARE_MODULE_TAG,
+    .version_major = 1,
+    .version_minor = 0,
+    .id = GPS_HARDWARE_MODULE_ID,
+    .name = "Goldfish GPS Module",
+    .author = "The Android Open Source Project",
+    .methods = &gps_module_methods,
+};
diff --git a/tools/emulator/system/qemu-props/Android.mk b/tools/emulator/system/qemu-props/Android.mk
new file mode 100644
index 0000000..1bdbf68
--- /dev/null
+++ b/tools/emulator/system/qemu-props/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# this file is used to build emulator-specific program tools
+# that should only run in the emulator.
+#
+
+# We're moving the emulator-specific platform libs to
+# development.git/tools/emulator/. The following test is to ensure
+# smooth builds even if the tree contains both versions.
+#
+ifndef BUILD_EMULATOR_QEMU_PROPS
+BUILD_EMULATOR_QEMU_PROPS := true
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_PRODUCT),sim)
+
+# The 'qemu-props' program is run from /system/etc/init.goldfish.rc
+# to setup various system properties sent by the emulator program.
+#
+include $(CLEAR_VARS)
+LOCAL_MODULE    := qemu-props
+LOCAL_SRC_FILES := qemu-props.c
+LOCAL_SHARED_LIBRARIES := libcutils
+# we don't want this in 'user' builds which don't have
+# emulator-specific binaries.
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
+
+endif # TARGET_PRODUCT != sim
+
+endif # BUILD_EMULATOR_QEMU_PROPS
diff --git a/tools/emulator/system/qemu-props/qemu-props.c b/tools/emulator/system/qemu-props/qemu-props.c
new file mode 100644
index 0000000..3f086a1
--- /dev/null
+++ b/tools/emulator/system/qemu-props/qemu-props.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* this program is used to read a set of system properties and their values
+ * from the emulator program and set them in the currently-running emulated
+ * system. It does so by connecting to the 'boot-properties' qemud service.
+ *
+ * This program should be run as root and called from
+ * /system/etc/init.goldfish.rc exclusively.
+ */
+
+#define LOG_TAG  "qemu-props"
+
+#define DEBUG  1
+
+#if DEBUG
+#  include <cutils/log.h>
+#  define  DD(...)    LOGI(__VA_ARGS__)
+#else
+#  define  DD(...)    ((void)0)
+#endif
+
+#include <cutils/properties.h>
+#include <unistd.h>
+#include <hardware/qemud.h>
+
+/* Name of the qemud service we want to connect to.
+ */
+#define  QEMUD_SERVICE  "boot-properties"
+
+#define  MAX_TRIES      5
+
+int  main(void)
+{
+    int  qemud_fd, count = 0;
+
+    /* try to connect to the qemud service */
+    {
+        int  tries = MAX_TRIES;
+
+        while (1) {
+            qemud_fd = qemud_channel_open( "boot-properties" );
+            if (qemud_fd >= 0)
+                break;
+
+            if (--tries <= 0) {
+                DD("Could not connect after too many tries. Aborting");
+                return 1;
+            }
+
+            DD("waiting 1s to wait for qemud.");
+            sleep(1);
+        }
+    }
+
+    DD("connected to '%s' qemud service.", QEMUD_SERVICE);
+
+    /* send the 'list' command to the service */
+    if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
+        DD("could not send command to '%s' service", QEMUD_SERVICE);
+        return 1;
+    }
+
+    /* read each system property as a single line from the service,
+     * until exhaustion.
+     */
+    for (;;)
+    {
+#define  BUFF_SIZE   (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
+        DD("receiving..");
+        char* q;
+        char  temp[BUFF_SIZE];
+        int   len = qemud_channel_recv(qemud_fd, temp, sizeof temp - 1);
+
+        /* lone NUL-byte signals end of properties */
+        if (len < 0 || len > BUFF_SIZE-1 || temp[0] == '\0')
+            break;
+
+        temp[len] = '\0';  /* zero-terminate string */
+
+        DD("received: %.*s", len, temp);
+
+        /* separate propery name from value */
+        q = strchr(temp, '=');
+        if (q == NULL) {
+            DD("invalid format, ignored.");
+            continue;
+        }
+        *q++ = '\0';
+
+        if (property_set(temp, q) < 0) {
+            DD("could not set property '%s' to '%s'", temp, q);
+        } else {
+            count += 1;
+        }
+    }
+
+
+    /* finally, close the channel and exit */
+    close(qemud_fd);
+    DD("exiting (%d properties set).", count);
+    return 0;
+}
diff --git a/tools/emulator/system/qemud/Android.mk b/tools/emulator/system/qemud/Android.mk
new file mode 100644
index 0000000..5666a74
--- /dev/null
+++ b/tools/emulator/system/qemud/Android.mk
@@ -0,0 +1,25 @@
+# Copyright 2008 The Android Open Source Project
+
+# We're moving the emulator-specific platform libs to
+# development.git/tools/emulator/. The following test is to ensure
+# smooth builds even if the tree contains both versions.
+#
+ifndef BUILD_EMULATOR_QEMUD
+BUILD_EMULATOR_QEMUD := true
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	qemud.c
+
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+
+LOCAL_MODULE:= qemud
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
+
+endif # BUILD_EMULATOR_QEMUD
\ No newline at end of file
diff --git a/tools/emulator/system/qemud/qemud.c b/tools/emulator/system/qemud/qemud.c
new file mode 100644
index 0000000..e1c7b54
--- /dev/null
+++ b/tools/emulator/system/qemud/qemud.c
@@ -0,0 +1,1719 @@
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <termios.h>
+#include <cutils/sockets.h>
+
+/*
+ *  the qemud daemon program is only used within Android as a bridge
+ *  between the emulator program and the emulated system. it really works as
+ *  a simple stream multiplexer that works as follows:
+ *
+ *    - qemud is started by init following instructions in
+ *      /system/etc/init.goldfish.rc (i.e. it is never started on real devices)
+ *
+ *    - qemud communicates with the emulator program through a single serial
+ *      port, whose name is passed through a kernel boot parameter
+ *      (e.g. android.qemud=ttyS1)
+ *
+ *    - qemud binds one unix local stream socket (/dev/socket/qemud, created
+ *      by init through /system/etc/init.goldfish.rc).
+ *
+ *
+ *      emulator <==serial==> qemud <---> /dev/socket/qemud <-+--> client1
+ *                                                            |
+ *                                                            +--> client2
+ *
+ *   - the special channel index 0 is used by the emulator and qemud only.
+ *     other channel numbers correspond to clients. More specifically,
+ *     connection are created like this:
+ *
+ *     * the client connects to /dev/socket/qemud
+ *
+ *     * the client sends the service name through the socket, as
+ *            <service-name>
+ *
+ *     * qemud creates a "Client" object internally, assigns it an
+ *       internal unique channel number > 0, then sends a connection
+ *       initiation request to the emulator (i.e. through channel 0):
+ *
+ *           connect:<id>:<name>
+ *
+ *       where <name> is the service name, and <id> is a 2-hexchar
+ *       number corresponding to the channel number.
+ *
+ *     * in case of success, the emulator responds through channel 0
+ *       with:
+ *
+ *           ok:connect:<id>
+ *
+ *       after this, all messages between the client and the emulator
+ *       are passed in pass-through mode.
+ *
+ *     * if the emulator refuses the service connection, it will
+ *       send the following through channel 0:
+ *
+ *           ko:connect:<id>:reason-for-failure
+ *
+ *     * If the client closes the connection, qemud sends the following
+ *       to the emulator:
+ *
+ *           disconnect:<id>
+ *
+ *       The same message is the opposite direction if the emulator
+ *       chooses to close the connection.
+ *
+ *     * any command sent through channel 0 to the emulator that is
+ *       not properly recognized will be answered by:
+ *
+ *           ko:unknown command
+ *
+ *
+ *  Internally, the daemon maintains a "Client" object for each client
+ *  connection (i.e. accepting socket connection).
+ */
+
+/* name of the single control socket used by the daemon */
+#define CONTROL_SOCKET_NAME  "qemud"
+
+#define  DEBUG     1
+#define  T_ACTIVE  0  /* set to 1 to dump traffic */
+
+#if DEBUG
+#  define LOG_TAG  "qemud"
+#  include <cutils/log.h>
+#  define  D(...)   LOGD(__VA_ARGS__)
+#else
+#  define  D(...)  ((void)0)
+#  define  T(...)  ((void)0)
+#endif
+
+#if T_ACTIVE
+#  define  T(...)   D(__VA_ARGS__)
+#else
+#  define  T(...)   ((void)0)
+#endif
+
+/** UTILITIES
+ **/
+
+static void
+fatal( const char*  fmt, ... )
+{
+    va_list  args;
+    va_start(args, fmt);
+    fprintf(stderr, "PANIC: ");
+    vfprintf(stderr, fmt, args);
+    fprintf(stderr, "\n" );
+    va_end(args);
+    exit(1);
+}
+
+static void*
+xalloc( size_t   sz )
+{
+    void*  p;
+
+    if (sz == 0)
+        return NULL;
+
+    p = malloc(sz);
+    if (p == NULL)
+        fatal( "not enough memory" );
+
+    return p;
+}
+
+#define  xnew(p)   (p) = xalloc(sizeof(*(p)))
+
+static void*
+xalloc0( size_t  sz )
+{
+    void*  p = xalloc(sz);
+    memset( p, 0, sz );
+    return p;
+}
+
+#define  xnew0(p)   (p) = xalloc0(sizeof(*(p)))
+
+#define  xfree(p)    (free((p)), (p) = NULL)
+
+static void*
+xrealloc( void*  block, size_t  size )
+{
+    void*  p = realloc( block, size );
+
+    if (p == NULL && size > 0)
+        fatal( "not enough memory" );
+
+    return p;
+}
+
+#define  xrenew(p,count)  (p) = xrealloc((p),sizeof(*(p))*(count))
+
+static int
+hex2int( const uint8_t*  data, int  len )
+{
+    int  result = 0;
+    while (len > 0) {
+        int       c = *data++;
+        unsigned  d;
+
+        result <<= 4;
+        do {
+            d = (unsigned)(c - '0');
+            if (d < 10)
+                break;
+
+            d = (unsigned)(c - 'a');
+            if (d < 6) {
+                d += 10;
+                break;
+            }
+
+            d = (unsigned)(c - 'A');
+            if (d < 6) {
+                d += 10;
+                break;
+            }
+
+            return -1;
+        }
+        while (0);
+
+        result |= d;
+        len    -= 1;
+    }
+    return  result;
+}
+
+
+static void
+int2hex( int  value, uint8_t*  to, int  width )
+{
+    int  nn = 0;
+    static const char hexchars[16] = "0123456789abcdef";
+
+    for ( --width; width >= 0; width--, nn++ ) {
+        to[nn] = hexchars[(value >> (width*4)) & 15];
+    }
+}
+
+static int
+fd_read(int  fd, void*  to, int  len)
+{
+    int  ret;
+
+    do {
+        ret = read(fd, to, len);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static int
+fd_write(int  fd, const void*  from, int  len)
+{
+    int  ret;
+
+    do {
+        ret = write(fd, from, len);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+static void
+fd_setnonblock(int  fd)
+{
+    int  ret, flags;
+
+    do {
+        flags = fcntl(fd, F_GETFD);
+    } while (flags < 0 && errno == EINTR);
+
+    if (flags < 0) {
+        fatal( "%s: could not get flags for fd %d: %s",
+               __FUNCTION__, fd, strerror(errno) );
+    }
+
+    do {
+        ret = fcntl(fd, F_SETFD, flags | O_NONBLOCK);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret < 0) {
+        fatal( "%s: could not set fd %d to non-blocking: %s",
+               __FUNCTION__, fd, strerror(errno) );
+    }
+}
+
+
+static int
+fd_accept(int  fd)
+{
+    struct sockaddr  from;
+    socklen_t        fromlen = sizeof(from);
+    int              ret;
+
+    do {
+        ret = accept(fd, &from, &fromlen);
+    } while (ret < 0 && errno == EINTR);
+
+    return ret;
+}
+
+/** FD EVENT LOOP
+ **/
+
+/* A Looper object is used to monitor activity on one or more
+ * file descriptors (e.g sockets).
+ *
+ * - call looper_add() to register a function that will be
+ *   called when events happen on the file descriptor.
+ *
+ * - call looper_enable() or looper_disable() to enable/disable
+ *   the set of monitored events for a given file descriptor.
+ *
+ * - call looper_del() to unregister a file descriptor.
+ *   this does *not* close the file descriptor.
+ *
+ * Note that you can only provide a single function to handle
+ * all events related to a given file descriptor.
+
+ * You can call looper_enable/_disable/_del within a function
+ * callback.
+ */
+
+/* the current implementation uses Linux's epoll facility
+ * the event mask we use are simply combinations of EPOLLIN
+ * EPOLLOUT, EPOLLHUP and EPOLLERR
+ */
+#include <sys/epoll.h>
+
+#define  MAX_CHANNELS  16
+#define  MAX_EVENTS    (MAX_CHANNELS+1)  /* each channel + the serial fd */
+
+/* the event handler function type, 'user' is a user-specific
+ * opaque pointer passed to looper_add().
+ */
+typedef void (*EventFunc)( void*  user, int  events );
+
+/* bit flags for the LoopHook structure.
+ *
+ * HOOK_PENDING means that an event happened on the
+ * corresponding file descriptor.
+ *
+ * HOOK_CLOSING is used to delay-close monitored
+ * file descriptors.
+ */
+enum {
+    HOOK_PENDING = (1 << 0),
+    HOOK_CLOSING = (1 << 1),
+};
+
+/* A LoopHook structure is used to monitor a given
+ * file descriptor and record its event handler.
+ */
+typedef struct {
+    int        fd;
+    int        wanted;  /* events we are monitoring */
+    int        events;  /* events that occured */
+    int        state;   /* see HOOK_XXX constants */
+    void*      ev_user; /* user-provided handler parameter */
+    EventFunc  ev_func; /* event handler callback */
+} LoopHook;
+
+/* Looper is the main object modeling a looper object
+ */
+typedef struct {
+    int                  epoll_fd;
+    int                  num_fds;
+    int                  max_fds;
+    struct epoll_event*  events;
+    LoopHook*            hooks;
+} Looper;
+
+/* initialize a looper object */
+static void
+looper_init( Looper*  l )
+{
+    l->epoll_fd = epoll_create(4);
+    l->num_fds  = 0;
+    l->max_fds  = 0;
+    l->events   = NULL;
+    l->hooks    = NULL;
+}
+
+/* finalize a looper object */
+static void
+looper_done( Looper*  l )
+{
+    xfree(l->events);
+    xfree(l->hooks);
+    l->max_fds = 0;
+    l->num_fds = 0;
+
+    close(l->epoll_fd);
+    l->epoll_fd  = -1;
+}
+
+/* return the LoopHook corresponding to a given
+ * monitored file descriptor, or NULL if not found
+ */
+static LoopHook*
+looper_find( Looper*  l, int  fd )
+{
+    LoopHook*  hook = l->hooks;
+    LoopHook*  end  = hook + l->num_fds;
+
+    for ( ; hook < end; hook++ ) {
+        if (hook->fd == fd)
+            return hook;
+    }
+    return NULL;
+}
+
+/* grow the arrays in the looper object */
+static void
+looper_grow( Looper*  l )
+{
+    int  old_max = l->max_fds;
+    int  new_max = old_max + (old_max >> 1) + 4;
+    int  n;
+
+    xrenew( l->events, new_max );
+    xrenew( l->hooks,  new_max );
+    l->max_fds = new_max;
+
+    /* now change the handles to all events */
+    for (n = 0; n < l->num_fds; n++) {
+        struct epoll_event ev;
+        LoopHook*          hook = l->hooks + n;
+
+        ev.events   = hook->wanted;
+        ev.data.ptr = hook;
+        epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, hook->fd, &ev );
+    }
+}
+
+/* register a file descriptor and its event handler.
+ * no event mask will be enabled
+ */
+static void
+looper_add( Looper*  l, int  fd, EventFunc  func, void*  user )
+{
+    struct epoll_event  ev;
+    LoopHook*           hook;
+
+    if (l->num_fds >= l->max_fds)
+        looper_grow(l);
+
+    hook = l->hooks + l->num_fds;
+
+    hook->fd      = fd;
+    hook->ev_user = user;
+    hook->ev_func = func;
+    hook->state   = 0;
+    hook->wanted  = 0;
+    hook->events  = 0;
+
+    fd_setnonblock(fd);
+
+    ev.events   = 0;
+    ev.data.ptr = hook;
+    epoll_ctl( l->epoll_fd, EPOLL_CTL_ADD, fd, &ev );
+
+    l->num_fds += 1;
+}
+
+/* unregister a file descriptor and its event handler
+ */
+static void
+looper_del( Looper*  l, int  fd )
+{
+    LoopHook*  hook = looper_find( l, fd );
+
+    if (!hook) {
+        D( "%s: invalid fd: %d", __FUNCTION__, fd );
+        return;
+    }
+    /* don't remove the hook yet */
+    hook->state |= HOOK_CLOSING;
+
+    epoll_ctl( l->epoll_fd, EPOLL_CTL_DEL, fd, NULL );
+}
+
+/* enable monitoring of certain events for a file
+ * descriptor. This adds 'events' to the current
+ * event mask
+ */
+static void
+looper_enable( Looper*  l, int  fd, int  events )
+{
+    LoopHook*  hook = looper_find( l, fd );
+
+    if (!hook) {
+        D("%s: invalid fd: %d", __FUNCTION__, fd );
+        return;
+    }
+
+    if (events & ~hook->wanted) {
+        struct epoll_event  ev;
+
+        hook->wanted |= events;
+        ev.events   = hook->wanted;
+        ev.data.ptr = hook;
+
+        epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev );
+    }
+}
+
+/* disable monitoring of certain events for a file
+ * descriptor. This ignores events that are not
+ * currently enabled.
+ */
+static void
+looper_disable( Looper*  l, int  fd, int  events )
+{
+    LoopHook*  hook = looper_find( l, fd );
+
+    if (!hook) {
+        D("%s: invalid fd: %d", __FUNCTION__, fd );
+        return;
+    }
+
+    if (events & hook->wanted) {
+        struct epoll_event  ev;
+
+        hook->wanted &= ~events;
+        ev.events   = hook->wanted;
+        ev.data.ptr = hook;
+
+        epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev );
+    }
+}
+
+/* wait until an event occurs on one of the registered file
+ * descriptors. Only returns in case of error !!
+ */
+static void
+looper_loop( Looper*  l )
+{
+    for (;;) {
+        int  n, count;
+
+        do {
+            count = epoll_wait( l->epoll_fd, l->events, l->num_fds, -1 );
+        } while (count < 0 && errno == EINTR);
+
+        if (count < 0) {
+            D("%s: error: %s", __FUNCTION__, strerror(errno) );
+            return;
+        }
+
+        if (count == 0) {
+            D("%s: huh ? epoll returned count=0", __FUNCTION__);
+            continue;
+        }
+
+        /* mark all pending hooks */
+        for (n = 0; n < count; n++) {
+            LoopHook*  hook = l->events[n].data.ptr;
+            hook->state  = HOOK_PENDING;
+            hook->events = l->events[n].events;
+        }
+
+        /* execute hook callbacks. this may change the 'hooks'
+         * and 'events' array, as well as l->num_fds, so be careful */
+        for (n = 0; n < l->num_fds; n++) {
+            LoopHook*  hook = l->hooks + n;
+            if (hook->state & HOOK_PENDING) {
+                hook->state &= ~HOOK_PENDING;
+                hook->ev_func( hook->ev_user, hook->events );
+            }
+        }
+
+        /* now remove all the hooks that were closed by
+         * the callbacks */
+        for (n = 0; n < l->num_fds;) {
+            struct epoll_event ev;
+            LoopHook*  hook = l->hooks + n;
+
+            if (!(hook->state & HOOK_CLOSING)) {
+                n++;
+                continue;
+            }
+
+            hook[0]     = l->hooks[l->num_fds-1];
+            l->num_fds -= 1;
+            ev.events   = hook->wanted;
+            ev.data.ptr = hook;
+            epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, hook->fd, &ev );
+        }
+    }
+}
+
+#if T_ACTIVE
+char*
+quote( const void*  data, int  len )
+{
+    const char*  p   = data;
+    const char*  end = p + len;
+    int          count = 0;
+    int          phase = 0;
+    static char*  buff = NULL;
+
+    for (phase = 0; phase < 2; phase++) {
+        if (phase != 0) {
+            xfree(buff);
+            buff = xalloc(count+1);
+        }
+        count = 0;
+        for (p = data; p < end; p++) {
+            int  c = *p;
+
+            if (c == '\\') {
+                if (phase != 0) {
+                    buff[count] = buff[count+1] = '\\';
+                }
+                count += 2;
+                continue;
+            }
+
+            if (c >= 32 && c < 127) {
+                if (phase != 0)
+                    buff[count] = c;
+                count += 1;
+                continue;
+            }
+
+
+            if (c == '\t') {
+                if (phase != 0) {
+                    memcpy(buff+count, "<TAB>", 5);
+                }
+                count += 5;
+                continue;
+            }
+            if (c == '\n') {
+                if (phase != 0) {
+                    memcpy(buff+count, "<LN>", 4);
+                }
+                count += 4;
+                continue;
+            }
+            if (c == '\r') {
+                if (phase != 0) {
+                    memcpy(buff+count, "<CR>", 4);
+                }
+                count += 4;
+                continue;
+            }
+
+            if (phase != 0) {
+                buff[count+0] = '\\';
+                buff[count+1] = 'x';
+                buff[count+2] = "0123456789abcdef"[(c >> 4) & 15];
+                buff[count+3] = "0123456789abcdef"[     (c) & 15];
+            }
+            count += 4;
+        }
+    }
+    buff[count] = 0;
+    return buff;
+}
+#endif /* T_ACTIVE */
+
+/** PACKETS
+ **
+ ** We need a way to buffer data before it can be sent to the
+ ** corresponding file descriptor. We use linked list of Packet
+ ** objects to do this.
+ **/
+
+typedef struct Packet   Packet;
+
+#define  MAX_PAYLOAD  4000
+
+struct Packet {
+    Packet*   next;
+    int       len;
+    int       channel;
+    uint8_t   data[ MAX_PAYLOAD ];
+};
+
+/* we expect to alloc/free a lot of packets during
+ * operations so use a single linked list of free packets
+ * to keep things speedy and simple.
+ */
+static Packet*   _free_packets;
+
+/* Allocate a packet */
+static Packet*
+packet_alloc(void)
+{
+    Packet*  p = _free_packets;
+    if (p != NULL) {
+        _free_packets = p->next;
+    } else {
+        xnew(p);
+    }
+    p->next    = NULL;
+    p->len     = 0;
+    p->channel = -1;
+    return p;
+}
+
+/* Release a packet. This takes the address of a packet
+ * pointer that will be set to NULL on exit (avoids
+ * referencing dangling pointers in case of bugs)
+ */
+static void
+packet_free( Packet*  *ppacket )
+{
+    Packet*  p = *ppacket;
+    if (p) {
+        p->next       = _free_packets;
+        _free_packets = p;
+        *ppacket = NULL;
+    }
+}
+
+/** PACKET RECEIVER
+ **
+ ** Simple abstraction for something that can receive a packet
+ ** from a FDHandler (see below) or something else.
+ **
+ ** Send a packet to it with 'receiver_post'
+ **
+ ** Call 'receiver_close' to indicate that the corresponding
+ ** packet source was closed.
+ **/
+
+typedef void (*PostFunc) ( void*  user, Packet*  p );
+typedef void (*CloseFunc)( void*  user );
+
+typedef struct {
+    PostFunc   post;
+    CloseFunc  close;
+    void*      user;
+} Receiver;
+
+/* post a packet to a receiver. Note that this transfers
+ * ownership of the packet to the receiver.
+ */
+static __inline__ void
+receiver_post( Receiver*  r, Packet*  p )
+{
+    if (r->post)
+        r->post( r->user, p );
+    else
+        packet_free(&p);
+}
+
+/* tell a receiver the packet source was closed.
+ * this will also prevent further posting to the
+ * receiver.
+ */
+static __inline__ void
+receiver_close( Receiver*  r )
+{
+    if (r->close) {
+        r->close( r->user );
+        r->close = NULL;
+    }
+    r->post  = NULL;
+}
+
+
+/** FD HANDLERS
+ **
+ ** these are smart listeners that send incoming packets to a receiver
+ ** and can queue one or more outgoing packets and send them when
+ ** possible to the FD.
+ **
+ ** note that we support clean shutdown of file descriptors,
+ ** i.e. we try to send all outgoing packets before destroying
+ ** the FDHandler.
+ **/
+
+typedef struct FDHandler      FDHandler;
+typedef struct FDHandlerList  FDHandlerList;
+
+struct FDHandler {
+    int             fd;
+    FDHandlerList*  list;
+    char            closing;
+    Receiver        receiver[1];
+
+    /* queue of outgoing packets */
+    int             out_pos;
+    Packet*         out_first;
+    Packet**        out_ptail;
+
+    FDHandler*      next;
+    FDHandler**     pref;
+
+};
+
+struct FDHandlerList {
+    /* the looper that manages the fds */
+    Looper*      looper;
+
+    /* list of active FDHandler objects */
+    FDHandler*   active;
+
+    /* list of closing FDHandler objects.
+     * these are waiting to push their
+     * queued packets to the fd before
+     * freeing themselves.
+     */
+    FDHandler*   closing;
+
+};
+
+/* remove a FDHandler from its current list */
+static void
+fdhandler_remove( FDHandler*  f )
+{
+    f->pref[0] = f->next;
+    if (f->next)
+        f->next->pref = f->pref;
+}
+
+/* add a FDHandler to a given list */
+static void
+fdhandler_prepend( FDHandler*  f, FDHandler**  list )
+{
+    f->next = list[0];
+    f->pref = list;
+    list[0] = f;
+    if (f->next)
+        f->next->pref = &f->next;
+}
+
+/* initialize a FDHandler list */
+static void
+fdhandler_list_init( FDHandlerList*  list, Looper*  looper )
+{
+    list->looper  = looper;
+    list->active  = NULL;
+    list->closing = NULL;
+}
+
+
+/* close a FDHandler (and free it). Note that this will not
+ * perform a graceful shutdown, i.e. all packets in the
+ * outgoing queue will be immediately free.
+ *
+ * this *will* notify the receiver that the file descriptor
+ * was closed.
+ *
+ * you should call fdhandler_shutdown() if you want to
+ * notify the FDHandler that its packet source is closed.
+ */
+static void
+fdhandler_close( FDHandler*  f )
+{
+    /* notify receiver */
+    receiver_close(f->receiver);
+
+    /* remove the handler from its list */
+    fdhandler_remove(f);
+
+    /* get rid of outgoing packet queue */
+    if (f->out_first != NULL) {
+        Packet*  p;
+        while ((p = f->out_first) != NULL) {
+            f->out_first = p->next;
+            packet_free(&p);
+        }
+    }
+
+    /* get rid of file descriptor */
+    if (f->fd >= 0) {
+        looper_del( f->list->looper, f->fd );
+        close(f->fd);
+        f->fd = -1;
+    }
+
+    f->list = NULL;
+    xfree(f);
+}
+
+/* Ask the FDHandler to cleanly shutdown the connection,
+ * i.e. send any pending outgoing packets then auto-free
+ * itself.
+ */
+static void
+fdhandler_shutdown( FDHandler*  f )
+{
+    /* prevent later fdhandler_close() to
+     * call the receiver's close.
+     */
+    f->receiver->close = NULL;
+
+    if (f->out_first != NULL && !f->closing)
+    {
+        /* move the handler to the 'closing' list */
+        f->closing = 1;
+        fdhandler_remove(f);
+        fdhandler_prepend(f, &f->list->closing);
+        return;
+    }
+
+    fdhandler_close(f);
+}
+
+/* Enqueue a new packet that the FDHandler will
+ * send through its file descriptor.
+ */
+static void
+fdhandler_enqueue( FDHandler*  f, Packet*  p )
+{
+    Packet*  first = f->out_first;
+
+    p->next         = NULL;
+    f->out_ptail[0] = p;
+    f->out_ptail    = &p->next;
+
+    if (first == NULL) {
+        f->out_pos = 0;
+        looper_enable( f->list->looper, f->fd, EPOLLOUT );
+    }
+}
+
+
+/* FDHandler file descriptor event callback for read/write ops */
+static void
+fdhandler_event( FDHandler*  f, int  events )
+{
+   int  len;
+
+    /* in certain cases, it's possible to have both EPOLLIN and
+     * EPOLLHUP at the same time. This indicates that there is incoming
+     * data to read, but that the connection was nonetheless closed
+     * by the sender. Be sure to read the data before closing
+     * the receiver to avoid packet loss.
+     */
+
+    if (events & EPOLLIN) {
+        Packet*  p = packet_alloc();
+        int      len;
+
+        if ((len = fd_read(f->fd, p->data, MAX_PAYLOAD)) < 0) {
+            D("%s: can't recv: %s", __FUNCTION__, strerror(errno));
+            packet_free(&p);
+        } else if (len > 0) {
+            p->len     = len;
+            p->channel = -101;  /* special debug value, not used */
+            receiver_post( f->receiver, p );
+        }
+    }
+
+    if (events & (EPOLLHUP|EPOLLERR)) {
+        /* disconnection */
+        D("%s: disconnect on fd %d", __FUNCTION__, f->fd);
+        fdhandler_close(f);
+        return;
+    }
+
+    if (events & EPOLLOUT && f->out_first) {
+        Packet*  p = f->out_first;
+        int      avail, len;
+
+        avail = p->len - f->out_pos;
+        if ((len = fd_write(f->fd, p->data + f->out_pos, avail)) < 0) {
+            D("%s: can't send: %s", __FUNCTION__, strerror(errno));
+        } else {
+            f->out_pos += len;
+            if (f->out_pos >= p->len) {
+                f->out_pos   = 0;
+                f->out_first = p->next;
+                packet_free(&p);
+                if (f->out_first == NULL) {
+                    f->out_ptail = &f->out_first;
+                    looper_disable( f->list->looper, f->fd, EPOLLOUT );
+                }
+            }
+        }
+    }
+}
+
+
+/* Create a new FDHandler that monitors read/writes */
+static FDHandler*
+fdhandler_new( int             fd,
+               FDHandlerList*  list,
+               Receiver*       receiver )
+{
+    FDHandler*  f = xalloc0(sizeof(*f));
+
+    f->fd          = fd;
+    f->list        = list;
+    f->receiver[0] = receiver[0];
+    f->out_first   = NULL;
+    f->out_ptail   = &f->out_first;
+    f->out_pos     = 0;
+
+    fdhandler_prepend(f, &list->active);
+
+    looper_add( list->looper, fd, (EventFunc) fdhandler_event, f );
+    looper_enable( list->looper, fd, EPOLLIN );
+
+    return f;
+}
+
+
+/* event callback function to monitor accepts() on server sockets.
+ * the convention used here is that the receiver will receive a
+ * dummy packet with the new client socket in p->channel
+ */
+static void
+fdhandler_accept_event( FDHandler*  f, int  events )
+{
+    if (events & EPOLLIN) {
+        /* this is an accept - send a dummy packet to the receiver */
+        Packet*  p = packet_alloc();
+
+        D("%s: accepting on fd %d", __FUNCTION__, f->fd);
+        p->data[0] = 1;
+        p->len     = 1;
+        p->channel = fd_accept(f->fd);
+        if (p->channel < 0) {
+            D("%s: accept failed ?: %s", __FUNCTION__, strerror(errno));
+            packet_free(&p);
+            return;
+        }
+        receiver_post( f->receiver, p );
+    }
+
+    if (events & (EPOLLHUP|EPOLLERR)) {
+        /* disconnecting !! */
+        D("%s: closing accept fd %d", __FUNCTION__, f->fd);
+        fdhandler_close(f);
+        return;
+    }
+}
+
+
+/* Create a new FDHandler used to monitor new connections on a
+ * server socket. The receiver must expect the new connection
+ * fd in the 'channel' field of a dummy packet.
+ */
+static FDHandler*
+fdhandler_new_accept( int             fd,
+                      FDHandlerList*  list,
+                      Receiver*       receiver )
+{
+    FDHandler*  f = xalloc0(sizeof(*f));
+
+    f->fd          = fd;
+    f->list        = list;
+    f->receiver[0] = receiver[0];
+
+    fdhandler_prepend(f, &list->active);
+
+    looper_add( list->looper, fd, (EventFunc) fdhandler_accept_event, f );
+    looper_enable( list->looper, fd, EPOLLIN );
+    listen( fd, 5 );
+
+    return f;
+}
+
+/** SERIAL CONNECTION STATE
+ **
+ ** The following is used to handle the framing protocol
+ ** used on the serial port connection.
+ **/
+
+/* each packet is made of a 6 byte header followed by a payload
+ * the header looks like:
+ *
+ *   offset   size    description
+ *       0       2    a 2-byte hex string for the channel number
+ *       4       4    a 4-char hex string for the size of the payload
+ *       6       n    the payload itself
+ */
+#define  HEADER_SIZE    6
+#define  CHANNEL_OFFSET 0
+#define  LENGTH_OFFSET  2
+#define  CHANNEL_SIZE   2
+#define  LENGTH_SIZE    4
+
+#define  CHANNEL_CONTROL  0
+
+/* The Serial object receives data from the serial port,
+ * extracts the payload size and channel index, then sends
+ * the resulting messages as a packet to a generic receiver.
+ *
+ * You can also use serial_send to send a packet through
+ * the serial port.
+ */
+typedef struct Serial {
+    FDHandler*  fdhandler;   /* used to monitor serial port fd */
+    Receiver    receiver[1]; /* send payload there */
+    int         in_len;      /* current bytes in input packet */
+    int         in_datalen;  /* payload size, or 0 when reading header */
+    int         in_channel;  /* extracted channel number */
+    Packet*     in_packet;   /* used to read incoming packets */
+} Serial;
+
+
+/* a callback called when the serial port's fd is closed */
+static void
+serial_fd_close( Serial*  s )
+{
+    fatal("unexpected serial port close !!");
+}
+
+static void
+serial_dump( Packet*  p, const char*  funcname )
+{
+    T("%s: %03d bytes: '%s'",
+      funcname, p->len, quote(p->data, p->len));
+}
+
+/* a callback called when a packet arrives from the serial port's FDHandler.
+ *
+ * This will essentially parse the header, extract the channel number and
+ * the payload size and store them in 'in_datalen' and 'in_channel'.
+ *
+ * After that, the payload is sent to the receiver once completed.
+ */
+static void
+serial_fd_receive( Serial*  s, Packet*  p )
+{
+    int      rpos  = 0, rcount = p->len;
+    Packet*  inp   = s->in_packet;
+    int      inpos = s->in_len;
+
+    serial_dump( p, __FUNCTION__ );
+
+    while (rpos < rcount)
+    {
+        int  avail = rcount - rpos;
+
+        /* first, try to read the header */
+        if (s->in_datalen == 0) {
+            int  wanted = HEADER_SIZE - inpos;
+            if (avail > wanted)
+                avail = wanted;
+
+            memcpy( inp->data + inpos, p->data + rpos, avail );
+            inpos += avail;
+            rpos  += avail;
+
+            if (inpos == HEADER_SIZE) {
+                s->in_datalen = hex2int( inp->data + LENGTH_OFFSET,  LENGTH_SIZE );
+                s->in_channel = hex2int( inp->data + CHANNEL_OFFSET, CHANNEL_SIZE );
+
+                if (s->in_datalen <= 0) {
+                    D("ignoring %s packet from serial port",
+                      s->in_datalen ? "empty" : "malformed");
+                    s->in_datalen = 0;
+                }
+
+                //D("received %d bytes packet for channel %d", s->in_datalen, s->in_channel);
+                inpos = 0;
+            }
+        }
+        else /* then, populate the packet itself */
+        {
+            int   wanted = s->in_datalen - inpos;
+
+            if (avail > wanted)
+                avail = wanted;
+
+            memcpy( inp->data + inpos, p->data + rpos, avail );
+            inpos += avail;
+            rpos  += avail;
+
+            if (inpos == s->in_datalen) {
+                if (s->in_channel < 0) {
+                    D("ignoring %d bytes addressed to channel %d",
+                       inpos, s->in_channel);
+                } else {
+                    inp->len     = inpos;
+                    inp->channel = s->in_channel;
+                    receiver_post( s->receiver, inp );
+                    s->in_packet  = inp = packet_alloc();
+                }
+                s->in_datalen = 0;
+                inpos         = 0;
+            }
+        }
+    }
+    s->in_len = inpos;
+    packet_free(&p);
+}
+
+
+/* send a packet to the serial port.
+ * this assumes that p->len and p->channel contain the payload's
+ * size and channel and will add the appropriate header.
+ */
+static void
+serial_send( Serial*  s, Packet*  p )
+{
+    Packet*  h = packet_alloc();
+
+    //D("sending to serial %d bytes from channel %d: '%.*s'", p->len, p->channel, p->len, p->data);
+
+    /* insert a small header before this packet */
+    h->len = HEADER_SIZE;
+    int2hex( p->len,     h->data + LENGTH_OFFSET,  LENGTH_SIZE );
+    int2hex( p->channel, h->data + CHANNEL_OFFSET, CHANNEL_SIZE );
+
+    serial_dump( h, __FUNCTION__ );
+    serial_dump( p, __FUNCTION__ );
+
+    fdhandler_enqueue( s->fdhandler, h );
+    fdhandler_enqueue( s->fdhandler, p );
+}
+
+
+/* initialize serial reader */
+static void
+serial_init( Serial*         s,
+             int             fd,
+             FDHandlerList*  list,
+             Receiver*       receiver )
+{
+    Receiver  recv;
+
+    recv.user  = s;
+    recv.post  = (PostFunc)  serial_fd_receive;
+    recv.close = (CloseFunc) serial_fd_close;
+
+    s->receiver[0] = receiver[0];
+
+    s->fdhandler = fdhandler_new( fd, list, &recv );
+    s->in_len     = 0;
+    s->in_datalen = 0;
+    s->in_channel = 0;
+    s->in_packet  = packet_alloc();
+}
+
+
+/** CLIENTS
+ **/
+
+typedef struct Client       Client;
+typedef struct Multiplexer  Multiplexer;
+
+/* A Client object models a single qemud client socket
+ * connection in the emulated system.
+ *
+ * the client first sends the name of the system service
+ * it wants to contact (no framing), then waits for a 2
+ * byte answer from qemud.
+ *
+ * the answer is either "OK" or "KO" to indicate
+ * success or failure.
+ *
+ * In case of success, the client can send messages
+ * to the service.
+ *
+ * In case of failure, it can disconnect or try sending
+ * the name of another service.
+ */
+struct Client {
+    Client*       next;
+    Client**      pref;
+    int           channel;
+    char          registered;
+    FDHandler*    fdhandler;
+    Multiplexer*  multiplexer;
+};
+
+struct Multiplexer {
+    Client*        clients;
+    int            last_channel;
+    Serial         serial[1];
+    Looper         looper[1];
+    FDHandlerList  fdhandlers[1];
+};
+
+
+static int   multiplexer_open_channel( Multiplexer*  mult, Packet*  p );
+static void  multiplexer_close_channel( Multiplexer*  mult, int  channel );
+static void  multiplexer_serial_send( Multiplexer* mult, int  channel, Packet*  p );
+
+static void
+client_dump( Client*  c, Packet*  p, const char*  funcname )
+{
+    T("%s: client %p (%d): %3d bytes: '%s'",
+      funcname, c, c->fdhandler->fd,
+      p->len, quote(p->data, p->len));
+}
+
+/* destroy a client */
+static void
+client_free( Client*  c )
+{
+    /* remove from list */
+    c->pref[0] = c->next;
+    if (c->next)
+        c->next->pref = c->pref;
+
+    c->channel    = -1;
+    c->registered = 0;
+
+    /* gently ask the FDHandler to shutdown to
+     * avoid losing queued outgoing packets */
+    if (c->fdhandler != NULL) {
+        fdhandler_shutdown(c->fdhandler);
+        c->fdhandler = NULL;
+    }
+
+    xfree(c);
+}
+
+
+/* a function called when a client socket receives data */
+static void
+client_fd_receive( Client*  c, Packet*  p )
+{
+    client_dump(c, p, __FUNCTION__);
+
+    if (c->registered) {
+        /* the client is registered, just send the
+         * data through the serial port
+         */
+        multiplexer_serial_send(c->multiplexer, c->channel, p);
+        return;
+    }
+
+    if (c->channel > 0) {
+        /* the client is waiting registration results.
+         * this should not happen because the client
+         * should wait for our 'ok' or 'ko'.
+         * close the connection.
+         */
+         D("%s: bad client sending data before end of registration",
+           __FUNCTION__);
+     BAD_CLIENT:
+         packet_free(&p);
+         client_free(c);
+         return;
+    }
+
+    /* the client hasn't registered a service yet,
+     * so this must be the name of a service, call
+     * the multiplexer to start registration for
+     * it.
+     */
+    D("%s: attempting registration for service '%.*s'",
+      __FUNCTION__, p->len, p->data);
+    c->channel = multiplexer_open_channel(c->multiplexer, p);
+    if (c->channel < 0) {
+        D("%s: service name too long", __FUNCTION__);
+        goto BAD_CLIENT;
+    }
+    D("%s:    -> received channel id %d", __FUNCTION__, c->channel);
+    packet_free(&p);
+}
+
+
+/* a function called when the client socket is closed. */
+static void
+client_fd_close( Client*  c )
+{
+    T("%s: client %p (%d)", __FUNCTION__, c, c->fdhandler->fd);
+
+    /* no need to shutdown the FDHandler */
+    c->fdhandler = NULL;
+
+    /* tell the emulator we're out */
+    if (c->channel > 0)
+        multiplexer_close_channel(c->multiplexer, c->channel);
+
+    /* free the client */
+    client_free(c);
+}
+
+/* a function called when the multiplexer received a registration
+ * response from the emulator for a given client.
+ */
+static void
+client_registration( Client*  c, int  registered )
+{
+    Packet*  p = packet_alloc();
+
+    /* sends registration status to client */
+    if (!registered) {
+        D("%s: registration failed for client %d", __FUNCTION__, c->channel);
+        memcpy( p->data, "KO", 2 );
+        p->len = 2;
+    } else {
+        D("%s: registration succeeded for client %d", __FUNCTION__, c->channel);
+        memcpy( p->data, "OK", 2 );
+        p->len = 2;
+    }
+    client_dump(c, p, __FUNCTION__);
+    fdhandler_enqueue(c->fdhandler, p);
+
+    /* now save registration state
+     */
+    c->registered = registered;
+    if (!registered) {
+        /* allow the client to try registering another service */
+        c->channel = -1;
+    }
+}
+
+/* send data to a client */
+static void
+client_send( Client*  c, Packet*  p )
+{
+    client_dump(c, p, __FUNCTION__);
+    fdhandler_enqueue(c->fdhandler, p);
+}
+
+
+/* Create new client socket handler */
+static Client*
+client_new( Multiplexer*    mult,
+            int             fd,
+            FDHandlerList*  pfdhandlers,
+            Client**        pclients )
+{
+    Client*   c;
+    Receiver  recv;
+
+    xnew(c);
+
+    c->multiplexer = mult;
+    c->next        = NULL;
+    c->pref        = &c->next;
+    c->channel     = -1;
+    c->registered  = 0;
+
+    recv.user  = c;
+    recv.post  = (PostFunc)  client_fd_receive;
+    recv.close = (CloseFunc) client_fd_close;
+
+    c->fdhandler = fdhandler_new( fd, pfdhandlers, &recv );
+
+    /* add to client list */
+    c->next   = *pclients;
+    c->pref   = pclients;
+    *pclients = c;
+    if (c->next)
+        c->next->pref = &c->next;
+
+    return c;
+}
+
+/**  GLOBAL MULTIPLEXER
+ **/
+
+/* find a client by its channel */
+static Client*
+multiplexer_find_client( Multiplexer*  mult, int  channel )
+{
+    Client* c = mult->clients;
+
+    for ( ; c != NULL; c = c->next ) {
+        if (c->channel == channel)
+            return c;
+    }
+    return NULL;
+}
+
+/* handle control messages coming from the serial port
+ * on CONTROL_CHANNEL.
+ */
+static void
+multiplexer_handle_control( Multiplexer*  mult, Packet*  p )
+{
+    /* connection registration success */
+    if (p->len == 13 && !memcmp(p->data, "ok:connect:", 11)) {
+        int      channel = hex2int(p->data+11, 2);
+        Client*  client  = multiplexer_find_client(mult, channel);
+
+        /* note that 'client' can be NULL if the corresponding
+         * socket was closed before the emulator response arrived.
+         */
+        if (client != NULL) {
+            client_registration(client, 1);
+        } else {
+            D("%s: NULL client: '%.*s'", __FUNCTION__, p->len, p->data+11);
+        }
+        goto EXIT;
+    }
+
+    /* connection registration failure */
+    if (p->len == 13 && !memcmp(p->data, "ko:connect:",11)) {
+        int     channel = hex2int(p->data+11, 2);
+        Client* client  = multiplexer_find_client(mult, channel);
+
+        if (client != NULL)
+            client_registration(client, 0);
+
+        goto EXIT;
+    }
+
+    /* emulator-induced client disconnection */
+    if (p->len == 13 && !memcmp(p->data, "disconnect:",11)) {
+        int      channel = hex2int(p->data+11, 2);
+        Client*  client  = multiplexer_find_client(mult, channel);
+
+        if (client != NULL)
+            client_free(client);
+
+        goto EXIT;
+    }
+
+    /* A message that begins with "X00" is a probe sent by
+     * the emulator used to detect which version of qemud it runs
+     * against (in order to detect 1.0/1.1 system images. Just
+     * silently ignore it there instead of printing an error
+     * message.
+     */
+    if (p->len >= 3 && !memcmp(p->data,"X00",3)) {
+        goto EXIT;
+    }
+
+    D("%s: unknown control message (%d bytes): '%.*s'",
+      __FUNCTION__, p->len, p->len, p->data);
+
+EXIT:
+    packet_free(&p);
+}
+
+/* a function called when an incoming packet comes from the serial port */
+static void
+multiplexer_serial_receive( Multiplexer*  mult, Packet*  p )
+{
+    Client*  client;
+
+    T("%s: channel=%d '%.*s'", __FUNCTION__, p->channel, p->len, p->data);
+
+    if (p->channel == CHANNEL_CONTROL) {
+        multiplexer_handle_control(mult, p);
+        return;
+    }
+
+    client = multiplexer_find_client(mult, p->channel);
+    if (client != NULL) {
+        client_send(client, p);
+        return;
+    }
+
+    D("%s: discarding packet for unknown channel %d", __FUNCTION__, p->channel);
+    packet_free(&p);
+}
+
+/* a function called when the serial reader closes */
+static void
+multiplexer_serial_close( Multiplexer*  mult )
+{
+    fatal("unexpected close of serial reader");
+}
+
+/* a function called to send a packet to the serial port */
+static void
+multiplexer_serial_send( Multiplexer*  mult, int  channel, Packet*  p )
+{
+    p->channel = channel;
+    serial_send( mult->serial, p );
+}
+
+
+
+/* a function used by a client to allocate a new channel id and
+ * ask the emulator to open it. 'service' must be a packet containing
+ * the name of the service in its payload.
+ *
+ * returns -1 if the service name is too long.
+ *
+ * notice that client_registration() will be called later when
+ * the answer arrives.
+ */
+static int
+multiplexer_open_channel( Multiplexer*  mult, Packet*  service )
+{
+    Packet*   p = packet_alloc();
+    int       len, channel;
+
+    /* find a free channel number, assume we don't have many
+     * clients here. */
+    {
+        Client*  c;
+    TRY_AGAIN:
+        channel = (++mult->last_channel) & 0xff;
+
+        for (c = mult->clients; c != NULL; c = c->next)
+            if (c->channel == channel)
+                goto TRY_AGAIN;
+    }
+
+    len = snprintf((char*)p->data, sizeof p->data, "connect:%.*s:%02x", service->len, service->data, channel);
+    if (len >= (int)sizeof(p->data)) {
+        D("%s: weird, service name too long (%d > %d)", __FUNCTION__, len, sizeof(p->data));
+        packet_free(&p);
+        return -1;
+    }
+    p->channel = CHANNEL_CONTROL;
+    p->len     = len;
+
+    serial_send(mult->serial, p);
+    return channel;
+}
+
+/* used to tell the emulator a channel was closed by a client */
+static void
+multiplexer_close_channel( Multiplexer*  mult, int  channel )
+{
+    Packet*  p   = packet_alloc();
+    int      len = snprintf((char*)p->data, sizeof(p->data), "disconnect:%02x", channel);
+
+    if (len > (int)sizeof(p->data)) {
+        /* should not happen */
+        return;
+    }
+
+    p->channel = CHANNEL_CONTROL;
+    p->len     = len;
+
+    serial_send(mult->serial, p);
+}
+
+/* this function is used when a new connection happens on the control
+ * socket.
+ */
+static void
+multiplexer_control_accept( Multiplexer*  m, Packet*  p )
+{
+    /* the file descriptor for the new socket connection is
+     * in p->channel. See fdhandler_accept_event() */
+    int      fd     = p->channel;
+    Client*  client = client_new( m, fd, m->fdhandlers, &m->clients );
+
+    D("created client %p listening on fd %d", client, fd);
+
+    /* free dummy packet */
+    packet_free(&p);
+}
+
+static void
+multiplexer_control_close( Multiplexer*  m )
+{
+    fatal("unexpected multiplexer control close");
+}
+
+static void
+multiplexer_init( Multiplexer*  m, const char*  serial_dev )
+{
+    int       fd, control_fd;
+    Receiver  recv;
+
+    /* initialize looper and fdhandlers list */
+    looper_init( m->looper );
+    fdhandler_list_init( m->fdhandlers, m->looper );
+
+    /* open the serial port */
+    do {
+        fd = open(serial_dev, O_RDWR);
+    } while (fd < 0 && errno == EINTR);
+
+    if (fd < 0) {
+        fatal( "%s: could not open '%s': %s", __FUNCTION__, serial_dev,
+               strerror(errno) );
+    }
+    // disable echo on serial lines
+    if ( !memcmp( serial_dev, "/dev/ttyS", 9 ) ) {
+        struct termios  ios;
+        tcgetattr( fd, &ios );
+        ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
+        tcsetattr( fd, TCSANOW, &ios );
+    }
+
+    /* initialize the serial reader/writer */
+    recv.user  = m;
+    recv.post  = (PostFunc)  multiplexer_serial_receive;
+    recv.close = (CloseFunc) multiplexer_serial_close;
+
+    serial_init( m->serial, fd, m->fdhandlers, &recv );
+
+    /* open the qemud control socket */
+    recv.user  = m;
+    recv.post  = (PostFunc)  multiplexer_control_accept;
+    recv.close = (CloseFunc) multiplexer_control_close;
+
+    fd = android_get_control_socket(CONTROL_SOCKET_NAME);
+    if (fd < 0) {
+        fatal("couldn't get fd for control socket '%s'", CONTROL_SOCKET_NAME);
+    }
+
+    fdhandler_new_accept( fd, m->fdhandlers, &recv );
+
+    /* initialize clients list */
+    m->clients = NULL;
+}
+
+/** MAIN LOOP
+ **/
+
+static Multiplexer  _multiplexer[1];
+
+int  main( void )
+{
+    Multiplexer*  m = _multiplexer;
+
+   /* extract the name of our serial device from the kernel
+    * boot options that are stored in /proc/cmdline
+    */
+#define  KERNEL_OPTION  "android.qemud="
+
+    {
+        char          buff[1024];
+        int           fd, len;
+        char*         p;
+        char*         q;
+
+        fd = open( "/proc/cmdline", O_RDONLY );
+        if (fd < 0) {
+            D("%s: can't open /proc/cmdline !!: %s", __FUNCTION__,
+            strerror(errno));
+            exit(1);
+        }
+
+        len = fd_read( fd, buff, sizeof(buff)-1 );
+        close(fd);
+        if (len < 0) {
+            D("%s: can't read /proc/cmdline: %s", __FUNCTION__,
+            strerror(errno));
+            exit(1);
+        }
+        buff[len] = 0;
+
+        p = strstr( buff, KERNEL_OPTION );
+        if (p == NULL) {
+            D("%s: can't find '%s' in /proc/cmdline",
+            __FUNCTION__, KERNEL_OPTION );
+            exit(1);
+        }
+
+        p += sizeof(KERNEL_OPTION)-1;  /* skip option */
+        q  = p;
+        while ( *q && *q != ' ' && *q != '\t' )
+            q += 1;
+
+        snprintf( buff, sizeof(buff), "/dev/%.*s", q-p, p );
+
+        multiplexer_init( m, buff );
+    }
+
+    D( "entering main loop");
+    looper_loop( m->looper );
+    D( "unexpected termination !!" );
+    return 0;
+}
diff --git a/tools/emulator/system/sensors/Android.mk b/tools/emulator/system/sensors/Android.mk
new file mode 100644
index 0000000..9b0e83d
--- /dev/null
+++ b/tools/emulator/system/sensors/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# We're moving the emulator-specific platform libs to
+# development.git/tools/emulator/. The following test is to ensure
+# smooth builds even if the tree contains both versions.
+#
+ifndef BUILD_EMULATOR_SENSORS_MODULE
+BUILD_EMULATOR_SENSORS_MODULE := true
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_PRODUCT),sim)
+# HAL module implemenation, not prelinked and stored in
+# hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.hardware>.so
+include $(CLEAR_VARS)
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_SRC_FILES := sensors_qemu.c
+LOCAL_MODULE := sensors.goldfish
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_SHARED_LIBRARY)
+endif
+
+endif # BUILD_EMULATOR_SENSORS_MODULE
diff --git a/tools/emulator/system/sensors/sensors_qemu.c b/tools/emulator/system/sensors/sensors_qemu.c
new file mode 100644
index 0000000..9a776c7
--- /dev/null
+++ b/tools/emulator/system/sensors/sensors_qemu.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* this implements a sensors hardware library for the Android emulator.
+ * the following code should be built as a shared library that will be
+ * placed into /system/lib/hw/sensors.goldfish.so
+ *
+ * it will be loaded by the code in hardware/libhardware/hardware.c
+ * which is itself called from com_android_server_SensorService.cpp
+ */
+
+
+/* we connect with the emulator through the "sensors" qemud service
+ */
+#define  SENSORS_SERVICE_NAME "sensors"
+
+#define LOG_TAG "QemuSensors"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <cutils/log.h>
+#include <cutils/native_handle.h>
+#include <cutils/sockets.h>
+#include <hardware/sensors.h>
+
+#if 0
+#define  D(...)  LOGD(__VA_ARGS__)
+#else
+#define  D(...)  ((void)0)
+#endif
+
+#define  E(...)  LOGE(__VA_ARGS__)
+
+#include <hardware/qemud.h>
+
+/** SENSOR IDS AND NAMES
+ **/
+
+#define MAX_NUM_SENSORS 5
+
+#define SUPPORTED_SENSORS  ((1<<MAX_NUM_SENSORS)-1)
+
+#define  ID_BASE           SENSORS_HANDLE_BASE
+#define  ID_ACCELERATION   (ID_BASE+0)
+#define  ID_MAGNETIC_FIELD (ID_BASE+1)
+#define  ID_ORIENTATION    (ID_BASE+2)
+#define  ID_TEMPERATURE    (ID_BASE+3)
+#define  ID_PROXIMITY      (ID_BASE+4)
+
+#define  SENSORS_ACCELERATION   (1 << ID_ACCELERATION)
+#define  SENSORS_MAGNETIC_FIELD  (1 << ID_MAGNETIC_FIELD)
+#define  SENSORS_ORIENTATION     (1 << ID_ORIENTATION)
+#define  SENSORS_TEMPERATURE     (1 << ID_TEMPERATURE)
+#define  SENSORS_PROXIMITY       (1 << ID_PROXIMITY)
+
+#define  ID_CHECK(x)  ((unsigned)((x)-ID_BASE) < MAX_NUM_SENSORS)
+
+#define  SENSORS_LIST  \
+    SENSOR_(ACCELERATION,"acceleration") \
+    SENSOR_(MAGNETIC_FIELD,"magnetic-field") \
+    SENSOR_(ORIENTATION,"orientation") \
+    SENSOR_(TEMPERATURE,"temperature") \
+    SENSOR_(PROXIMITY,"proximity") \
+
+static const struct {
+    const char*  name;
+    int          id; } _sensorIds[MAX_NUM_SENSORS] =
+{
+#define SENSOR_(x,y)  { y, ID_##x },
+    SENSORS_LIST
+#undef  SENSOR_
+};
+
+static const char*
+_sensorIdToName( int  id )
+{
+    int  nn;
+    for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
+        if (id == _sensorIds[nn].id)
+            return _sensorIds[nn].name;
+    return "<UNKNOWN>";
+}
+
+static int
+_sensorIdFromName( const char*  name )
+{
+    int  nn;
+
+    if (name == NULL)
+        return -1;
+
+    for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
+        if (!strcmp(name, _sensorIds[nn].name))
+            return _sensorIds[nn].id;
+
+    return -1;
+}
+
+/** SENSORS POLL DEVICE
+ **
+ ** This one is used to read sensor data from the hardware.
+ ** We implement this by simply reading the data from the
+ ** emulator through the QEMUD channel.
+ **/
+
+typedef struct SensorPoll {
+    struct sensors_poll_device_t  device;
+    sensors_event_t               sensors[MAX_NUM_SENSORS];
+    int                           events_fd;
+    uint32_t                      pendingSensors;
+    int64_t                       timeStart;
+    int64_t                       timeOffset;
+    int                           fd;
+    uint32_t                      active_sensors;
+} SensorPoll;
+
+/* this must return a file descriptor that will be used to read
+ * the sensors data (it is passed to data__data_open() below
+ */
+static native_handle_t*
+control__open_data_source(struct sensors_poll_device_t *dev)
+{
+    SensorPoll*  ctl = (void*)dev;
+    native_handle_t* handle;
+
+    if (ctl->fd < 0) {
+        ctl->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
+    }
+    D("%s: fd=%d", __FUNCTION__, ctl->fd);
+    handle = native_handle_create(1, 0);
+    handle->data[0] = dup(ctl->fd);
+    return handle;
+}
+
+static int
+control__activate(struct sensors_poll_device_t *dev,
+                  int handle,
+                  int enabled)
+{
+    SensorPoll*     ctl = (void*)dev;
+    uint32_t        mask, sensors, active, new_sensors, changed;
+    char            command[128];
+    int             ret;
+
+    D("%s: handle=%s (%d) fd=%d enabled=%d", __FUNCTION__,
+        _sensorIdToName(handle), handle, ctl->fd, enabled);
+
+    if (!ID_CHECK(handle)) {
+        E("%s: bad handle ID", __FUNCTION__);
+        return -1;
+    }
+
+    mask    = (1<<handle);
+    sensors = enabled ? mask : 0;
+
+    active      = ctl->active_sensors;
+    new_sensors = (active & ~mask) | (sensors & mask);
+    changed     = active ^ new_sensors;
+
+    if (!changed)
+        return 0;
+
+    snprintf(command, sizeof command, "set:%s:%d",
+                _sensorIdToName(handle), enabled != 0);
+
+    if (ctl->fd < 0) {
+        ctl->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
+    }
+
+    ret = qemud_channel_send(ctl->fd, command, -1);
+    if (ret < 0) {
+        E("%s: when sending command errno=%d: %s", __FUNCTION__, errno, strerror(errno));
+        return -1;
+    }
+    ctl->active_sensors = new_sensors;
+
+    return 0;
+}
+
+static int
+control__set_delay(struct sensors_poll_device_t *dev, int32_t ms)
+{
+    SensorPoll*     ctl = (void*)dev;
+    char            command[128];
+
+    D("%s: dev=%p delay-ms=%d", __FUNCTION__, dev, ms);
+
+    snprintf(command, sizeof command, "set-delay:%d", ms);
+
+    return qemud_channel_send(ctl->fd, command, -1);
+}
+
+static int
+control__close(struct hw_device_t *dev) 
+{
+    SensorPoll*  ctl = (void*)dev;
+    close(ctl->fd);
+    free(ctl);
+    return 0;
+}
+
+/* return the current time in nanoseconds */
+static int64_t
+data__now_ns(void)
+{
+    struct timespec  ts;
+
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+
+    return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
+
+static int
+data__data_open(struct sensors_poll_device_t *dev, native_handle_t* handle)
+{
+    SensorPoll*  data = (void*)dev;
+    int i;
+    D("%s: dev=%p fd=%d", __FUNCTION__, dev, handle->data[0]);
+    memset(&data->sensors, 0, sizeof(data->sensors));
+
+    for (i=0 ; i<MAX_NUM_SENSORS ; i++) {
+        data->sensors[i].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
+    }
+    data->pendingSensors = 0;
+    data->timeStart      = 0;
+    data->timeOffset     = 0;
+
+    data->events_fd = dup(handle->data[0]);
+    D("%s: dev=%p fd=%d (was %d)", __FUNCTION__, dev, data->events_fd, handle->data[0]);
+    native_handle_close(handle);
+    native_handle_delete(handle);
+    return 0;
+}
+
+static int
+data__data_close(struct sensors_poll_device_t *dev)
+{
+    SensorPoll*  data = (void*)dev;
+    D("%s: dev=%p", __FUNCTION__, dev);
+    if (data->events_fd >= 0) {
+        close(data->events_fd);
+        data->events_fd = -1;
+    }
+    return 0;
+}
+
+static int
+pick_sensor(SensorPoll*       data,
+            sensors_event_t*  values)
+{
+    uint32_t mask = SUPPORTED_SENSORS;
+    while (mask) {
+        uint32_t i = 31 - __builtin_clz(mask);
+        mask &= ~(1<<i);
+        if (data->pendingSensors & (1<<i)) {
+            data->pendingSensors &= ~(1<<i);
+            *values = data->sensors[i];
+            values->sensor = i;
+            values->version = sizeof(*values);
+
+            D("%s: %d [%f, %f, %f]", __FUNCTION__,
+                    i,
+                    values->data[0],
+                    values->data[1],
+                    values->data[2]);
+            return i;
+        }
+    }
+    LOGE("No sensor to return!!! pendingSensors=%08x", data->pendingSensors);
+    // we may end-up in a busy loop, slow things down, just in case.
+    usleep(100000);
+    return -EINVAL;
+}
+
+static int
+data__poll(struct sensors_poll_device_t *dev, sensors_event_t* values)
+{
+    SensorPoll*  data = (void*)dev;
+    int fd = data->events_fd;
+
+    D("%s: data=%p", __FUNCTION__, dev);
+
+    // there are pending sensors, returns them now...
+    if (data->pendingSensors) {
+        return pick_sensor(data, values);
+    }
+
+    // wait until we get a complete event for an enabled sensor
+    uint32_t new_sensors = 0;
+
+    while (1) {
+        /* read the next event */
+        char     buff[256];
+        int      len = qemud_channel_recv(data->events_fd, buff, sizeof buff-1);
+        float    params[3];
+        int64_t  event_time;
+
+        if (len < 0) {
+            E("%s: len=%d, errno=%d: %s", __FUNCTION__, len, errno, strerror(errno));
+            return -errno;
+        }
+
+        buff[len] = 0;
+
+        /* "wake" is sent from the emulator to exit this loop. */
+        if (!strcmp((const char*)data, "wake")) {
+            return 0x7FFFFFFF;
+        }
+
+        /* "acceleration:<x>:<y>:<z>" corresponds to an acceleration event */
+        if (sscanf(buff, "acceleration:%g:%g:%g", params+0, params+1, params+2) == 3) {
+            new_sensors |= SENSORS_ACCELERATION;
+            data->sensors[ID_ACCELERATION].acceleration.x = params[0];
+            data->sensors[ID_ACCELERATION].acceleration.y = params[1];
+            data->sensors[ID_ACCELERATION].acceleration.z = params[2];
+            continue;
+        }
+
+        /* "orientation:<azimuth>:<pitch>:<roll>" is sent when orientation changes */
+        if (sscanf(buff, "orientation:%g:%g:%g", params+0, params+1, params+2) == 3) {
+            new_sensors |= SENSORS_ORIENTATION;
+            data->sensors[ID_ORIENTATION].orientation.azimuth = params[0];
+            data->sensors[ID_ORIENTATION].orientation.pitch   = params[1];
+            data->sensors[ID_ORIENTATION].orientation.roll    = params[2];
+            continue;
+        }
+
+        /* "magnetic:<x>:<y>:<z>" is sent for the params of the magnetic field */
+        if (sscanf(buff, "magnetic:%g:%g:%g", params+0, params+1, params+2) == 3) {
+            new_sensors |= SENSORS_MAGNETIC_FIELD;
+            data->sensors[ID_MAGNETIC_FIELD].magnetic.x = params[0];
+            data->sensors[ID_MAGNETIC_FIELD].magnetic.y = params[1];
+            data->sensors[ID_MAGNETIC_FIELD].magnetic.z = params[2];
+            continue;
+        }
+
+        /* "temperature:<celsius>" */
+        if (sscanf(buff, "temperature:%g", params+0) == 2) {
+            new_sensors |= SENSORS_TEMPERATURE;
+            data->sensors[ID_TEMPERATURE].temperature = params[0];
+            continue;
+        }
+
+        /* "proximity:<value>" */
+        if (sscanf(buff, "proximity:%g", params+0) == 1) {
+            new_sensors |= SENSORS_PROXIMITY;
+            data->sensors[ID_PROXIMITY].distance = params[0];
+            continue;
+        }
+
+        /* "sync:<time>" is sent after a series of sensor events.
+         * where 'time' is expressed in micro-seconds and corresponds
+         * to the VM time when the real poll occured.
+         */
+        if (sscanf(buff, "sync:%lld", &event_time) == 1) {
+            if (new_sensors) {
+                data->pendingSensors = new_sensors;
+                int64_t t = event_time * 1000LL;  /* convert to nano-seconds */
+
+                /* use the time at the first sync: as the base for later
+                 * time values */
+                if (data->timeStart == 0) {
+                    data->timeStart  = data__now_ns();
+                    data->timeOffset = data->timeStart - t;
+                }
+                t += data->timeOffset;
+
+                while (new_sensors) {
+                    uint32_t i = 31 - __builtin_clz(new_sensors);
+                    new_sensors &= ~(1<<i);
+                    data->sensors[i].timestamp = t;
+                }
+                return pick_sensor(data, values);
+            } else {
+                D("huh ? sync without any sensor data ?");
+            }
+            continue;
+        }
+        D("huh ? unsupported command");
+    }
+    return -1;
+}
+
+static int
+data__close(struct hw_device_t *dev) 
+{
+    SensorPoll* data = (SensorPoll*)dev;
+    if (data) {
+        if (data->events_fd >= 0) {
+            //LOGD("(device close) about to close fd=%d", data->events_fd);
+            close(data->events_fd);
+        }
+        free(data);
+    }
+    return 0;
+}
+
+/** SENSORS POLL DEVICE FUNCTIONS **/
+
+static int poll__close(struct hw_device_t* dev)
+{
+    SensorPoll*  ctl = (void*)dev;
+    close(ctl->fd);
+    if (ctl->fd >= 0) {
+        close(ctl->fd);
+    }
+    if (ctl->events_fd >= 0) {
+        close(ctl->events_fd);
+    }
+    free(ctl);
+    return 0;
+}
+
+static int poll__poll(struct sensors_poll_device_t *dev,
+            sensors_event_t* data, int count)
+{
+    SensorPoll*  datadev = (void*)dev;
+    int ret;
+    int i;
+    D("%s: dev=%p data=%p count=%d ", __FUNCTION__, dev, data, count);
+
+    for (i = 0; i < count; i++)  {
+        ret = data__poll(dev, data);
+        data++;
+        if (ret > MAX_NUM_SENSORS || ret < 0) {
+           return i;
+        }
+        if (!datadev->pendingSensors) {
+           return i + 1;
+        }
+    }
+    return count;
+}
+
+static int poll__activate(struct sensors_poll_device_t *dev,
+            int handle, int enabled)
+{
+    int ret;
+    native_handle_t* hdl;
+    SensorPoll*  ctl = (void*)dev;
+    D("%s: dev=%p handle=%x enable=%d ", __FUNCTION__, dev, handle, enabled);
+    if (ctl->fd < 0) {
+        D("%s: OPEN CTRL and DATA ", __FUNCTION__);
+        hdl = control__open_data_source(dev);
+        ret = data__data_open(dev,hdl);
+    }
+    ret = control__activate(dev, handle, enabled);
+    return ret;
+}
+
+static int poll__setDelay(struct sensors_poll_device_t *dev,
+            int handle, int64_t ns)
+{
+    // TODO
+    return 0;
+}
+
+/** MODULE REGISTRATION SUPPORT
+ **
+ ** This is required so that hardware/libhardware/hardware.c
+ ** will dlopen() this library appropriately.
+ **/
+
+/*
+ * the following is the list of all supported sensors.
+ * this table is used to build sSensorList declared below
+ * according to which hardware sensors are reported as
+ * available from the emulator (see get_sensors_list below)
+ *
+ * note: numerical values for maxRange/resolution/power were
+ *       taken from the reference AK8976A implementation
+ */
+static const struct sensor_t sSensorListInit[] = {
+        { .name       = "Goldfish 3-axis Accelerometer",
+          .vendor     = "The Android Open Source Project",
+          .version    = 1,
+          .handle     = ID_ACCELERATION,
+          .type       = SENSOR_TYPE_ACCELEROMETER,
+          .maxRange   = 2.8f,
+          .resolution = 1.0f/4032.0f,
+          .power      = 3.0f,
+          .reserved   = {}
+        },
+
+        { .name       = "Goldfish 3-axis Magnetic field sensor",
+          .vendor     = "The Android Open Source Project",
+          .version    = 1,
+          .handle     = ID_MAGNETIC_FIELD,
+          .type       = SENSOR_TYPE_MAGNETIC_FIELD,
+          .maxRange   = 2000.0f,
+          .resolution = 1.0f,
+          .power      = 6.7f,
+          .reserved   = {}
+        },
+
+        { .name       = "Goldfish Orientation sensor",
+          .vendor     = "The Android Open Source Project",
+          .version    = 1,
+          .handle     = ID_ORIENTATION,
+          .type       = SENSOR_TYPE_ORIENTATION,
+          .maxRange   = 360.0f,
+          .resolution = 1.0f,
+          .power      = 9.7f,
+          .reserved   = {}
+        },
+
+        { .name       = "Goldfish Temperature sensor",
+          .vendor     = "The Android Open Source Project",
+          .version    = 1,
+          .handle     = ID_TEMPERATURE,
+          .type       = SENSOR_TYPE_TEMPERATURE,
+          .maxRange   = 80.0f,
+          .resolution = 1.0f,
+          .power      = 0.0f,
+          .reserved   = {}
+        },
+
+        { .name       = "Goldfish Proximity sensor",
+          .vendor     = "The Android Open Source Project",
+          .version    = 1,
+          .handle     = ID_PROXIMITY,
+          .type       = SENSOR_TYPE_PROXIMITY,
+          .maxRange   = 1.0f,
+          .resolution = 1.0f,
+          .power      = 20.0f,
+          .reserved   = {}
+        },
+};
+
+static struct sensor_t  sSensorList[MAX_NUM_SENSORS];
+
+static int sensors__get_sensors_list(struct sensors_module_t* module,
+        struct sensor_t const** list) 
+{
+    int  fd = qemud_channel_open(SENSORS_SERVICE_NAME);
+    char buffer[12];
+    int  mask, nn, count;
+
+    int  ret;
+    if (fd < 0) {
+        E("%s: no qemud connection", __FUNCTION__);
+        return 0;
+    }
+    ret = qemud_channel_send(fd, "list-sensors", -1);
+    if (ret < 0) {
+        E("%s: could not query sensor list: %s", __FUNCTION__,
+          strerror(errno));
+        close(fd);
+        return 0;
+    }
+    ret = qemud_channel_recv(fd, buffer, sizeof buffer-1);
+    if (ret < 0) {
+        E("%s: could not receive sensor list: %s", __FUNCTION__,
+          strerror(errno));
+        close(fd);
+        return 0;
+    }
+    buffer[ret] = 0;
+    close(fd);
+
+    /* the result is a integer used as a mask for available sensors */
+    mask  = atoi(buffer);
+    count = 0;
+    for (nn = 0; nn < MAX_NUM_SENSORS; nn++) {
+        if (((1 << nn) & mask) == 0)
+            continue;
+
+        sSensorList[count++] = sSensorListInit[nn];
+    }
+    D("%s: returned %d sensors (mask=%d)", __FUNCTION__, count, mask);
+    *list = sSensorList;
+    return count;
+}
+
+
+static int
+open_sensors(const struct hw_module_t* module,
+             const char*               name,
+             struct hw_device_t*      *device)
+{
+    int  status = -EINVAL;
+
+    D("%s: name=%s", __FUNCTION__, name);
+
+    if (!strcmp(name, SENSORS_HARDWARE_POLL)) {
+        SensorPoll *dev = malloc(sizeof(*dev));
+
+        memset(dev, 0, sizeof(*dev));
+
+        dev->device.common.tag     = HARDWARE_DEVICE_TAG;
+        dev->device.common.version = 0;
+        dev->device.common.module  = (struct hw_module_t*) module;
+        dev->device.common.close   = poll__close;
+        dev->device.poll           = poll__poll;
+        dev->device.activate       = poll__activate;
+        dev->device.setDelay       = poll__setDelay;
+        dev->events_fd             = -1;
+        dev->fd                    = -1;
+
+        *device = &dev->device.common;
+        status  = 0;
+    }
+    return status;
+}
+
+
+static struct hw_module_methods_t sensors_module_methods = {
+    .open = open_sensors
+};
+
+const struct sensors_module_t HAL_MODULE_INFO_SYM = {
+    .common = {
+        .tag = HARDWARE_MODULE_TAG,
+        .version_major = 1,
+        .version_minor = 0,
+        .id = SENSORS_HARDWARE_MODULE_ID,
+        .name = "Goldfish SENSORS Module",
+        .author = "The Android Open Source Project",
+        .methods = &sensors_module_methods,
+    },
+    .get_sensors_list = sensors__get_sensors_list
+};