am afe3a013: (-s ours) am 288f2280: Revert "Fix alignment when recompacting a DexMerger result. do not merge."

* commit 'afe3a0131e75367759e1d7a69cec0aac2a45524c':
  Revert "Fix alignment when recompacting a DexMerger result. do not merge."
diff --git a/vm/Globals.h b/vm/Globals.h
index 3bef865..565c92a 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -90,6 +90,9 @@
     size_t      heapStartingSize;
     size_t      heapMaximumSize;
     size_t      heapGrowthLimit;
+    double      heapTargetUtilization;
+    size_t      heapMinFree;
+    size_t      heapMaxFree;
     size_t      stackSize;
     size_t      mainThreadStackSize;
 
diff --git a/vm/Init.cpp b/vm/Init.cpp
index 5e3711e..11d884e 100644
--- a/vm/Init.cpp
+++ b/vm/Init.cpp
@@ -23,7 +23,10 @@
 #include <signal.h>
 #include <limits.h>
 #include <ctype.h>
+#include <sys/mount.h>
 #include <sys/wait.h>
+#include <linux/fs.h>
+#include <cutils/fs.h>
 #include <unistd.h>
 
 #include "Dalvik.h"
@@ -918,6 +921,36 @@
                 dvmFprintf(stderr, "Invalid -XX:HeapGrowthLimit option '%s'\n", argv[i]);
                 return -1;
             }
+        } else if (strncmp(argv[i], "-XX:HeapMinFree=", 16) == 0) {
+            size_t val = parseMemOption(argv[i] + 16, 1024);
+            if (val != 0) {
+                gDvm.heapMinFree = val;
+            } else {
+                dvmFprintf(stderr, "Invalid -XX:HeapMinFree option '%s'\n", argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-XX:HeapMaxFree=", 16) == 0) {
+            size_t val = parseMemOption(argv[i] + 16, 1024);
+            if (val != 0) {
+                gDvm.heapMaxFree = val;
+            } else {
+                dvmFprintf(stderr, "Invalid -XX:HeapMaxFree option '%s'\n", argv[i]);
+                return -1;
+            }
+        } else if (strncmp(argv[i], "-XX:HeapTargetUtilization=", 26) == 0) {
+            const char* start = argv[i] + 26;
+            const char* end = start;
+            double val = strtod(start, const_cast<char**>(&end));
+            // Ensure that we have a value, there was no cruft after it and it
+            // satisfies a sensible range.
+            bool sane_val = (start != end) && (end[0] == '\0') &&
+                (val >= 0.1) && (val <= 0.9);
+            if (sane_val) {
+                gDvm.heapTargetUtilization = val;
+            } else {
+                dvmFprintf(stderr, "Invalid -XX:HeapTargetUtilization option '%s'\n", argv[i]);
+                return -1;
+            }
         } else if (strncmp(argv[i], "-Xss", 4) == 0) {
             size_t val = parseMemOption(argv[i]+4, 1);
             if (val != 0) {
@@ -1206,6 +1239,15 @@
     gDvm.heapGrowthLimit = 0;  // 0 means no growth limit
     gDvm.stackSize = kDefaultStackSize;
     gDvm.mainThreadStackSize = kDefaultStackSize;
+    // When the heap is less than the maximum or growth limited size,
+    // fix the free portion of the heap. The utilization is the ratio
+    // of live to free memory, 0.5 implies half the heap is available
+    // to allocate into before a GC occurs. Min free and max free
+    // force the free memory to never be smaller than min free or
+    // larger than max free.
+    gDvm.heapTargetUtilization = 0.5;
+    gDvm.heapMaxFree = 2 * 1024 * 1024;
+    gDvm.heapMinFree = gDvm.heapMaxFree / 4;
 
     gDvm.concurrentMarkSweep = true;
 
@@ -1238,7 +1280,6 @@
 
     gDvm.constInit = false;
     gDvm.commonInit = false;
-    gDvmJit.disableOpt = 1<<kMethodInlining;
 #else
     gDvm.executionMode = kExecutionModeInterpFast;
 #endif
@@ -1597,6 +1638,32 @@
     /* zygote goes into its own process group */
     setpgid(0,0);
 
+    // See storage config details at http://source.android.com/tech/storage/
+    // Create private mount namespace shared by all children
+    if (unshare(CLONE_NEWNS) == -1) {
+        SLOGE("Failed to unshare(): %s", strerror(errno));
+        return -1;
+    }
+
+    // Mark rootfs as being a slave so that changes from default
+    // namespace only flow into our children.
+    if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) {
+        SLOGE("Failed to mount() rootfs as MS_SLAVE: %s", strerror(errno));
+        return -1;
+    }
+
+    // Create a staging tmpfs that is shared by our children; they will
+    // bind mount storage into their respective private namespaces, which
+    // are isolated from each other.
+    const char* target_base = getenv("EMULATED_STORAGE_TARGET");
+    if (target_base != NULL) {
+        if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
+                "uid=0,gid=1028,mode=0050") == -1) {
+            SLOGE("Failed to mount tmpfs to %s: %s", target_base, strerror(errno));
+            return -1;
+        }
+    }
+
     return true;
 }
 
