Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4dbcd23b authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "Add SharedMemory API"

parents 677c0db1 dea6a027
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -729,6 +729,7 @@ aidl_files := \
	frameworks/base/core/java/android/os/DropBoxManager.aidl \
	frameworks/base/core/java/android/os/Bundle.aidl \
	frameworks/base/core/java/android/os/Debug.aidl \
	frameworks/base/core/java/android/os/SharedMemory.aidl \
	frameworks/base/core/java/android/os/StrictMode.aidl \
	frameworks/base/core/java/android/accessibilityservice/AccessibilityServiceInfo.aidl \
	frameworks/base/core/java/android/net/Network.aidl \
+19 −3
Original line number Diff line number Diff line
@@ -31023,12 +31023,12 @@ package android.os {
  public class MemoryFile {
    ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
    method public synchronized boolean allowPurging(boolean) throws java.io.IOException;
    method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
    method public void close();
    method protected void finalize();
    method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
    method public java.io.InputStream getInputStream();
    method public java.io.OutputStream getOutputStream();
    method public boolean isPurgingAllowed();
    method public deprecated boolean isPurgingAllowed();
    method public int length();
    method public int readBytes(byte[], int, int, int) throws java.io.IOException;
    method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -31453,6 +31453,22 @@ package android.os {
    field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR;
  }
  public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
    method public void close();
    method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
    method public int describeContents();
    method public int getFd();
    method public java.io.FileDescriptor getFileDescriptor();
    method public int getSize();
    method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
    method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
    method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
    method public boolean setProtect(int);
    method public static void unmap(java.nio.ByteBuffer);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
  }
  public class StatFs {
    ctor public StatFs(java.lang.String);
    method public deprecated int getAvailableBlocks();
+19 −3
Original line number Diff line number Diff line
@@ -33773,12 +33773,12 @@ package android.os {
  public class MemoryFile {
    ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
    method public synchronized boolean allowPurging(boolean) throws java.io.IOException;
    method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
    method public void close();
    method protected void finalize();
    method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
    method public java.io.InputStream getInputStream();
    method public java.io.OutputStream getOutputStream();
    method public boolean isPurgingAllowed();
    method public deprecated boolean isPurgingAllowed();
    method public int length();
    method public int readBytes(byte[], int, int, int) throws java.io.IOException;
    method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -34232,6 +34232,22 @@ package android.os {
    field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR;
  }
  public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
    method public void close();
    method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
    method public int describeContents();
    method public int getFd();
    method public java.io.FileDescriptor getFileDescriptor();
    method public int getSize();
    method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
    method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
    method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
    method public boolean setProtect(int);
    method public static void unmap(java.nio.ByteBuffer);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
  }
  public class StatFs {
    ctor public StatFs(java.lang.String);
    method public deprecated int getAvailableBlocks();
+19 −3
Original line number Diff line number Diff line
@@ -31154,12 +31154,12 @@ package android.os {
  public class MemoryFile {
    ctor public MemoryFile(java.lang.String, int) throws java.io.IOException;
    method public synchronized boolean allowPurging(boolean) throws java.io.IOException;
    method public deprecated synchronized boolean allowPurging(boolean) throws java.io.IOException;
    method public void close();
    method protected void finalize();
    method public java.io.FileDescriptor getFileDescriptor() throws java.io.IOException;
    method public java.io.InputStream getInputStream();
    method public java.io.OutputStream getOutputStream();
    method public boolean isPurgingAllowed();
    method public deprecated boolean isPurgingAllowed();
    method public int length();
    method public int readBytes(byte[], int, int, int) throws java.io.IOException;
    method public void writeBytes(byte[], int, int, int) throws java.io.IOException;
@@ -31585,6 +31585,22 @@ package android.os {
    field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR;
  }
  public final class SharedMemory implements java.io.Closeable android.os.Parcelable {
    method public void close();
    method public static android.os.SharedMemory create(java.lang.String, int) throws android.system.ErrnoException;
    method public int describeContents();
    method public int getFd();
    method public java.io.FileDescriptor getFileDescriptor();
    method public int getSize();
    method public java.nio.ByteBuffer map(int, int, int) throws android.system.ErrnoException;
    method public java.nio.ByteBuffer mapReadOnly() throws android.system.ErrnoException;
    method public java.nio.ByteBuffer mapReadWrite() throws android.system.ErrnoException;
    method public boolean setProtect(int);
    method public static void unmap(java.nio.ByteBuffer);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.os.SharedMemory> CREATOR;
  }
  public class StatFs {
    ctor public StatFs(java.lang.String);
    method public deprecated int getAvailableBlocks();
+66 −88
Original line number Diff line number Diff line
@@ -16,68 +16,50 @@

package android.os;

import android.util.Log;
import android.system.ErrnoException;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;


/**
 * MemoryFile is a wrapper for the Linux ashmem driver.
 * MemoryFiles are backed by shared memory, which can be optionally
 * set to be purgeable.
 * MemoryFile is a wrapper for {@link SharedMemory} which can optionally be set to purgeable.
 *
 * Applications should generally prefer to use {@link SharedMemory} which offers more flexible
 * access & control over the shared memory region than MemoryFile does.
 *
 * Purgeable files may have their contents reclaimed by the kernel
 * in low memory conditions (only if allowPurging is set to true).
 * After a file is purged, attempts to read or write the file will
 * cause an IOException to be thrown.
 */
public class MemoryFile
{
public class MemoryFile {
    private static String TAG = "MemoryFile";

    // mmap(2) protection flags from <sys/mman.h>
    private static final int PROT_READ = 0x1;
    private static final int PROT_WRITE = 0x2;

    private static native FileDescriptor native_open(String name, int length) throws IOException;
    // returns memory address for ashmem region
    private static native long native_mmap(FileDescriptor fd, int length, int mode)
            throws IOException;
    private static native void native_munmap(long addr, int length) throws IOException;
    private static native void native_close(FileDescriptor fd);
    private static native int native_read(FileDescriptor fd, long address, byte[] buffer,
            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
    private static native void native_write(FileDescriptor fd, long address, byte[] buffer,
            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
    private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
    // Returns 'true' if purged, 'false' otherwise
    private static native boolean native_pin(FileDescriptor fd, boolean pin) throws IOException;
    private static native int native_get_size(FileDescriptor fd) throws IOException;

    private FileDescriptor mFD;        // ashmem file descriptor
    private long mAddress;   // address of ashmem memory
    private int mLength;    // total length of our ashmem region
    private SharedMemory mSharedMemory;
    private ByteBuffer mMapping;
    private boolean mAllowPurging = false;  // true if our ashmem region is unpinned

    /**
     * Allocates a new ashmem region. The region is initially not purgable.
     *
     * @param name optional name for the file (can be null).
     * @param length of the memory file in bytes, must be non-negative.
     * @param length of the memory file in bytes, must be positive.
     * @throws IOException if the memory file could not be created.
     */
    public MemoryFile(String name, int length) throws IOException {
        mLength = length;
        if (length >= 0) {
            mFD = native_open(name, length);
        } else {
            throw new IOException("Invalid length: " + length);
        }

        if (length > 0) {
            mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
        } else {
            mAddress = 0;
        try {
            mMapping = mSharedMemory.mapReadWrite();
            mSharedMemory = SharedMemory.create(name, length);
        } catch (ErrnoException ex) {
            ex.rethrowAsIOException();
        }
    }

@@ -87,9 +69,7 @@ public class MemoryFile
     */
    public void close() {
        deactivate();
        if (!isClosed()) {
            native_close(mFD);
        }
        mSharedMemory.close();
    }

    /**
@@ -100,35 +80,30 @@ public class MemoryFile
     * @hide
     */
    void deactivate() {
        if (!isDeactivated()) {
            try {
                native_munmap(mAddress, mLength);
                mAddress = 0;
            } catch (IOException ex) {
                Log.e(TAG, ex.toString());
            }
        if (mMapping != null) {
            SharedMemory.unmap(mMapping);
            mMapping = null;
        }
    }

    /**
     * Checks whether the memory file has been deactivated.
     */
    private boolean isDeactivated() {
        return mAddress == 0;
    private void checkActive() throws IOException {
        if (mMapping == null) {
            throw new IOException("MemoryFile has been deactivated");
        }
    }

    /**
     * Checks whether the memory file has been closed.
     */
    private boolean isClosed() {
        return !mFD.valid();
    private void beginAccess() throws IOException {
        checkActive();
        if (mAllowPurging) {
            if (native_pin(mSharedMemory.getFileDescriptor(), true)) {
                throw new IOException("MemoryFile has been purged");
            }
        }
    }

    @Override
    protected void finalize() {
        if (!isClosed()) {
            Log.e(TAG, "MemoryFile.finalize() called while ashmem still open");
            close();
    private void endAccess() throws IOException {
        if (mAllowPurging) {
            native_pin(mSharedMemory.getFileDescriptor(), false);
        }
    }

@@ -138,14 +113,19 @@ public class MemoryFile
     * @return file length.
     */
    public int length() {
        return mLength;
        return mSharedMemory.getSize();
    }

    /**
     * Is memory file purging enabled?
     *
     * @return true if the file may be purged.
     *
     * @deprecated Purgable is considered generally fragile and hard to use safely. Applications
     * are recommend to instead use {@link android.content.ComponentCallbacks2#onTrimMemory(int)}
     * to react to memory events and release shared memory regions as appropriate.
     */
    @Deprecated
    public boolean isPurgingAllowed() {
        return mAllowPurging;
    }
@@ -156,11 +136,16 @@ public class MemoryFile
     * @param allowPurging true if the operating system can purge the contents
     * of the file in low memory situations
     * @return previous value of allowPurging
     *
     * @deprecated Purgable is considered generally fragile and hard to use safely. Applications
     * are recommend to instead use {@link android.content.ComponentCallbacks2#onTrimMemory(int)}
     * to react to memory events and release shared memory regions as appropriate.
     */
    @Deprecated
    synchronized public boolean allowPurging(boolean allowPurging) throws IOException {
        boolean oldValue = mAllowPurging;
        if (oldValue != allowPurging) {
            native_pin(mFD, !allowPurging);
            native_pin(mSharedMemory.getFileDescriptor(), !allowPurging);
            mAllowPurging = allowPurging;
        }
        return oldValue;
@@ -197,16 +182,14 @@ public class MemoryFile
     */
    public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
            throws IOException {
        if (isDeactivated()) {
            throw new IOException("Can't read from deactivated memory file.");
        }
        if (destOffset < 0 || destOffset > buffer.length || count < 0
                || count > buffer.length - destOffset
                || srcOffset < 0 || srcOffset > mLength
                || count > mLength - srcOffset) {
            throw new IndexOutOfBoundsException();
        beginAccess();
        try {
            mMapping.position(srcOffset);
            mMapping.get(buffer, destOffset, count);
        } finally {
            endAccess();
        }
        return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
        return count;
    }

    /**
@@ -221,16 +204,13 @@ public class MemoryFile
     */
    public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
            throws IOException {
        if (isDeactivated()) {
            throw new IOException("Can't write to deactivated memory file.");
        }
        if (srcOffset < 0 || srcOffset > buffer.length || count < 0
                || count > buffer.length - srcOffset
                || destOffset < 0 || destOffset > mLength
                || count > mLength - destOffset) {
            throw new IndexOutOfBoundsException();
        beginAccess();
        try {
            mMapping.position(destOffset);
            mMapping.put(buffer, srcOffset, count);
        } finally {
            endAccess();
        }
        native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
    }

    /**
@@ -239,11 +219,9 @@ public class MemoryFile
     * The returned file descriptor is not duplicated.
     *
     * @throws IOException If the memory file has been closed.
     *
     * @hide
     */
    public FileDescriptor getFileDescriptor() throws IOException {
        return mFD;
        return mSharedMemory.getFileDescriptor();
    }

    /**
@@ -266,10 +244,10 @@ public class MemoryFile

        @Override
        public int available() throws IOException {
            if (mOffset >= mLength) {
            if (mOffset >= mSharedMemory.getSize()) {
                return 0;
            }
            return mLength - mOffset;
            return mSharedMemory.getSize() - mOffset;
        }

        @Override
@@ -319,8 +297,8 @@ public class MemoryFile

        @Override
        public long skip(long n) throws IOException {
            if (mOffset + n > mLength) {
                n = mLength - mOffset;
            if (mOffset + n > mSharedMemory.getSize()) {
                n = mSharedMemory.getSize() - mOffset;
            }
            mOffset += n;
            return n;
Loading