Merge "Fix mainDexClasses with obfuscation."
diff --git a/unit-tests/Android.mk b/unit-tests/Android.mk
index 62b666a..1e14c08 100644
--- a/unit-tests/Android.mk
+++ b/unit-tests/Android.mk
@@ -17,7 +17,6 @@
 LOCAL_PATH := $(call my-dir)
 
 test_module = dalvik-vm-unit-tests
-test_tags = eng tests
 
 test_src_files = \
     dvmHumanReadableDescriptor_test.cpp \
@@ -32,7 +31,6 @@
 LOCAL_CFLAGS += -DANDROID_SMP=1
 LOCAL_C_INCLUDES += $(test_c_includes)
 LOCAL_MODULE := $(test_module)
-LOCAL_MODULE_TAGS := $(test_tags)
 LOCAL_SRC_FILES := $(test_src_files)
 LOCAL_SHARED_LIBRARIES += libcutils libdvm
 include $(BUILD_NATIVE_TEST)
@@ -43,7 +41,6 @@
 #include $(CLEAR_VARS)
 #LOCAL_C_INCLUDES += $(test_c_includes)
 #LOCAL_MODULE := $(test_module)
-#LOCAL_MODULE_TAGS := $(test_tags)
 #LOCAL_SRC_FILES := $(test_src_files)
 #LOCAL_SHARED_LIBRARIES += libdvm libcrypto libssl libicuuc libicui18n
 #LOCAL_WHOLE_STATIC_LIBRARIES += libcutils liblog libdvm
diff --git a/vm/Android.mk b/vm/Android.mk
index 1c1f91a..909190c 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -53,7 +53,7 @@
 # Define WITH_ADDRESS_SANITIZER to build an ASan-instrumented version of the
 # library in /system/lib/asan/libdvm.so.
 ifneq ($(strip $(WITH_ADDRESS_SANITIZER)),)
-    LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/asan
+    LOCAL_MODULE_RELATIVE_PATH := asan
     LOCAL_ADDRESS_SANITIZER := true
     LOCAL_CFLAGS := $(filter-out $(CLANG_CONFIG_UNKNOWN_CFLAGS),$(LOCAL_CFLAGS))
 endif
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index fe700de..cad61d1 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -28,6 +28,7 @@
 LOCAL_CFLAGS += -fstrict-aliasing -Wstrict-aliasing=2
 LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter -Wno-unused-but-set-variable
 LOCAL_CFLAGS += -DARCH_VARIANT=\"$(dvm_arch_variant)\"
+LOCAL_CFLAGS += -D__STDC_LIMIT_MACROS
 
 ifneq ($(strip $(LOCAL_CLANG)),true)
 LOCAL_CFLAGS += -fno-align-jumps
diff --git a/vm/Init.cpp b/vm/Init.cpp
index 136e1cb..ccd5115 100644
--- a/vm/Init.cpp
+++ b/vm/Init.cpp
@@ -17,7 +17,6 @@
 /*
  * Dalvik initialization, shutdown, and command-line argument processing.
  */
-#define __STDC_LIMIT_MACROS
 #include <stdlib.h>
 #include <stdio.h>
 #include <signal.h>
diff --git a/vm/alloc/HeapSource.cpp b/vm/alloc/HeapSource.cpp
index 22de1b5..ad12a2f 100644
--- a/vm/alloc/HeapSource.cpp
+++ b/vm/alloc/HeapSource.cpp
@@ -19,8 +19,6 @@
 #include <errno.h>
 #include <cutils/ashmem.h>
 
-#define SIZE_MAX UINT_MAX  // TODO: get SIZE_MAX from stdint.h
-
 #include "Dalvik.h"
 #include "alloc/DlMalloc.h"
 #include "alloc/Heap.h"
@@ -402,7 +400,7 @@
     ALOGE("Unable to create an ashmem region for the new heap");
     return false;
   }
-  void* addr = mmap(newHeapBase, rem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+  void* addr = mmap(newHeapBase, rem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0);
   int ret = close(fd);
   if (addr == MAP_FAILED) {
     ALOGE("Unable to map an ashmem region for the new heap");
diff --git a/vm/compiler/Compiler.cpp b/vm/compiler/Compiler.cpp
index 04d6456..1ebc2d1 100644
--- a/vm/compiler/Compiler.cpp
+++ b/vm/compiler/Compiler.cpp
@@ -212,7 +212,7 @@
 
     /* Only flush the part in the code cache that is being used now */
     dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
-                          (intptr_t) gDvmJit.codeCache + templateSize, 0);
+                          (intptr_t) gDvmJit.codeCache + templateSize);
 #else
     gDvmJit.codeCacheByteUsed = 0;
     stream = (char*)gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