diff --git a/vm/Native.cpp b/vm/Native.cpp
index be719a7..8892c2a 100644
--- a/vm/Native.cpp
+++ b/vm/Native.cpp
@@ -385,6 +385,7 @@
 
     if (handle == NULL) {
         *detail = strdup(dlerror());
+        ALOGE("dlopen(\"%s\") failed: %s", pathName, *detail);
         return false;
     }
 
diff --git a/vm/alloc/HeapSource.cpp b/vm/alloc/HeapSource.cpp
index cd2f4df..ee40af82 100644
--- a/vm/alloc/HeapSource.cpp
+++ b/vm/alloc/HeapSource.cpp
@@ -34,9 +34,6 @@
 static void trimHeaps();
 
 #define HEAP_UTILIZATION_MAX        1024
-#define DEFAULT_HEAP_UTILIZATION    512     // Range 1..HEAP_UTILIZATION_MAX
-#define HEAP_IDEAL_FREE             (2 * 1024 * 1024)
-#define HEAP_MIN_FREE               (HEAP_IDEAL_FREE / 4)
 
 /* How long to wait after a GC before performing a heap trim
  * operation to reclaim unused pages.
@@ -134,6 +131,18 @@
      */
     size_t softLimit;
 
+    /* Minimum number of free bytes. Used with the target utilization when
+     * setting the softLimit. Never allows less bytes than this to be free
+     * when the heap size is below the maximum size or growth limit.
+     */
+    size_t minFree;
+
+    /* Maximum number of free bytes. Used with the target utilization when
+     * setting the softLimit. Never allows more bytes than this to be free
+     * when the heap size is below the maximum size or growth limit.
+     */
+    size_t maxFree;
+
     /* The heaps; heaps[0] is always the active heap,
      * which new objects should be allocated from.
      */
@@ -393,7 +402,7 @@
     size_t overhead = base - hs->heaps[0].base;
     assert(((size_t)hs->heaps[0].base & (SYSTEM_PAGE_SIZE - 1)) == 0);
 
-    if (overhead + HEAP_MIN_FREE >= hs->maximumSize) {
+    if (overhead + hs->minFree >= hs->maximumSize) {
         LOGE_HEAP("No room to create any more heaps "
                   "(%zd overhead, %zd max)",
                   overhead, hs->maximumSize);
@@ -401,11 +410,11 @@
     }
     size_t morecoreStart = SYSTEM_PAGE_SIZE;
     heap.maximumSize = hs->growthLimit - overhead;
-    heap.concurrentStartBytes = HEAP_MIN_FREE - CONCURRENT_START;
+    heap.concurrentStartBytes = hs->minFree - CONCURRENT_START;
     heap.base = base;
     heap.limit = heap.base + heap.maximumSize;
     heap.brk = heap.base + morecoreStart;
-    heap.msp = createMspace(base, morecoreStart, HEAP_MIN_FREE);
+    heap.msp = createMspace(base, morecoreStart, hs->minFree);
     if (heap.msp == NULL) {
         return false;
     }
@@ -577,7 +586,9 @@
         goto fail;
     }
 
