summaryrefslogtreecommitdiffstats
path: root/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/SharedMemory.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/SharedMemory.java')
-rw-r--r--mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/SharedMemory.java192
1 files changed, 192 insertions, 0 deletions
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/SharedMemory.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/SharedMemory.java
new file mode 100644
index 0000000000..af8b62c382
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/SharedMemory.java
@@ -0,0 +1,192 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.mozglue;
+
+import android.annotation.SuppressLint;
+import android.os.MemoryFile;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+@SuppressLint("DiscouragedPrivateApi")
+public class SharedMemory implements Parcelable {
+ private static final String LOGTAG = "GeckoShmem";
+ private static final Method sGetFDMethod;
+ private ParcelFileDescriptor mDescriptor;
+ private int mSize;
+ private int mId;
+ private long mHandle; // The native pointer.
+ private boolean mIsMapped;
+ private MemoryFile mBackedFile;
+
+ // MemoryFile.getFileDescriptor() is hidden. :(
+ static {
+ Method method = null;
+ try {
+ method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
+ } catch (final NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ sGetFDMethod = method;
+ }
+
+ private SharedMemory(final Parcel in) {
+ mDescriptor = in.readFileDescriptor();
+ mSize = in.readInt();
+ mId = in.readInt();
+ }
+
+ public static final Creator<SharedMemory> CREATOR =
+ new Creator<SharedMemory>() {
+ @Override
+ public SharedMemory createFromParcel(final Parcel in) {
+ return new SharedMemory(in);
+ }
+
+ @Override
+ public SharedMemory[] newArray(final int size) {
+ return new SharedMemory[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return CONTENTS_FILE_DESCRIPTOR;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ // We don't want ParcelFileDescriptor.writeToParcel() to close the fd.
+ dest.writeFileDescriptor(mDescriptor.getFileDescriptor());
+ dest.writeInt(mSize);
+ dest.writeInt(mId);
+ }
+
+ public SharedMemory(final int id, final int size) throws NoSuchMethodException, IOException {
+ if (sGetFDMethod == null) {
+ throw new NoSuchMethodException("MemoryFile.getFileDescriptor() doesn't exist.");
+ }
+ mBackedFile = new MemoryFile(null, size);
+ try {
+ final FileDescriptor fd = (FileDescriptor) sGetFDMethod.invoke(mBackedFile);
+ mDescriptor = ParcelFileDescriptor.dup(fd);
+ mSize = size;
+ mId = id;
+ mBackedFile.allowPurging(false);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ close();
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ public void flush() {
+ if (!mIsMapped) {
+ return;
+ }
+
+ unmap(mHandle, mSize);
+ mHandle = 0;
+ mIsMapped = false;
+ }
+
+ public void close() {
+ flush();
+
+ if (mDescriptor != null) {
+ try {
+ mDescriptor.close();
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ mDescriptor = null;
+ }
+ }
+
+ // Should only be called by process that allocates shared memory.
+ public void dispose() {
+ if (!isValid()) {
+ return;
+ }
+
+ close();
+
+ if (mBackedFile != null) {
+ mBackedFile.close();
+ mBackedFile = null;
+ }
+ }
+
+ private native void unmap(long address, int size);
+
+ public boolean isValid() {
+ return mDescriptor != null;
+ }
+
+ public int getSize() {
+ return mSize;
+ }
+
+ private int getFD() {
+ return isValid() ? mDescriptor.getFd() : -1;
+ }
+
+ public long getPointer() {
+ if (!isValid()) {
+ return 0;
+ }
+
+ if (!mIsMapped) {
+ try {
+ mHandle = map(getFD(), mSize);
+ } catch (final NullPointerException e) {
+ Log.e(LOGTAG, "SharedMemory#" + mId + " error.", e);
+ throw e;
+ }
+ if (mHandle != 0) {
+ mIsMapped = true;
+ }
+ }
+ return mHandle;
+ }
+
+ private native long map(int fd, int size);
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mBackedFile != null) {
+ Log.w(LOGTAG, "dispose() not called before finalizing");
+ }
+ dispose();
+
+ super.finalize();
+ }
+
+ @Override
+ public String toString() {
+ return "SHM("
+ + getSize()
+ + " bytes): id="
+ + mId
+ + ", backing="
+ + mBackedFile
+ + ",fd="
+ + mDescriptor;
+ }
+
+ @Override
+ public boolean equals(final Object that) {
+ return (this == that) || ((that instanceof SharedMemory) && (hashCode() == that.hashCode()));
+ }
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
+}