@@ -332,8 +332,7 @@
                           gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
 
     dvmCompilerCacheFlush((intptr_t) gDvmJit.codeCache,
-                          (intptr_t) gDvmJit.codeCache +
-                          gDvmJit.codeCacheByteUsed, 0);
+                          (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
 
     PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
 
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
index faca03d..a06192d 100644
--- a/vm/compiler/CompilerUtility.h
+++ b/vm/compiler/CompilerUtility.h
@@ -73,7 +73,7 @@
 void dvmDumpBlockBitVector(const GrowableList *blocks, char *msg,
                            const BitVector *bv, int length);
 void dvmGetBlockName(struct BasicBlock *bb, char *name);
-void dvmCompilerCacheFlush(long start, long end, long flags);
+void dvmCompilerCacheFlush(uintptr_t start, uintptr_t end);
 void dvmCompilerCacheClear(char *start, size_t size);
 
 
diff --git a/vm/compiler/Frontend.cpp b/vm/compiler/Frontend.cpp
index 916915d..47c1898 100644
--- a/vm/compiler/Frontend.cpp
+++ b/vm/compiler/Frontend.cpp
@@ -1579,23 +1579,16 @@
         dvmCompilerCodegenDump(cUnit);
     }
 
-    dvmLockMutex(&gDvmJit.compilerLock);
-    if (info->cacheVersion == gDvmJit.cacheVersion) {
-        /*
-         * If this trace uses class objects as constants,
-         * dvmJitInstallClassObjectPointers will switch the thread state
-         * to running and look up the class pointers using the descriptor/loader
-         * tuple stored in the callsite info structure. We need to make this window
-         * as short as possible since it is blocking GC.
-         */
-        if (cUnit->hasClassLiterals && info->codeAddress) {
-           dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress);
-        }
-    } else {
-        ALOGD("JIT CC reset. New version: %d / trace version: %d",
-              gDvmJit.cacheVersion, info->cacheVersion);
+    /*
+     * If this trace uses class objects as constants,
+     * dvmJitInstallClassObjectPointers will switch the thread state
+     * to running and look up the class pointers using the descriptor/loader
+     * tuple stored in the callsite info structure. We need to make this window
+     * as short as possible since it is blocking GC.
+     */
+    if (cUnit->hasClassLiterals && info->codeAddress) {
+        dvmJitInstallClassObjectPointers(cUnit, (char *) info->codeAddress);
     }
-    dvmUnlockMutex(&gDvmJit.compilerLock);
 
     /*
      * Since callsiteinfo is allocated from the arena, delay the reset until
@@ -2158,23 +2151,16 @@
                                optHints);
     }
 
-    dvmLockMutex(&gDvmJit.compilerLock);
-    if (info->cacheVersion == gDvmJit.cacheVersion) {
-        /*
-         * If this trace uses class objects as constants,
-         * dvmJitInstallClassObjectPointers will switch the thread state
-         * to running and look up the class pointers using the descriptor/loader
-         * tuple stored in the callsite info structure. We need to make this window
-         * as short as possible since it is blocking GC.
-         */
-        if (cUnit.hasClassLiterals && info->codeAddress) {
-            dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress);
-        }
-    } else {
-        ALOGD("JIT CC reset. New version: %d / trace version: %d",
-              gDvmJit.cacheVersion, info->cacheVersion);
+    /*
+     * If this trace uses class objects as constants,
+     * dvmJitInstallClassObjectPointers will switch the thread state
+     * to running and look up the class pointers using the descriptor/loader
+     * tuple stored in the callsite info structure. We need to make this window
+     * as short as possible since it is blocking GC.
+     */
+    if (cUnit.hasClassLiterals && info->codeAddress) {
+        dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress);
     }