-    hs->targetUtilization = DEFAULT_HEAP_UTILIZATION;
+    hs->targetUtilization = gDvm.heapTargetUtilization * HEAP_UTILIZATION_MAX;
+    hs->minFree = gDvm.heapMinFree;
+    hs->maxFree = gDvm.heapMaxFree;
     hs->startSize = startSize;
     hs->maximumSize = maximumSize;
     hs->growthLimit = growthLimit;
@@ -588,6 +599,16 @@
     hs->hasGcThread = false;
     hs->heapBase = (char *)base;
     hs->heapLength = length;
+
+    if (hs->maxFree > hs->maximumSize) {
+      hs->maxFree = hs->maximumSize;
+    }
+    if (hs->minFree < CONCURRENT_START) {
+      hs->minFree = CONCURRENT_START;
+    } else if (hs->minFree > hs->maxFree) {
+      hs->minFree = hs->maxFree;
+    }
+
     if (!addInitialHeap(hs, msp, growthLimit)) {
         LOGE_HEAP("Can't add initial heap");
         goto fail;
@@ -1242,23 +1263,21 @@
 /*
  * Given the size of a live set, returns the ideal heap size given
  * the current target utilization and MIN/MAX values.
- *
- * targetUtilization is in the range 1..HEAP_UTILIZATION_MAX.
  */
-static size_t getUtilizationTarget(size_t liveSize, size_t targetUtilization)
+static size_t getUtilizationTarget(const HeapSource* hs, size_t liveSize)
 {
     /* Use the current target utilization ratio to determine the
      * ideal heap size based on the size of the live set.
      */
-    size_t targetSize = (liveSize / targetUtilization) * HEAP_UTILIZATION_MAX;
+    size_t targetSize = (liveSize / hs->targetUtilization) * HEAP_UTILIZATION_MAX;
 
     /* Cap the amount of free space, though, so we don't end up
      * with, e.g., 8MB of free space when the live set size hits 8MB.
      */
-    if (targetSize > liveSize + HEAP_IDEAL_FREE) {
-        targetSize = liveSize + HEAP_IDEAL_FREE;
-    } else if (targetSize < liveSize + HEAP_MIN_FREE) {
-        targetSize = liveSize + HEAP_MIN_FREE;
+    if (targetSize > liveSize + hs->maxFree) {
+        targetSize = liveSize + hs->maxFree;
+    } else if (targetSize < liveSize + hs->minFree) {
+        targetSize = liveSize + hs->minFree;
     }
     return targetSize;
 }
@@ -1285,8 +1304,7 @@
      * the current heap.
      */
     size_t currentHeapUsed = heap->bytesAllocated;
-    size_t targetHeapSize =
-            getUtilizationTarget(currentHeapUsed, hs->targetUtilization);
+    size_t targetHeapSize = getUtilizationTarget(hs, currentHeapUsed);
 
     /* The ideal size includes the old heaps; add overhead so that
      * it can be immediately subtracted again in setIdealFootprint().
diff --git a/vm/alloc/MarkSweep.cpp b/vm/alloc/MarkSweep.cpp
index 268d880..eb739e5 100644
--- a/vm/alloc/MarkSweep.cpp
+++ b/vm/alloc/MarkSweep.cpp
@@ -556,9 +556,7 @@
 {
     GcHeap *h = gDvm.gcHeap;
     const u1 *base, *limit, *ptr, *dirty;
-    size_t footprint;
 
-    footprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
     base = &h->cardTableBase[0];
     limit = dvmCardFromAddr((u1 *)dvmHeapSourceGetLimit());
     assert(limit <= &h->cardTableBase[h->cardTableLength]);
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp
index 222b880..84744b5 100644
--- a/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp
+++ b/vm/compiler/codegen/arm/armv7-a-neon/MethodCodegenDriver.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#if 0
+
 /*
  * Rebuild the interpreter frame then punt to the interpreter to execute
  * instruction at specified PC.
@@ -445,3 +447,11 @@
     selfVerificationBranchInsertPass(cUnit);
 #endif
 }
+
+#else
+
+void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit) {
+    // Method-based JIT not supported for ARM.
+}
+
+#endif
diff --git a/vm/compiler/codegen/x86/CodegenInterface.cpp b/vm/compiler/codegen/x86/CodegenInterface.cpp
index aade180..c99fadd 100644
--- a/vm/compiler/codegen/x86/CodegenInterface.cpp
+++ b/vm/compiler/codegen/x86/CodegenInterface.cpp
@@ -189,8 +189,7 @@
 
 void dvmCompilerMethodMIR2LIR(CompilationUnit *cUnit)
 {
-    ALOGE("Method-based JIT not supported for the x86 target");
-    dvmAbort();
+    // Method-based JIT not supported for x86.
 }
 
 void dvmJitScanAllClassPointers(void (*callback)(void *))
diff --git a/vm/native/dalvik_system_Zygote.cpp b/vm/native/dalvik_system_Zygote.cpp
index 28d8d2d..269b961 100644
--- a/vm/native/dalvik_system_Zygote.cpp
+++ b/vm/native/dalvik_system_Zygote.cpp
@@ -31,7 +31,13 @@
 #include <errno.h>
 #include <paths.h>
 #include <sys/personality.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+#include <cutils/fs.h>
 #include <cutils/sched_policy.h>
+#include <cutils/multiuser.h>
+#include <sched.h>
 
 #if defined(HAVE_PRCTL)
 # include <sys/prctl.h>
@@ -48,6 +54,14 @@
     DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
 };
 
+/* must match values in dalvik.system.Zygote */
+enum {
+    MOUNT_EXTERNAL_NONE = 0,
+    MOUNT_EXTERNAL_SINGLEUSER = 1,
+    MOUNT_EXTERNAL_MULTIUSER = 2,
+    MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+};
+
 /*
  * This signal handler is for zygote mode, since the zygote
  * must reap its children
@@ -229,6 +243,98 @@
     return 0;
 }
 
+/*
+ * Create a private mount namespace and bind mount appropriate emulated
+ * storage for the given user.
+ */
+static int mountEmulatedStorage(uid_t uid, u4 mountMode) {
+    // See storage config details at http://source.android.com/tech/storage/
+    userid_t userid = multiuser_get_user_id(uid);
+
+    // Create a second private mount namespace for our process
+    if (unshare(CLONE_NEWNS) == -1) {
+        SLOGE("Failed to unshare(): %s", strerror(errno));
+        return -1;
+    }
+
+    // Create bind mounts to expose external storage
+    if (mountMode == MOUNT_EXTERNAL_MULTIUSER
+            || mountMode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+        // These paths must already be created by init.rc
+        const char* source = getenv("EMULATED_STORAGE_SOURCE");
+        const char* target = getenv("EMULATED_STORAGE_TARGET");
+        const char* legacy = getenv("EXTERNAL_STORAGE");
+        if (source == NULL || target == NULL || legacy == NULL) {
+            SLOGE("Storage environment undefined; unable to provide external storage");
+            return -1;
+        }
+
+        // Prepare source paths
+        char source_user[PATH_MAX];
+        char source_obb[PATH_MAX];
+        char target_user[PATH_MAX];
+
+        // /mnt/shell/emulated/0
+        snprintf(source_user, PATH_MAX, "%s/%d", source, userid);
+        // /mnt/shell/emulated/obb
+        snprintf(source_obb, PATH_MAX, "%s/obb", source);
+        // /storage/emulated/0
+        snprintf(target_user, PATH_MAX, "%s/%d", target, userid);
+
+        if (fs_prepare_dir(source_user, 0000, 0, 0) == -1
+                || fs_prepare_dir(source_obb, 0000, 0, 0) == -1
+                || fs_prepare_dir(target_user, 0000, 0, 0) == -1) {
+            return -1;
+        }
+
+        if (mountMode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+            // Mount entire external storage tree for all users
+            if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
+                SLOGE("Failed to mount %s to %s: %s", source, target, strerror(errno));
+                return -1;
+            }
+        } else {
+            // Only mount user-specific external storage
+            if (mount(source_user, target_user, NULL, MS_BIND, NULL) == -1) {
+                SLOGE("Failed to mount %s to %s: %s", source_user, target_user, strerror(errno));
+                return -1;
+            }
+        }
+
+        // Now that user is mounted, prepare and mount OBB storage
+        // into place for current user
+        char target_android[PATH_MAX];
+        char target_obb[PATH_MAX];
+
+        // /storage/emulated/0/Android
+        snprintf(target_android, PATH_MAX, "%s/%d/Android", target, userid);
+        // /storage/emulated/0/Android/obb
+        snprintf(target_obb, PATH_MAX, "%s/%d/Android/obb", target, userid);
+
+        if (fs_prepare_dir(target_android, 0000, 0, 0) == -1
+                || fs_prepare_dir(target_obb, 0000, 0, 0) == -1
+                || fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+            return -1;
+        }
+        if (mount(source_obb, target_obb, NULL, MS_BIND, NULL) == -1) {
+            SLOGE("Failed to mount %s to %s: %s", source_obb, target_obb, strerror(errno));
+            return -1;
+        }
+
+        // Finally, mount user-specific path into place for legacy users
+        if (mount(target_user, legacy, NULL, MS_BIND | MS_REC, NULL) == -1) {
+            SLOGE("Failed to mount %s to %s: %s", target_user, legacy, strerror(errno));
+            return -1;
+        }
+
+    } else {
+        SLOGE("Mount mode %d unsupported", mountMode);
+        return -1;
+    }
+
+    return 0;
+}
+
 /* native public static int fork(); */
 static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue* pResult)
 {
@@ -390,6 +496,7 @@
     ArrayObject* gids = (ArrayObject *)args[2];
     u4 debugFlags = args[3];
     ArrayObject *rlimits = (ArrayObject *)args[4];
+    u4 mountMode = MOUNT_EXTERNAL_NONE;
     int64_t permittedCapabilities, effectiveCapabilities;
 #ifdef HAVE_SELINUX
     char *seInfo = NULL;
@@ -407,9 +514,10 @@
         permittedCapabilities = args[5] | (int64_t) args[6] << 32;
         effectiveCapabilities = args[7] | (int64_t) args[8] << 32;
     } else {
+        mountMode = args[5];
         permittedCapabilities = effectiveCapabilities = 0;
 #ifdef HAVE_SELINUX
-        StringObject* seInfoObj = (StringObject*)args[5];
+        StringObject* seInfoObj = (StringObject*)args[6];
         if (seInfoObj) {
             seInfo = dvmCreateCstrFromString(seInfoObj);
             if (!seInfo) {
@@ -417,7 +525,7 @@
                 dvmAbort();
             }
         }
-        StringObject* niceNameObj = (StringObject*)args[6];
+        StringObject* niceNameObj = (StringObject*)args[7];
         if (niceNameObj) {
             niceName = dvmCreateCstrFromString(niceNameObj);
             if (!niceName) {
@@ -465,15 +573,30 @@
 
 #endif /* HAVE_ANDROID_OS */
 
-        err = setgroupsIntarray(gids);
+        if (mountMode != MOUNT_EXTERNAL_NONE) {
+            err = mountEmulatedStorage(uid, mountMode);
+            if (err < 0) {
+                ALOGE("cannot mountExternalStorage(): %s", strerror(errno));
 
+                if (errno == ENOTCONN || errno == EROFS) {
+                    // When device is actively encrypting, we get ENOTCONN here
+                    // since FUSE was mounted before the framework restarted.
+                    // When encrypted device is booting, we get EROFS since
+                    // FUSE hasn't been created yet by init.
+                    // In either case, continue without external storage.
+                } else {
+                    dvmAbort();
+                }
+            }
+        }
+
+        err = setgroupsIntarray(gids);
         if (err < 0) {
             ALOGE("cannot setgroups(): %s", strerror(errno));
             dvmAbort();
         }
 
         err = setrlimitsFromArray(rlimits);
-
         if (err < 0) {
             ALOGE("cannot setrlimit(): %s", strerror(errno));
             dvmAbort();
@@ -549,8 +672,10 @@
     return pid;
 }
 
-/* native public static int forkAndSpecialize(int uid, int gid,
- *     int[] gids, int debugFlags, String seInfo, String niceName);
+/*
+ * native public static int nativeForkAndSpecialize(int uid, int gid,
+ *     int[] gids, int debugFlags, int[][] rlimits, int mountExternal,
+ *     String seInfo, String niceName);
  */
 static void Dalvik_dalvik_system_Zygote_forkAndSpecialize(const u4* args,
     JValue* pResult)
@@ -562,9 +687,10 @@
     RETURN_INT(pid);
 }
 
-/* native public static int forkSystemServer(int uid, int gid,
- *     int[] gids, int debugFlags, long permittedCapabilities,
- *     long effectiveCapabilities);
+/*
+ * native public static int nativeForkSystemServer(int uid, int gid,
+ *     int[] gids, int debugFlags, int[][] rlimits,
+ *     long permittedCapabilities, long effectiveCapabilities);
  */
 static void Dalvik_dalvik_system_Zygote_forkSystemServer(
         const u4* args, JValue* pResult)
@@ -609,7 +735,7 @@
 const DalvikNativeMethod dvm_dalvik_system_Zygote[] = {
     { "nativeFork", "()I",
       Dalvik_dalvik_system_Zygote_fork },
-    { "nativeForkAndSpecialize", "(II[II[[ILjava/lang/String;Ljava/lang/String;)I",
+    { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;)I",
       Dalvik_dalvik_system_Zygote_forkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       Dalvik_dalvik_system_Zygote_forkSystemServer },
diff --git a/vm/oo/Class.cpp b/vm/oo/Class.cpp
index eb816b0..85ac9a7 100644
--- a/vm/oo/Class.cpp
+++ b/vm/oo/Class.cpp
@@ -2914,25 +2914,29 @@
                 Method* superMeth = clazz->vtable[si];
 
                 if (dvmCompareMethodNamesAndProtos(localMeth, superMeth) == 0) {
-                    if (dvmCheckMethodAccess(clazz, superMeth)) {
-                        /* verify */
-                        if (dvmIsFinalMethod(superMeth)) {
-                            ALOGW("Method %s.%s overrides final %s.%s",
-                                localMeth->clazz->descriptor, localMeth->name,
-                                superMeth->clazz->descriptor, superMeth->name);
-                            goto bail;
-                        }
-                        clazz->vtable[si] = localMeth;
-                        localMeth->methodIndex = (u2) si;
-                        //ALOGV("+++   override %s.%s (slot %d)",
-                        //    clazz->descriptor, localMeth->name, si);
-                        break;
-                    } else {
-                        ALOGW("in older versions of dalvik, method %s.%s would have incorrectly "
-                              "overridden package-private method with same name in %s",
+                    // We should have an access check here, but some apps rely on us not
+                    // checking access: http://b/7301030
+                    bool isAccessible = dvmCheckMethodAccess(clazz, superMeth);
+                    if (dvmIsFinalMethod(superMeth)) {
+                        ALOGE("Method %s.%s overrides final %s.%s",
+                              localMeth->clazz->descriptor, localMeth->name,
+                              superMeth->clazz->descriptor, superMeth->name);
+                        goto bail;
+                    }
+
+                    // Warn if we just spotted code relying on this bug...
+                    if (!isAccessible) {
+                        ALOGW("method %s.%s incorrectly overrides "
+                              "package-private method with same name in %s",
                               localMeth->clazz->descriptor, localMeth->name,
                               superMeth->clazz->descriptor);
                     }
+
+                    clazz->vtable[si] = localMeth;
+                    localMeth->methodIndex = (u2) si;
+                    //ALOGV("+++   override %s.%s (slot %d)",
+                    //    clazz->descriptor, localMeth->name, si);
+                    break;
                 }
             }
 
diff --git a/vm/reflect/Annotation.cpp b/vm/reflect/Annotation.cpp
index 453ddc5..26dea75 100644
--- a/vm/reflect/Annotation.cpp
+++ b/vm/reflect/Annotation.cpp
@@ -679,7 +679,7 @@
             ALOGW("WARNING: could not find annotation member %s in %s",
                 name, annoClass->descriptor);
         } else {
-            methodObj = dvmCreateReflectMethodObject(annoMeth);
+            methodObj = dvmCreateReflectObjForMethod(annoClass, annoMeth);
             methodReturn = dvmGetBoxedReturnType(annoMeth);
         }
     }