19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.os;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringertimport java.io.FileDescriptor;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * MemoryFile is a wrapper for the Linux ashmem driver.
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * MemoryFiles are backed by shared memory, which can be optionally
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * set to be purgeable.
31112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson * Purgeable files may have their contents reclaimed by the kernel
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in low memory conditions (only if allowPurging is set to true).
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * After a file is purged, attempts to read or write the file will
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cause an IOException to be thrown.
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class MemoryFile
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String TAG = "MemoryFile";
39761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
40963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    // mmap(2) protection flags from <sys/mman.h>
41963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    private static final int PROT_READ = 0x1;
42963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    private static final int PROT_WRITE = 0x2;
43963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert
44761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native FileDescriptor native_open(String name, int length) throws IOException;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // returns memory address for ashmem region
46963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    private static native int native_mmap(FileDescriptor fd, int length, int mode)
47963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert            throws IOException;
48761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native void native_munmap(int addr, int length) throws IOException;
49761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native void native_close(FileDescriptor fd);
50761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native int native_read(FileDescriptor fd, int address, byte[] buffer,
519fc2e9c965c68d56a0caf812f7f6d38d15317063Bjorn Bringert            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
52761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native void native_write(FileDescriptor fd, int address, byte[] buffer,
539fc2e9c965c68d56a0caf812f7f6d38d15317063Bjorn Bringert            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
54761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native void native_pin(FileDescriptor fd, boolean pin) throws IOException;
557bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen    private static native int native_get_size(FileDescriptor fd) throws IOException;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
57761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private FileDescriptor mFD;        // ashmem file descriptor
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mAddress;   // address of ashmem memory
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mLength;    // total length of our ashmem region
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAllowPurging = false;  // true if our ashmem region is unpinned
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
63963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * Allocates a new ashmem region. The region is initially not purgable.
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param name optional name for the file (can be null).
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param length of the memory file in bytes.
679fc2e9c965c68d56a0caf812f7f6d38d15317063Bjorn Bringert     * @throws IOException if the memory file could not be created.
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
699fc2e9c965c68d56a0caf812f7f6d38d15317063Bjorn Bringert    public MemoryFile(String name, int length) throws IOException {
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLength = length;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFD = native_open(name, length);
72a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        if (length > 0) {
73a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert            mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
74a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        } else {
75a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert            mAddress = 0;
76963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert        }
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
80963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * Closes the memory file. If there are no other open references to the memory
81963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * file, it will be deleted.
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() {
84761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        deactivate();
85761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (!isClosed()) {
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_close(mFD);
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
90963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    /**
91963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * Unmaps the memory file from the process's memory space, but does not close it.
92963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * After this method has been called, read and write operations through this object
93963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * will fail, but {@link #getFileDescriptor()} will still return a valid file descriptor.
94963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
95963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * @hide
96963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     */
97a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert    void deactivate() {
98761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (!isDeactivated()) {
99761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            try {
100761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert                native_munmap(mAddress, mLength);
101761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert                mAddress = 0;
102761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            } catch (IOException ex) {
103761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert                Log.e(TAG, ex.toString());
104761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            }
105761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        }
106761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    }
107761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
108761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    /**
109761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * Checks whether the memory file has been deactivated.
110761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     */
111761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private boolean isDeactivated() {
112761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        return mAddress == 0;
113761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    }
114761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
115761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    /**
116761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * Checks whether the memory file has been closed.
117761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     */
118761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private boolean isClosed() {
119761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        return !mFD.valid();
120761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    }
121761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() {
124761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (!isClosed()) {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "MemoryFile.finalize() called while ashmem still open");
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close();
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
129112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the length of the memory file.
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return file length.
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int length() {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLength;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Is memory file purging enabled?
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the file may be purged.
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isPurgingAllowed() {
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAllowPurging;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables purging of the memory file.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allowPurging true if the operating system can purge the contents
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the file in low memory situations
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return previous value of allowPurging
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized public boolean allowPurging(boolean allowPurging) throws IOException {
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean oldValue = mAllowPurging;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (oldValue != allowPurging) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_pin(mFD, !allowPurging);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAllowPurging = allowPurging;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return oldValue;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new InputStream for reading from the memory file.
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     @return InputStream
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public InputStream getInputStream() {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new MemoryInputStream();
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new OutputStream for writing to the memory file.
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     @return OutputStream
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     public OutputStream getOutputStream() {
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new MemoryOutputStream();
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Reads bytes from the memory file.
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Will throw an IOException if the file has been purged.
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param buffer byte array to read bytes into.
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param srcOffset offset into the memory file to read from.
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param destOffset offset into the byte array buffer to read into.
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param count number of bytes to read.
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return number of bytes read.
191761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * @throws IOException if the memory file has been purged or deactivated.
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
193112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson    public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
195761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (isDeactivated()) {
196761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            throw new IOException("Can't read from deactivated memory file.");
197761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (destOffset < 0 || destOffset > buffer.length || count < 0
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > buffer.length - destOffset
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || srcOffset < 0 || srcOffset > mLength
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > mLength - srcOffset) {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Write bytes to the memory file.
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Will throw an IOException if the file has been purged.
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param buffer byte array to write bytes from.
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param srcOffset offset into the byte array buffer to write from.
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param destOffset offset  into the memory file to write to.
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param count number of bytes to write.
215761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * @throws IOException if the memory file has been purged or deactivated.
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
219761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (isDeactivated()) {
220761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            throw new IOException("Can't write to deactivated memory file.");
221761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (srcOffset < 0 || srcOffset > buffer.length || count < 0
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > buffer.length - srcOffset
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || destOffset < 0 || destOffset > mLength
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > mLength - destOffset) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException();
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
231963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    /**
232a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * Gets a FileDescriptor for the memory file.
233963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
234963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * The returned file descriptor is not duplicated.
235963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
236963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * @throws IOException If the memory file has been closed.
237963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
238963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * @hide
239963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     */
240963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    public FileDescriptor getFileDescriptor() throws IOException {
241963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert        return mFD;
242963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    }
243963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert
244963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    /**
2457bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen     * Returns the size of the memory file that the file descriptor refers to,
2467bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen     * or -1 if the file descriptor does not refer to a memory file.
247ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     *
248ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     * @throws IOException If <code>fd</code> is not a valid file descriptor.
249ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     *
250ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     * @hide
251ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     */
2527bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen    public static int getSize(FileDescriptor fd) throws IOException {
2537bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen        return native_get_size(fd);
254963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    }
255963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class MemoryInputStream extends InputStream {
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mMark = 0;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mOffset = 0;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private byte[] mSingleByte;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int available() throws IOException {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mOffset >= mLength) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mLength - mOffset;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean markSupported() {
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void mark(int readlimit) {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMark = mOffset;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void reset() throws IOException {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOffset = mMark;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int read() throws IOException {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSingleByte == null) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSingleByte = new byte[1];
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int result = read(mSingleByte, 0, 1);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result != 1) {
292c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                return -1;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSingleByte[0];
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int read(byte buffer[], int offset, int count) throws IOException {
299c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            if (offset < 0 || count < 0 || offset + count > buffer.length) {
300c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                // readBytes() also does this check, but we need to do it before
301c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                // changing count.
302c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                throw new IndexOutOfBoundsException();
303c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            }
304c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            count = Math.min(count, available());
305c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            if (count < 1) {
306c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                return -1;
307c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            }
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int result = readBytes(buffer, mOffset, offset, count);
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result > 0) {
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOffset += result;
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public long skip(long n) throws IOException {
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mOffset + n > mLength) {
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                n = mLength - mOffset;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOffset += n;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return n;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class MemoryOutputStream extends OutputStream {
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mOffset = 0;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private byte[] mSingleByte;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void write(byte buffer[], int offset, int count) throws IOException {
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            writeBytes(buffer, offset, mOffset, count);
333112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson            mOffset += count;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void write(int oneByte) throws IOException {
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSingleByte == null) {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSingleByte = new byte[1];
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSingleByte[0] = (byte)oneByte;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            write(mSingleByte, 0, 1);
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
346