-    dvmUnlockMutex(&gDvmJit.compilerLock);
 
     /*
      * Since callsiteinfo is allocated from the arena, delay the reset until
diff --git a/vm/compiler/Utility.cpp b/vm/compiler/Utility.cpp
index 2fe94d2..eaa562b 100644
--- a/vm/compiler/Utility.cpp
+++ b/vm/compiler/Utility.cpp
@@ -407,3 +407,7 @@
             break;
     }
 }
+
+void dvmCompilerCacheFlush(uintptr_t start, uintptr_t end) {
+    __builtin___clear_cache(reinterpret_cast<void*>(start), reinterpret_cast<void*>(end));
+}
diff --git a/vm/compiler/codegen/arm/ArchUtility.cpp b/vm/compiler/codegen/arm/ArchUtility.cpp
index 9f87b7f..b5e739f 100644
--- a/vm/compiler/codegen/arm/ArchUtility.cpp
+++ b/vm/compiler/codegen/arm/ArchUtility.cpp
@@ -420,12 +420,6 @@
     }
 }
 
-/* Target-specific cache flushing */
-void dvmCompilerCacheFlush(long start, long end, long flags)
-{
-    cacheflush(start, end, flags);
-}
-
 /* Target-specific cache clearing */
 void dvmCompilerCacheClear(char *start, size_t size)
 {
diff --git a/vm/compiler/codegen/arm/Assemble.cpp b/vm/compiler/codegen/arm/Assemble.cpp
index 5f2de72..7ed2d47 100644
--- a/vm/compiler/codegen/arm/Assemble.cpp
+++ b/vm/compiler/codegen/arm/Assemble.cpp
@@ -1562,7 +1562,7 @@
 
     /* Flush dcache and invalidate the icache to maintain coherence */
     dvmCompilerCacheFlush((long)cUnit->baseAddr,
-                          (long)((char *) cUnit->baseAddr + offset), 0);
+                          (long)((char *) cUnit->baseAddr + offset));
     UPDATE_CODE_CACHE_PATCHES();
 
     PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
@@ -1662,7 +1662,7 @@
         UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
 
         *branchAddr = newInst;
-        dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
+        dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4);
         UPDATE_CODE_CACHE_PATCHES();
 
         PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
@@ -1702,7 +1702,7 @@
          */
         android_atomic_release_store((int32_t)newContent->clazz,
             (volatile int32_t *)(void *)&cellAddr->clazz);
-        dvmCompilerCacheFlush((intptr_t) cellAddr, (intptr_t) (cellAddr+1), 0);
+        dvmCompilerCacheFlush((intptr_t) cellAddr, (intptr_t) (cellAddr+1));
         UPDATE_CODE_CACHE_PATCHES();
 
         PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
@@ -1902,7 +1902,7 @@
     }
 
     /* Then synchronize the I/D cache */
-    dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
+    dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1));
     UPDATE_CODE_CACHE_PATCHES();
 
     PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
@@ -2010,7 +2010,7 @@
                     highAddress = lastAddress;
             }
         }
-        dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
+        dvmCompilerCacheFlush((long)lowAddress, (long)highAddress);
         UPDATE_CODE_CACHE_PATCHES();
 
         PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
diff --git a/vm/compiler/codegen/mips/ArchUtility.cpp b/vm/compiler/codegen/mips/ArchUtility.cpp
index 47c4c6d..0b10cda 100644
--- a/vm/compiler/codegen/mips/ArchUtility.cpp
+++ b/vm/compiler/codegen/mips/ArchUtility.cpp
@@ -369,12 +369,6 @@
     }
 }
 
-/* Target-specific cache flushing */
-void dvmCompilerCacheFlush(long start, long end, long flags)
-{
-    cacheflush(start, end, flags);
-}
-
 /* Target-specific cache clearing */
 void dvmCompilerCacheClear(char *start, size_t size)
 {
diff --git a/vm/compiler/codegen/mips/Assemble.cpp b/vm/compiler/codegen/mips/Assemble.cpp
index 36a301c..76aa606 100644
--- a/vm/compiler/codegen/mips/Assemble.cpp
+++ b/vm/compiler/codegen/mips/Assemble.cpp
@@ -913,7 +913,7 @@
 
     /* Flush dcache and invalidate the icache to maintain coherence */
     dvmCompilerCacheFlush((long)cUnit->baseAddr,
-                          (long)((char *) cUnit->baseAddr + offset), 0);
+                          (long)((char *) cUnit->baseAddr + offset));
 
     UPDATE_CODE_CACHE_PATCHES();
 
@@ -974,7 +974,7 @@
         UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
 
         *branchAddr = newInst;
-        dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
+        dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4);
         UPDATE_CODE_CACHE_PATCHES();
 
         PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
