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
46c20cadbdad0cdfe8e56431c22bd26ae666101e89Ashok Bhat    private static native long native_mmap(FileDescriptor fd, int length, int mode)
47963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert            throws IOException;
48c20cadbdad0cdfe8e56431c22bd26ae666101e89Ashok Bhat    private static native void native_munmap(long addr, int length) throws IOException;
49761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private static native void native_close(FileDescriptor fd);
50c20cadbdad0cdfe8e56431c22bd26ae666101e89Ashok Bhat    private static native int native_read(FileDescriptor fd, long address, byte[] buffer,
519fc2e9c965c68d56a0caf812f7f6d38d15317063Bjorn Bringert            int srcOffset, int destOffset, int count, boolean isUnpinned) throws IOException;
52c20cadbdad0cdfe8e56431c22bd26ae666101e89Ashok Bhat    private static native void native_write(FileDescriptor fd, long 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
58c20cadbdad0cdfe8e56431c22bd26ae666101e89Ashok Bhat    private long 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).
66f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath     * @param length of the memory file in bytes, must be non-negative.
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;
71f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath        if (length >= 0) {
72f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath            mFD = native_open(name, length);
73f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath        } else {
74f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath            throw new IOException("Invalid length: " + length);
75f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath        }
76f626ca2c96f629627a8df6944c9b0d774e6e67aeNarayan Kamath
77a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        if (length > 0) {
78a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert            mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
79a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert        } else {
80a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert            mAddress = 0;
81963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert        }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
85963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * Closes the memory file. If there are no other open references to the memory
86963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * file, it will be deleted.
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() {
89761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        deactivate();
90761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (!isClosed()) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_close(mFD);
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
95963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    /**
96963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * Unmaps the memory file from the process's memory space, but does not close it.
97963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * After this method has been called, read and write operations through this object
98963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * will fail, but {@link #getFileDescriptor()} will still return a valid file descriptor.
99963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
100963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * @hide
101963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     */
102a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert    void deactivate() {
103761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (!isDeactivated()) {
104761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            try {
105761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert                native_munmap(mAddress, mLength);
106761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert                mAddress = 0;
107761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            } catch (IOException ex) {
108761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert                Log.e(TAG, ex.toString());
109761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            }
110761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        }
111761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    }
112761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
113761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    /**
114761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * Checks whether the memory file has been deactivated.
115761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     */
116761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private boolean isDeactivated() {
117761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        return mAddress == 0;
118761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    }
119761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
120761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    /**
121761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * Checks whether the memory file has been closed.
122761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     */
123761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    private boolean isClosed() {
124761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        return !mFD.valid();
125761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert    }
126761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() {
129761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (!isClosed()) {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "MemoryFile.finalize() called while ashmem still open");
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            close();
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
134112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns the length of the memory file.
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return file length.
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int length() {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLength;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Is memory file purging enabled?
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the file may be purged.
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isPurgingAllowed() {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mAllowPurging;
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enables or disables purging of the memory file.
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param allowPurging true if the operating system can purge the contents
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of the file in low memory situations
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return previous value of allowPurging
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized public boolean allowPurging(boolean allowPurging) throws IOException {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean oldValue = mAllowPurging;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (oldValue != allowPurging) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            native_pin(mFD, !allowPurging);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAllowPurging = allowPurging;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return oldValue;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new InputStream for reading from the memory file.
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     @return InputStream
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public InputStream getInputStream() {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new MemoryInputStream();
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new OutputStream for writing to the memory file.
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     @return OutputStream
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     public OutputStream getOutputStream() {
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new MemoryOutputStream();
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Reads bytes from the memory file.
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Will throw an IOException if the file has been purged.
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param buffer byte array to read bytes into.
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param srcOffset offset into the memory file to read from.
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param destOffset offset into the byte array buffer to read into.
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param count number of bytes to read.
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return number of bytes read.
196761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * @throws IOException if the memory file has been purged or deactivated.
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
198112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson    public int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
200761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (isDeactivated()) {
201761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            throw new IOException("Can't read from deactivated memory file.");
202761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        }
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (destOffset < 0 || destOffset > buffer.length || count < 0
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > buffer.length - destOffset
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || srcOffset < 0 || srcOffset > mLength
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > mLength - srcOffset) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException();
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Write bytes to the memory file.
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Will throw an IOException if the file has been purged.
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param buffer byte array to write bytes from.
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param srcOffset offset into the byte array buffer to write from.
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param destOffset offset  into the memory file to write to.
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param count number of bytes to write.
220761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert     * @throws IOException if the memory file has been purged or deactivated.
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws IOException {
224761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        if (isDeactivated()) {
225761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert            throw new IOException("Can't write to deactivated memory file.");
226761e0918d30b6a3f292625b44b86dffd1538bc78Bjorn Bringert        }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (srcOffset < 0 || srcOffset > buffer.length || count < 0
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > buffer.length - srcOffset
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || destOffset < 0 || destOffset > mLength
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || count > mLength - destOffset) {
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
236963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    /**
237a006b47298539d89dc7a06b54c070cb3e986352aBjorn Bringert     * Gets a FileDescriptor for the memory file.
238963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
239963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * The returned file descriptor is not duplicated.
240963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
241963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * @throws IOException If the memory file has been closed.
242963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     *
243963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     * @hide
244963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert     */
245963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    public FileDescriptor getFileDescriptor() throws IOException {
246963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert        return mFD;
247963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    }
248963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert
249963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    /**
2507bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen     * Returns the size of the memory file that the file descriptor refers to,
2517bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen     * or -1 if the file descriptor does not refer to a memory file.
252ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     *
253ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     * @throws IOException If <code>fd</code> is not a valid file descriptor.
254ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     *
255ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     * @hide
256ec100900e63a8374ac010e7131d9c7e54c5e6984Marco Nelissen     */
2577bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen    public static int getSize(FileDescriptor fd) throws IOException {
2587bcbd511731e13b9f2778e6aa6c633417d266f5eMarco Nelissen        return native_get_size(fd);
259963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert    }
260963cd006c45716b034f656bf7e7179e6476f7e4dBjorn Bringert
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class MemoryInputStream extends InputStream {
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mMark = 0;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mOffset = 0;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private byte[] mSingleByte;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int available() throws IOException {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mOffset >= mLength) {
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mLength - mOffset;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean markSupported() {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void mark(int readlimit) {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMark = mOffset;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void reset() throws IOException {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOffset = mMark;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int read() throws IOException {
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSingleByte == null) {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSingleByte = new byte[1];
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int result = read(mSingleByte, 0, 1);
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result != 1) {
297c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                return -1;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSingleByte[0];
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int read(byte buffer[], int offset, int count) throws IOException {
304c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            if (offset < 0 || count < 0 || offset + count > buffer.length) {
305c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                // readBytes() also does this check, but we need to do it before
306c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                // changing count.
307c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                throw new IndexOutOfBoundsException();
308c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            }
309c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            count = Math.min(count, available());
310c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            if (count < 1) {
311c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert                return -1;
312c1823701cc76790494fb622fe58f0942236cd7d0Bjorn Bringert            }
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int result = readBytes(buffer, mOffset, offset, count);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (result > 0) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mOffset += result;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public long skip(long n) throws IOException {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mOffset + n > mLength) {
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                n = mLength - mOffset;
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mOffset += n;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return n;
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class MemoryOutputStream extends OutputStream {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mOffset = 0;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private byte[] mSingleByte;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void write(byte buffer[], int offset, int count) throws IOException {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            writeBytes(buffer, offset, mOffset, count);
338112d339673c379b71a989bd33b73648aafe58ce1Jesse Wilson            mOffset += count;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void write(int oneByte) throws IOException {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSingleByte == null) {
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSingleByte = new byte[1];
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSingleByte[0] = (byte)oneByte;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            write(mSingleByte, 0, 1);
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
351