Merge change I117408b2

* changes:
  Restore support for DEX on FAT.
diff --git a/libdex/CmdUtils.c b/libdex/CmdUtils.c
index 7dfee87..102664c 100644
--- a/libdex/CmdUtils.c
+++ b/libdex/CmdUtils.c
@@ -162,7 +162,7 @@
         goto bail;
     }
 
-    if (sysMapFileInShmem(fd, pMap) != 0) {
+    if (sysMapFileInShmemReadOnly(fd, pMap) != 0) {
         fprintf(stderr, "ERROR: Unable to map %s\n", fileName);
         close(fd);
         goto bail;
diff --git a/libdex/SysUtil.c b/libdex/SysUtil.c
index 08dc67c..eaa612b 100644
--- a/libdex/SysUtil.c
+++ b/libdex/SysUtil.c
@@ -160,7 +160,7 @@
  * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
  * value and does not disturb "pMap".
  */
-int sysMapFileInShmem(int fd, MemMapping* pMap)
+int sysMapFileInShmemReadOnly(int fd, MemMapping* pMap)
 {
 #ifdef HAVE_POSIX_FILEMAP
     off_t start;
@@ -172,32 +172,72 @@
     if (getFileStartAndLength(fd, &start, &length) < 0)
         return -1;
 
-    /*
-     * This was originally (PROT_READ, MAP_SHARED), but we want to be able
-     * to make local edits for verification errors and debugger breakpoints.
-     * So we map it read-write and private, but use mprotect to mark the
-     * pages read-only.  This should yield identical results so long as the
-     * pages are left read-only.
-     */
-    memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
-            fd, start);
+    memPtr = mmap(NULL, length, PROT_READ, MAP_FILE | MAP_SHARED, fd, start);
     if (memPtr == MAP_FAILED) {
-        LOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s\n", (int) length,
+        LOGW("mmap(%d, RO, FILE|SHARED, %d, %d) failed: %s\n", (int) length,
             fd, (int) start, strerror(errno));
         return -1;
     }
-    if (mprotect(memPtr, length, PROT_READ) < 0) {
-        LOGW("mprotect(%p, %d, PROT_READ) failed: %s\n",
-            memPtr, length, strerror(errno));
-        (void) munmap(memPtr, length);
-        return -1;
-    }
 
     pMap->baseAddr = pMap->addr = memPtr;
     pMap->baseLength = pMap->length = length;
 
     return 0;
 #else
+    sysFakeMapFile(fd, pMap);
+#endif
+}
+
+/*
+ * Map a file (from fd's current offset) into a private, read-write memory
+ * segment that will be marked read-only (a/k/a "writable read-only").  The
+ * file offset must be a multiple of the system page size.
+ *
+ * In some cases the mapping will be fully writable (e.g. for files on
+ * FAT filesystems).
+ *
+ * On success, returns 0 and fills out "pMap".  On failure, returns a nonzero
+ * value and does not disturb "pMap".
+ */
+int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap)
+{
+#ifdef HAVE_POSIX_FILEMAP
+    off_t start;
+    size_t length;
+    void* memPtr;
+
+    assert(pMap != NULL);
+
+    if (getFileStartAndLength(fd, &start, &length) < 0)
+        return -1;
+
+    memPtr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE,
+            fd, start);
+    if (memPtr == MAP_FAILED) {
+        LOGW("mmap(%d, R/W, FILE|PRIVATE, %d, %d) failed: %s\n", (int) length,
+            fd, (int) start, strerror(errno));
+        return -1;
+    }
+    if (mprotect(memPtr, length, PROT_READ) < 0) {
+        /* this fails with EACCESS on FAT filesystems, e.g. /sdcard */
+        int err = errno;
+        LOGV("mprotect(%p, %d, PROT_READ) failed: %s\n",
+            memPtr, length, strerror(err));
+        LOGD("mprotect(RO) failed (%d), file will remain read-write\n", err);
+    }
+
+    pMap->baseAddr = pMap->addr = memPtr;
+    pMap->baseLength = pMap->length = length;
+
+    return 0;
+#else
+    sysFakeMapFile(fd, pMap);
+#endif
+}
+
+#ifndef HAVE_POSIX_FILEMAP
+int sysFakeMapFile(int fd, MemMapping* pMap)
+{
     /* No MMAP, just fake it by copying the bits.
        For Win32 we could use MapViewOfFile if really necessary
        (see libs/utils/FileMap.cpp).
@@ -222,8 +262,8 @@
     pMap->baseLength = pMap->length = length;
 
     return 0;
-#endif
 }
+#endif
 
 /*
  * Map part of a file (from fd's current offset) into a shared, read-only
@@ -314,7 +354,7 @@
     int prot = wantReadWrite ? (PROT_READ|PROT_WRITE) : (PROT_READ);
     if (mprotect(alignAddr, alignLength, prot) != 0) {
         int err = errno;
-        LOGW("mprotect (%p,%zd,%d) failed: %s\n",
+        LOGV("mprotect (%p,%zd,%d) failed: %s\n",
             alignAddr, alignLength, prot, strerror(errno));
         return (errno != 0) ? errno : -1;
     }
diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h
index 6ee352b..b300a7b 100644
--- a/libdex/SysUtil.h
+++ b/libdex/SysUtil.h
@@ -66,10 +66,19 @@
  *
  * On success, "pMap" is filled in, and zero is returned.
  */
-int sysMapFileInShmem(int fd, MemMapping* pMap);
+int sysMapFileInShmemReadOnly(int fd, MemMapping* pMap);
 
 /*
- * Like sysMapFileInShmem, but on only part of a file.
+ * Map a file (from fd's current offset) into a shared, read-only memory
+ * segment that can be made writable.  (In some cases, such as when
+ * mapping a file on a FAT filesystem, the result may be fully writable.)
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysMapFileInShmemWritableReadOnly(int fd, MemMapping* pMap);
+
+/*
+ * Like sysMapFileInShmemReadOnly, but on only part of a file.
  */
 int sysMapFileSegmentInShmem(int fd, off_t start, long length,
     MemMapping* pMap);
diff --git a/libdex/ZipArchive.c b/libdex/ZipArchive.c
index 3f88e7d..7c7e18e 100644
--- a/libdex/ZipArchive.c
+++ b/libdex/ZipArchive.c
@@ -310,7 +310,7 @@
 
     pArchive->mFd = fd;
 
-    if (sysMapFileInShmem(pArchive->mFd, &map) != 0) {
+    if (sysMapFileInShmemReadOnly(pArchive->mFd, &map) != 0) {
         err = -1;
         LOGW("Map of '%s' failed\n", debugFileName);
         goto bail;
diff --git a/tests/071-dexfile/expected.txt b/tests/071-dexfile/expected.txt
index 8aa4061..b7af75e 100644
--- a/tests/071-dexfile/expected.txt
+++ b/tests/071-dexfile/expected.txt
@@ -1,4 +1,3 @@
-My path is: test-ex.jar
 Constructing another
 Got expected ULE
 done
diff --git a/vm/DvmDex.c b/vm/DvmDex.c
index 20a4376..258d768 100644
--- a/vm/DvmDex.c
+++ b/vm/DvmDex.c
@@ -130,7 +130,7 @@
         goto bail;
     }
 
-    if (sysMapFileInShmem(fd, &memMap) != 0) {
+    if (sysMapFileInShmemWritableReadOnly(fd, &memMap) != 0) {
         LOGE("Unable to map file\n");
         goto bail;
     }
@@ -245,16 +245,16 @@
     }
 
     LOGV("+++ change byte at %p from 0x%02x to 0x%02x\n", addr, *addr, newVal);
-    if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) < 0) {
-        LOGE("access change failed\n");
-        return false;
+    if (sysChangeMapAccess(addr, 1, true, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RW) failed\n");
+        /* expected on files mounted from FAT; keep going (may crash) */
     }
 
     *addr = newVal;
 
-    if (sysChangeMapAccess(addr, 1, false, &pDvmDex->memMap) < 0) {
-        LOGW("WARNING: unable to restore read-only access on mapping\n");
-        /* not fatal, keep going */
+    if (sysChangeMapAccess(addr, 1, false, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RO) failed\n");
+        /* expected on files mounted from FAT; keep going */
     }
 
     return true;
@@ -274,16 +274,16 @@
     }
 
     LOGV("+++ change 2byte at %p from 0x%04x to 0x%04x\n", addr, *addr, newVal);
-    if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) < 0) {
-        LOGE("access change failed\n");
-        return false;
+    if (sysChangeMapAccess(addr, 2, true, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RW) failed\n");
+        /* expected on files mounted from FAT; keep going (may crash) */
     }
 
     *addr = newVal;
 
-    if (sysChangeMapAccess(addr, 2, false, &pDvmDex->memMap) < 0) {
-        LOGW("WARNING: unable to restore read-only access on mapping\n");
-        /* not fatal, keep going */
+    if (sysChangeMapAccess(addr, 2, false, &pDvmDex->memMap) != 0) {
+        LOGD("NOTE: DEX page access change (->RO) failed\n");
+        /* expected on files mounted from FAT; keep going */
     }
 
     return true;