@@ -1015,7 +1015,7 @@
          */
         android_atomic_release_store((int32_t)newContent->clazz,
             (volatile int32_t *)(void*) &cellAddr->clazz);
-        dvmCompilerCacheFlush((long) cellAddr, (long) (cellAddr+1), 0);
+        dvmCompilerCacheFlush((long) cellAddr, (long) (cellAddr+1));
         UPDATE_CODE_CACHE_PATCHES();
 
         PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
@@ -1226,7 +1226,7 @@
     }
 
     /* Then synchronize the I/D cache */
-    dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
+    dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1));
     UPDATE_CODE_CACHE_PATCHES();
 
     PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
@@ -1353,7 +1353,7 @@
         }
 
         if (lowAddress && highAddress)
-            dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
+            dvmCompilerCacheFlush((long)lowAddress, (long)highAddress);
 
         UPDATE_CODE_CACHE_PATCHES();
 
diff --git a/vm/compiler/codegen/x86/CodegenInterface.cpp b/vm/compiler/codegen/x86/CodegenInterface.cpp
index 337bd61..6ec5f9d 100644
--- a/vm/compiler/codegen/x86/CodegenInterface.cpp
+++ b/vm/compiler/codegen/x86/CodegenInterface.cpp
@@ -1538,8 +1538,4 @@
     return isCompile;
 }
 
-void dvmCompilerCacheFlush(long start, long end, long flags) {
-  /* cacheflush is needed for ARM, but not for IA32 (coherent icache) */
-}
-
 //#endif
diff --git a/vm/dalvik b/vm/dalvik
index 9229e5a..e5e4e51 100644
--- a/vm/dalvik
+++ b/vm/dalvik
@@ -14,6 +14,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+ANDROID_BUILD_TOP="$(cd "${PROG_DIR}/../../../../" ; pwd -P)/"
+
 mkdir -p /tmp/android-data/dalvik-cache
 ANDROID_PRINTF_LOG=tag \
 ANDROID_LOG_TAGS="" \
diff --git a/vm/native/dalvik_system_DexFile.cpp b/vm/native/dalvik_system_DexFile.cpp
index af1deb6..a7d83f5 100644
--- a/vm/native/dalvik_system_DexFile.cpp
+++ b/vm/native/dalvik_system_DexFile.cpp
@@ -145,8 +145,6 @@
  * To optimize this away we could search for existing entries in the hash
  * table and refCount them.  Requires atomic ops or adding "synchronized"
  * to the non-native code that calls here.
- *
- * TODO: should be using "long" for a pointer.
  */
 static void Dalvik_dalvik_system_DexFile_openDexFileNative(const u4* args,
     JValue* pResult)
@@ -233,7 +231,7 @@
     }
 
     free(outputName);
