Shared memory với Ashmem
Bài đăng này đã không được cập nhật trong 6 năm
Android ashmem
Một tính năng mà google được thêm vào kernel linux là ashmem. Chúng ta có thể tạo ra một vùng nhớ mới bằng cách sử dụng lớp MemoryFile hoặc ashmem_create_region trên layer native, nhưng vì lý do bảo mật, chúng ta không thể mở vùng nhớ đó Giải pháp là tạo ra một service tạo vùng và trả lại cho client thông qua file descriptor.
Tại sao ashmem tốt hơn để chia sẻ bộ nhớ?
Ashmem có một vài ưu điểm so với các phương pháp chia sẻ bộ nhớ khác. Đó là một cách tuyệt vời để chia sẻ số lượng lớn dữ liệu giữa các ứng dụng hoặc giữa nhiều process trong một ứng dụng. Sự khác biệt chính giữa bộ nhớ chia sẻ Linux và bộ nhớ chia sẻ này là trong khi các tiến trình khác của Linux không thể giải phóng bộ nhớ chia sẻ nhưng ở đây nếu các tiến trình khác đòi hỏi bộ nhớ, hệ điều hành Android này sẽ giải phóng bộ nhớ này.
Ashmem cho phép các tiến trình chia sẻ bộ nhớ như thế nào?
Quá trình tạo vùng ashmem mới gồm các bước sau:
- Mở file thiết bị, "/ dev / ashmem" và nhận file descriptor.
- Gọi ioctl của ASHMEM_SET_NAME để đặt tên ashmem. Đây có thể là tệp thiết bị ảo, vì vậy nếu bạn đặt tên là "my_mem", tên tệp sẽ thay đổi thành "/ dev / ashmem / my_mem".
- Gọi ASHMEM_SET_SIZE ioctl để thiết lập kích thước ashmem, theo byte.
- Thư viện cutils có một hàm "ashmem_create_region"
kết hợp các bước này ta gọi hàm ashmem_create_region và có được một file descriptor:
int fd = ashmem_create_region ("my_mem", PAGE_SIZE * 20);
file descriptor có thể được chia sẻ với các quá trình khác. Android cung cấp một cách đặc biệt để chia sẻ các file descriptor giữa các process, sử dụng một dịch vụ khác gọi là "binder". Sau đó mỗi process mmaps file:
char * map = mmap (NULL, PAGE_SIZE * 20, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
và như vậy bộ nhớ đã được chia sẻ
Đối với android 8.1
Android 8.1 (API level 27) giới thiệu một SharedMemory API mới. Lớp này cho phép bạn tạo, map và quản lý một instance SharedMemory ẩn danh. Bạn đặt bảo vệ bộ nhớ trên một đối tượng SharedMemory để đọc và/hoặc ghi, và vì đối tượng SharedMemory là Parcelable, bạn có thể dễ dàng chuyển nó sang một process khác thông qua AIDL.
API SharedMemory tương tác với lớp cơ sở ASharedMemory trong NDK. ASharedMemory cho phép truy cập vào một file descriptor, sau đó có thể chuyền được nó để read và write.
Đối với Android 8 trở về trước
- Đầu tiên định nghĩa service AIDL:
interface IShmService
{
ParcelFileDescriptor getFD(in String name);
}
để tạo và map bộ nhớ chia sẻ (hoặc bất kỳ đối tượng mô tả tập tin nào khác), chúng ta cần một đoạn code native:
static jint getFD(JNIEnv *env, jobject thiz, jstring n)
{
const char *name = (env)->GetStringUTFChars(n,NULL);
jint fd = open("/dev/ashmem",O_RDWR);
ioctl(fd,ASHMEM_SET_NAME,name);
ioctl(fd,ASHMEM_SET_SIZE,4096);
map = (int *)mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
// fill some data for testing purpose
map[0]=99;
map[10]=88;
(env)->ReleaseStringUTFChars(path,name);
return fd;
}
Hàm native trên trả về một file descriptor , cần chuyển đổi nó để thành một ParcelFileDescriptor
public ParcelFileDescriptor getFD(String name) throws RemoteException {
try {
int fd = ShmLib.getFD(name); // call to native function
ParcelFileDescriptor ret=ParcelFileDescriptor.fromFd(fd);
return ret;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Khai báo một con trỏ để giữ địa chỉ bộ nhớ chia sẻ và sử dụng mmap để set giá trị cho nó:
static void init(JNIEnv *env, jobject thiz, jint fd)
{
map = (int *)mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
}
Giờ đơn giản chỉ cần liên kết với service (sử dụng đối tượng bindservice và Intent) và gọi hàm ở trên để nhận được file descriptor
ParcelFileDescriptor p = service.getFD ("samp");
ShmClientLib.init (p.getFd ());
Nguồn: https://developer.android.com/reference/android/os/SharedMemory.html http://notjustburritos.tumblr.com/post/21442138796/an-introduction-to-android-shared-memory http://www.discoversdk.com/blog/android-shared-memory-ashmem-example
All rights reserved