auto import from //depot/cupcake/@135843
diff --git a/libs/utils/MemoryHeapPmem.cpp b/libs/utils/MemoryHeapPmem.cpp
new file mode 100644
index 0000000..eba2b30
--- /dev/null
+++ b/libs/utils/MemoryHeapPmem.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#define LOG_TAG "MemoryHeapPmem"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <cutils/log.h>
+
+#include <utils/MemoryHeapPmem.h>
+#include <utils/MemoryHeapBase.h>
+
+#if HAVE_ANDROID_OS
+#include <linux/android_pmem.h>
+#endif
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryPmem::MemoryPmem(const sp<MemoryHeapPmem>& heap)
+    : BnMemory(), mClientHeap(heap)
+{
+}
+
+MemoryHeapPmem::MemoryPmem::~MemoryPmem() {
+    if (mClientHeap != NULL) {
+        mClientHeap->remove(this);
+    }
+}
+
+// ---------------------------------------------------------------------------
+
+class SubRegionMemory : public MemoryHeapPmem::MemoryPmem {
+public:
+    SubRegionMemory(const sp<MemoryHeapPmem>& heap, ssize_t offset, size_t size);
+    virtual ~SubRegionMemory();
+    virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
+private:
+    friend class MemoryHeapPmem;
+    void revoke();
+    size_t              mSize;
+    ssize_t             mOffset;
+};
+
+SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
+        ssize_t offset, size_t size)
+    : MemoryHeapPmem::MemoryPmem(heap), mSize(size), mOffset(offset)
+{
+#ifndef NDEBUG
+    void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + offset);
+    memset(start_ptr, 0xda, size);
+#endif
+
+#if HAVE_ANDROID_OS
+    if (size > 0) {
+        const size_t pagesize = getpagesize();
+        size = (size + pagesize-1) & ~(pagesize-1);
+        int our_fd = heap->heapID();
+        struct pmem_region sub = { offset, size };
+        int err = ioctl(our_fd, PMEM_MAP, &sub);
+        LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+                "mFD=%d, sub.offset=%lu, sub.size=%lu",
+                strerror(errno), our_fd, sub.offset, sub.len);
+}
+#endif
+}
+
+sp<IMemoryHeap> SubRegionMemory::getMemory(ssize_t* offset, size_t* size) const
+{
+    if (offset) *offset = mOffset;
+    if (size)   *size = mSize;
+    return getHeap();
+}
+
+SubRegionMemory::~SubRegionMemory()
+{
+    revoke();
+}
+
+
+void SubRegionMemory::revoke()
+{
+    // NOTE: revoke() doesn't need to be protected by a lock because it
+    // can only be called from MemoryHeapPmem::revoke(), which means
+    // that we can't be in ~SubRegionMemory(), or in ~SubRegionMemory(),
+    // which means MemoryHeapPmem::revoke() wouldn't have been able to 
+    // promote() it.
+    
+#if HAVE_ANDROID_OS
+    if (mSize != NULL) {
+        const sp<MemoryHeapPmem>& heap(getHeap());
+        int our_fd = heap->heapID();
+        struct pmem_region sub;
+        sub.offset = mOffset;
+        sub.len = mSize;
+        int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+        LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+                "mFD=%d, sub.offset=%lu, sub.size=%lu",
+                strerror(errno), our_fd, sub.offset, sub.len);
+        mSize = 0;
+    }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
+        uint32_t flags)
+    : HeapInterface(), MemoryHeapBase()
+{
+    char const * const device = pmemHeap->getDevice();
+#if HAVE_ANDROID_OS
+    if (device) {
+        int fd = open(device, O_RDWR);
+        LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
+        if (fd >= 0) {
+            int err = ioctl(fd, PMEM_CONNECT, pmemHeap->heapID());
+            if (err < 0) {
+                LOGE("PMEM_CONNECT failed (%s), mFD=%d, sub-fd=%d",
+                        strerror(errno), fd, pmemHeap->heapID());
+                close(fd);
+            } else {
+                // everything went well...
+                mParentHeap = pmemHeap;
+                MemoryHeapBase::init(fd, 
+                        pmemHeap->getBase(),
+                        pmemHeap->getSize(),
+                        pmemHeap->getFlags() | flags,
+                        device);
+            }
+        }
+    }
+#else
+    mParentHeap = pmemHeap;
+    MemoryHeapBase::init( 
+            dup(pmemHeap->heapID()),
+            pmemHeap->getBase(),
+            pmemHeap->getSize(),
+            pmemHeap->getFlags() | flags,
+            device);
+#endif
+}
+
+MemoryHeapPmem::~MemoryHeapPmem()
+{
+}
+
+sp<IMemory> MemoryHeapPmem::mapMemory(size_t offset, size_t size)
+{
+    sp<MemoryPmem> memory = createMemory(offset, size);
+    if (memory != 0) {
+        Mutex::Autolock _l(mLock);
+        mAllocations.add(memory);
+    }
+    return memory;
+}
+
+sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
+        size_t offset, size_t size)
+{
+    sp<SubRegionMemory> memory;
+    if (heapID() > 0) 
+        memory = new SubRegionMemory(this, offset, size);
+    return memory;
+}
+
+status_t MemoryHeapPmem::slap()
+{
+#if HAVE_ANDROID_OS
+    size_t size = getSize();
+    const size_t pagesize = getpagesize();
+    size = (size + pagesize-1) & ~(pagesize-1);
+    int our_fd = getHeapID();
+    struct pmem_region sub = { 0, size };
+    int err = ioctl(our_fd, PMEM_MAP, &sub);
+    LOGE_IF(err<0, "PMEM_MAP failed (%s), "
+            "mFD=%d, sub.offset=%lu, sub.size=%lu",
+            strerror(errno), our_fd, sub.offset, sub.len);
+    return -errno;
+#else
+    return NO_ERROR;
+#endif
+}
+
+status_t MemoryHeapPmem::unslap()
+{
+#if HAVE_ANDROID_OS
+    size_t size = getSize();
+    const size_t pagesize = getpagesize();
+    size = (size + pagesize-1) & ~(pagesize-1);
+    int our_fd = getHeapID();
+    struct pmem_region sub = { 0, size };
+    int err = ioctl(our_fd, PMEM_UNMAP, &sub);
+    LOGE_IF(err<0, "PMEM_UNMAP failed (%s), "
+            "mFD=%d, sub.offset=%lu, sub.size=%lu",
+            strerror(errno), our_fd, sub.offset, sub.len);
+    return -errno;
+#else
+    return NO_ERROR;
+#endif
+}
+
+void MemoryHeapPmem::revoke()
+{
+    SortedVector< wp<MemoryPmem> > allocations;
+
+    { // scope for lock
+        Mutex::Autolock _l(mLock);
+        allocations = mAllocations;
+    }
+    
+    ssize_t count = allocations.size();
+    for (ssize_t i=0 ; i<count ; i++) {
+        sp<MemoryPmem> memory(allocations[i].promote());
+        if (memory != 0)
+            memory->revoke();
+    }
+}
+
+void MemoryHeapPmem::remove(const wp<MemoryPmem>& memory)
+{
+    Mutex::Autolock _l(mLock);
+    mAllocations.remove(memory);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android