-    RETURN_PTR(pDexOrJar);
+    RETURN_LONG((uintptr_t) pDexOrJar);
 }
 
 /*
@@ -286,7 +284,7 @@
     pDexOrJar->fileName = strdup("<memory>"); // Needs to be free()able.
     addToDexFileTable(pDexOrJar);
 
-    RETURN_PTR(pDexOrJar);
+    RETURN_LONG((uintptr_t) pDexOrJar);
 }
 
 /*
@@ -297,7 +295,7 @@
 static void Dalvik_dalvik_system_DexFile_closeDexFile(const u4* args,
     JValue* pResult)
 {
-    int cookie = args[0];
+    int cookie = dvmGetArgLong(args, 0);
     DexOrJar* pDexOrJar = (DexOrJar*) cookie;
 
     if (pDexOrJar == NULL)
@@ -351,7 +349,7 @@
 {
     StringObject* nameObj = (StringObject*) args[0];
     Object* loader = (Object*) args[1];
-    int cookie = args[2];
+    int cookie = dvmGetArgLong(args, 2);
     ClassObject* clazz = NULL;
     DexOrJar* pDexOrJar = (DexOrJar*) cookie;
     DvmDex* pDvmDex;
@@ -407,7 +405,7 @@
 static void Dalvik_dalvik_system_DexFile_getClassNameList(const u4* args,
     JValue* pResult)
 {
-    int cookie = args[0];
+    int cookie = dvmGetArgLong(args, 0);
     DexOrJar* pDexOrJar = (DexOrJar*) cookie;
     Thread* self = dvmThreadSelf();
 
@@ -517,15 +515,15 @@
 }
 
 const DalvikNativeMethod dvm_dalvik_system_DexFile[] = {
-    { "openDexFileNative",  "(Ljava/lang/String;Ljava/lang/String;I)I",
+    { "openDexFileNative",  "(Ljava/lang/String;Ljava/lang/String;I)J",
         Dalvik_dalvik_system_DexFile_openDexFileNative },
-    { "openDexFile",        "([B)I",
+    { "openDexFile",        "([B)J",
         Dalvik_dalvik_system_DexFile_openDexFile_bytearray },
-    { "closeDexFile",       "(I)V",
+    { "closeDexFile",       "(J)V",
         Dalvik_dalvik_system_DexFile_closeDexFile },
-    { "defineClassNative",  "(Ljava/lang/String;Ljava/lang/ClassLoader;I)Ljava/lang/Class;",
+    { "defineClassNative",  "(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;",
         Dalvik_dalvik_system_DexFile_defineClassNative },
-    { "getClassNameList",   "(I)[Ljava/lang/String;",
+    { "getClassNameList",   "(J)[Ljava/lang/String;",
         Dalvik_dalvik_system_DexFile_getClassNameList },
     { "isDexOptNeeded",     "(Ljava/lang/String;)Z",
         Dalvik_dalvik_system_DexFile_isDexOptNeeded },
diff --git a/vm/native/dalvik_system_VMDebug.cpp b/vm/native/dalvik_system_VMDebug.cpp
index 5377357..227d1c1 100644
--- a/vm/native/dalvik_system_VMDebug.cpp
+++ b/vm/native/dalvik_system_VMDebug.cpp
@@ -244,7 +244,7 @@
 
 /*
  * static void startMethodTracingFd(String traceFileName, FileDescriptor fd,
- *     int bufferSize, int flags)
+ *     int bufferSize, int flags, boolean samplingEnabled, int intervalUs)
  *
  * Start method trace profiling, sending results to a file descriptor.
  */
@@ -255,6 +255,8 @@
     Object* traceFd = (Object*) args[1];
     int bufferSize = args[2];
     int flags = args[3];
+    bool samplingEnabled = args[4];
+    int intervalUs = args[5];
 
     int origFd = getFileDescriptor(traceFd);
     if (origFd < 0)
@@ -272,14 +274,15 @@
         RETURN_VOID();
     }
 
-    dvmMethodTraceStart(traceFileName, fd, bufferSize, flags, false, false, 0);
+    dvmMethodTraceStart(traceFileName, fd, bufferSize, flags, false,
+        samplingEnabled, intervalUs);
     free(traceFileName);
     RETURN_VOID();
 }
 
 /*
  * static void startMethodTracingFilename(String traceFileName, int bufferSize,
- *     int flags)
+ *     int flags, boolean samplingEnabled, int intervalUs)
  *
  * Start method trace profiling, sending results to a file.
  */
@@ -289,13 +292,16 @@
     StringObject* traceFileStr = (StringObject*) args[0];
     int bufferSize = args[1];
     int flags = args[2];
+    bool samplingEnabled = args[3];
+    int intervalUs = args[4];
 
     char* traceFileName = dvmCreateCstrFromString(traceFileStr);
     if (traceFileName == NULL) {
         RETURN_VOID();
     }
 
-    dvmMethodTraceStart(traceFileName, -1, bufferSize, flags, false, false, 0);
+    dvmMethodTraceStart(traceFileName, -1, bufferSize, flags, false,
+        samplingEnabled, intervalUs);
     free(traceFileName);
     RETURN_VOID();
 }
@@ -823,9 +829,9 @@
         Dalvik_dalvik_system_VMDebug_stopAllocCounting },
     { "startMethodTracingDdmsImpl", "(IIZI)V",
         Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl },
