Android Anonymous shared memory the anonymous shared memory subsystem of the external Android system is implemented in kernel space in the form of a driver and provides a Java calling interface at the application framework layer. At the Android application framework layer, a memoryfile interface is provided to encapsulate the creation and use of anonymous shared memory files, which are implemented in the Frameworks/base/core/java/android/os/memoryfile.java
Public Memoryfile (String name, int length) throws IOException {
mlength = length;
Open the "/dev/ashmem" device file
MFD = Native_open (name, length);
if (length > 0) {
To map an open "/dev/ashmem" device file to the process virtual address space
maddress = Native_mmap (MFD, length, Prot_read | Prot_write);
} else {
maddress = 0;
}
}
The Native_open function is a local function, implemented through JNI in the C + + layer, where the code is located in the Frameworks\base\core\jni\android_os_memoryfile.cpp
Static Jobject Android_os_memoryfile_open (jnienv* env, Jobject clazz, jstring name, jint length)
{
String conversions
Const char* NAMESTR = (name. Env->getstringutfchars (name, NULL): null);
Open the device file "/dev/ashmem" and modify the device file name and shared memory size
int result = Ashmem_create_region (namestr, length);
if (name)
Env->releasestringutfchars (name, NAMESTR);
if (Result < 0) {
Jnithrowexception (env, "java/io/ioexception", "Ashmem_create_region failed");
return NULL;
}
Device file handle Conversion
Return Jnicreatefiledescriptor (env, result);
}
The function first converts your shared memory name from the Java layer to a C + + layer string, and then calls the Ashmem_create_region function to create an anonymous shared memory named dev/ashmem/, and modifies the name and size of the shared memory. The anonymous shared memory device file handle value created is then returned to the Java space. The function ashmem_create_region is analyzed in detail in the Android anonymous shared memory C interface analysis, which is used to create an anonymous shared memory.
When constructing a Memoryfile object in the Java space, first open the/DEV/ASHMEM device file and create a ashmem_area in kernel space, then you need to map the shared memory address allocated by the kernel space to the process virtual address space, and the mapping process is through the Native_ mmap function to complete.
Static Jint Android_os_memoryfile_mmap (jnienv* env, Jobject clazz, Jobject filedescriptor,
Jint length, Jint prot)
{
int FD = Jnigetfdfromfiledescriptor (env, filedescriptor);
Jint result = (jint) mmap (NULL, Length, prot, map_shared, FD, 0);
if (!result)
Jnithrowexception (env, "java/io/ioexception", "Mmap failed");
return result;
}
The function calls mmap directly to implement the address space mapping, note the flag bit map_shared, indicating that the buffer is mapped in a shared way. The mapping process is done by the Ashmem driver, and the Android anonymous shared memory driver source analysis details the implementation of the Android anonymous shared memory. When the Memoryfile object is constructed, the creation of anonymous shared memory and the mapping of the address space are completed, the size of the created anonymous shared memory is saved to the Memoryfile member variable mlength, and the member variable MFD saves the file descriptor for the anonymous shared memory created. The member variable maddress the starting address of the stored anonymous shared memory mapped to the process address space. With this information, you can use the anonymous shared memory directly.
Anonymous shared memory Read
The read operation of Anonymous shared memory, which is encapsulated as Memoryinputstream in the Java space, inherits from the input stream InputStream and provides the Read method externally, defined as follows:
@Override
public int read () throws IOException {
if (Msinglebyte = = null) {
Msinglebyte = new Byte[1];
}
int result = Read (Msinglebyte, 0, 1);
if (Result!= 1) {
return-1;
}
return msinglebyte[0];
}
@Override
public int read (byte buffer[], int offset, int count) throws IOException {
if (Offset < 0 | | | Count < 0 | | Offset + count > Buffer.length) {
Readbytes () also does this check, but we need todo it before
changing count.
throw new Indexoutofboundsexception ();
}
Count = Math.min (count, available ());
if (count < 1) {
return-1;
}
int result = readbytes (buffer, Moffset, offset, count);
if (Result > 0) {
Moffset + = result;
}
return result;
}
The Memoryinputstream class provides two read overloaded methods, and the first parameterless read method calls the parameter read method to read 1 bytes of data. The data reading process of the parameter read method is to call the Memoryinputstream external class Memoryfile Readbytes method to realize the reading process of anonymous shared memory data.
public int readbytes (byte[] buffer, int srcoffset, int destoffset, int count)
Throws IOException {
if (isdeactivated ()) {
throw new IOException ("Can" t read from deactivated memory file);
}
if (Destoffset < 0 | | destoffset > Buffer.length | | Count < 0
|| Count > Buffer.length-destoffset
|| Srcoffset < 0 | | Srcoffset > Mlength
|| Count > Mlength-srcoffset) {
throw new Indexoutofboundsexception ();
}
Return Native_read (MFD, maddress, buffer, Srcoffset, Destoffset, Count, mallowpurging);
}
The function also makes only a few judgments, and then calls the local method directly native_read in the C + + space to complete the data reading, when constructing the Memoryfile object, has opened and mapped the DEV/ASHMEM device file, Thus, the file handle value that opens the device file is uploaded directly to the C + + space to correctly read the contents of the specified anonymous shared memory, maddress to the originating address in the process address space for anonymous shared memory.
Static Jint Android_os_memoryfile_read (jnienv* env, Jobject Clazz,
Jobject FileDescriptor, jint address, Jbytearray buffer, Jint srcoffset, Jint Destoffset,
Jint count, Jboolean unpinned)
{
int FD = Jnigetfdfromfiledescriptor (env, filedescriptor);
if (unpinned && ashmem_pin_region (FD, 0, 0) = = ashmem_was_purged) {
Ashmem_unpin_region (FD, 0, 0);
Jnithrowexception (env, "java/io/ioexception", "Ashmem region was purged");
return-1;
}
Env->setbytearrayregion (buffer, Destoffset, Count, (const jbyte *) address + srcoffset);
if (unpinned) {
Ashmem_unpin_region (FD, 0, 0);
}
return count;
}
Anonymous shared memory write
Writes the specified data to anonymous shared memory, and writes the anonymous shared memory using Memoryoutputstream to encapsulate the class, which provides two overloaded write methods, one for writing multibyte data to anonymous shared memory, and one for writing only byte data. Here is a brief introduction to the multibyte data writing process:
public void Write (byte buffer[], int offset, int count) throws IOException {
Writebytes (buffer, offset, moffset, count);
Moffset + = count;
}
Parameter buffer refers to an array of bytes written to anonymous shared memory, offset specifies how long the data buffer starts to write, and parameter count specifies the length of bytes written to anonymous shared memory, and the function calls the Memoryfile writebytes function to complete the data write.
public void Writebytes (byte[] buffer, int srcoffset, int destoffset, int count)
Throws IOException {
if (isdeactivated ()) {
throw new IOException ("Can" T write to deactivated memory file. ");
}
if (Srcoffset < 0 | | srcoffset > Buffer.length | | Count < 0
|| Count > Buffer.length-srcoffset
|| Destoffset < 0 | | Destoffset > Mlength
|| Count > Mlength-destoffset) {
throw new Indexoutofboundsexception ();
}
Native_write (MFD, maddress, buffer, Srcoffset, Destoffset, Count, mallowpurging);
}
The function first examines the correctness of the parameters, and then calls the native method Native_write into C + + via JNI to complete data writing, the first parameter is the file descriptor for anonymous shared memory, and the second parameter is the base value of the anonymous shared memory mapped to the process address space. The following three parameters are described above, and the last parameter mallowpurging indicates whether memory recycling is allowed
Describes the write process for anonymous shared memory, which essentially copies data at the specified location in the buffer to the offset specified by the anonymous shared memory
Frameworks\base\core\jni\android_os_memoryfile.cpp
Static Jint Android_os_memoryfile_write (jnienv* env, Jobject Clazz,
Jobject FileDescriptor, jint address, Jbytearray buffer, Jint srcoffset, Jint Destoffset,
Jint count, Jboolean unpinned)
{
int FD = Jnigetfdfromfiledescriptor (env, filedescriptor);
if (unpinned && ashmem_pin_region (FD, 0, 0) = = ashmem_was_purged) {
Ashmem_unpin_region (FD, 0, 0);
Jnithrowexception (env, "java/io/ioexception", "Ashmem region was purged");
return-1;
}
Env->getbytearrayregion (buffer, Srcoffset, COUNT, (Jbyte *) address + destoffset);
if (unpinned) {
Ashmem_unpin_region (FD, 0, 0);
}
return count;
}
The data writing process is a copy operation of the data through the JNI function getbytearrayregion.
Memoryfile the main construction method Memoryfile (String name, int length), where the second parameter is file size, the Android Memoryfile and the traditional mmap are a little bit different, after all, the phone, Its internal memory management Ashmem will reclaim resources from the kernel. After all, currently some low-end models of RAM is also more tight.
Synchronized Boolean allowpurging (Boolean allowpurging)//allows Ashmem to clean up memory and thread-safe synchronization.
void Close ()//off, because the mmap occupies a handle inside Linux and must be freed when not needed
InputStream getInputStream () returns the contents of the read in the Java Layer InputStream save
OutputStream Getoutputstream () writes a outputsream to Memoryfile
Boolean ispurgingallowed ()//Determine whether to allow cleanup
int length ()//return memory-mapped file size
Here is what we are familiar with, read and write details, mainly on the operation of the character array, here you want to calculate the occupation of each file type, while considering the efficiency of their assigned size to consider granularity alignment.
int readbytes (byte[] buffer, int srcoffset, int destoffset, int count)
void Writebytes (byte[] buffer, int srcoffset, int destoffset, int count)
Application: For I/O need frequent operation, mainly and external storage-related I/O operations, memoryfile by the NAND or SD card files, segmented mapping into memory for modification processing, so that the use of high-speed RAM instead of ROM or SD card, the performance naturally improved a lot, It also reduces battery consumption for Android phones.