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