-    { "startMethodTracingFd",       "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
+    { "startMethodTracingFd",       "(Ljava/lang/String;Ljava/io/FileDescriptor;IIZI)V",
         Dalvik_dalvik_system_VMDebug_startMethodTracingFd },
-    { "startMethodTracingFilename", "(Ljava/lang/String;II)V",
+    { "startMethodTracingFilename", "(Ljava/lang/String;IIZI)V",
         Dalvik_dalvik_system_VMDebug_startMethodTracingFilename },
     { "getMethodTracingMode",       "()I",
         Dalvik_dalvik_system_VMDebug_getMethodTracingMode },
diff --git a/vm/native/dalvik_system_Zygote.cpp b/vm/native/dalvik_system_Zygote.cpp
index e2d0102..3dd56fb 100644
--- a/vm/native/dalvik_system_Zygote.cpp
+++ b/vm/native/dalvik_system_Zygote.cpp
@@ -29,6 +29,8 @@
 #include <grp.h>
 #include <errno.h>
 #include <paths.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <sys/personality.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
@@ -488,10 +490,49 @@
 #endif
 }
 
+#ifdef HAVE_ANDROID_OS
+
+// Utility to close down the Zygote socket file descriptors while
+// the child is still running as root with Zygote's privileges.  Each
+// descriptor (if any) is closed via dup2(), replacing it with a valid
+// (open) descriptor to /dev/null.
+
+static void detachDescriptors(ArrayObject* fdsToClose) {
+    if (!fdsToClose) {
+        return;
+    }
+    size_t count = fdsToClose->length;
+    int *ar = (int *) (void *) fdsToClose->contents;
+    if (!ar) {
+        ALOG(LOG_ERROR, ZYGOTE_LOG_TAG, "Bad fd array");
+        dvmAbort();
+    }
+    size_t i;
+    int devnull;
+    for (i = 0; i < count; i++) {
+        if (ar[1] < 0) {
+            continue;
+        }
+        devnull = open("/dev/null", O_RDWR);
+        if (devnull < 0) {
+            ALOG(LOG_ERROR, ZYGOTE_LOG_TAG, "Failed to open /dev/null");
+            dvmAbort();
+        }
+        ALOG(LOG_VERBOSE, ZYGOTE_LOG_TAG, "Switching descriptor %d to /dev/null", ar[i]);
+        if (dup2(devnull, ar[i]) < 0) {
+            ALOG(LOG_ERROR, ZYGOTE_LOG_TAG, "Failed dup2() on descriptor %d", ar[i]);
+            dvmAbort();
+        }
+        close(devnull);
+    }
+}
+
+#endif
+
 /*
  * Utility routine to fork zygote and specialize the child process.
  */
-static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
+static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer, bool legacyFork)
 {
     pid_t pid;
 
@@ -500,6 +541,7 @@
     ArrayObject* gids = (ArrayObject *)args[2];
     u4 debugFlags = args[3];
     ArrayObject *rlimits = (ArrayObject *)args[4];
+    ArrayObject *fdsToClose = NULL;
     u4 mountMode = MOUNT_EXTERNAL_NONE;
     int64_t permittedCapabilities, effectiveCapabilities;
     char *seInfo = NULL;
@@ -534,6 +576,9 @@
                 dvmAbort();
             }
         }
+        if (!legacyFork) {
+          fdsToClose = (ArrayObject *)args[8];
+        }
     }
 
     if (!gDvm.zygote) {
@@ -561,6 +606,10 @@
         extern int gMallocLeakZygoteChild;
         gMallocLeakZygoteChild = 1;
 
+        // Unhook from the Zygote sockets immediately
+
+        detachDescriptors(fdsToClose);
+
         /* keep caps across UID change, unless we're staying root */
         if (uid != 0) {
             err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
@@ -693,16 +742,23 @@
 }
 
 /*
+ * We must expose both flavors of the native forking code for a while,
+ * as this Dalvik change must be reviewed and checked in before the
+ * libcore and frameworks changes.  The legacy fork API function and
+ * registration can be removed later.
+ */
+
+/*
  * native public static int nativeForkAndSpecialize(int uid, int gid,
  *     int[] gids, int debugFlags, int[][] rlimits, int mountExternal,
- *     String seInfo, String niceName);
+ *     String seInfo, String niceName, int[] fdsToClose);
  */
 static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
     JValue* pResult)
 {
     pid_t pid;
 
-    pid = forkAndSpecializeCommon(args, false);
+    pid = forkAndSpecializeCommon(args, false, false);
 
     RETURN_INT(pid);
 }
@@ -716,7 +772,7 @@
         const u4* args, JValue* pResult)
 {
     pid_t pid;
-    pid = forkAndSpecializeCommon(args, true);
+    pid = forkAndSpecializeCommon(args, true, true);
 
     /* The zygote process checks whether the child process has died or not. */
     if (pid > 0) {
@@ -739,7 +795,7 @@
 const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
     { "nativeFork", "()I",
       Dalvik_dalvik_system_Zygote_fork },
-    { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
+    { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
       Dalvik_dalvik_system_Zygote_forkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       Dalvik_dalvik_system_Zygote_forkSystemServer },