Как передать файловый дескриптор в Ashmem между процессами
Я пытаюсь передать файловый дескриптор, указывающий на область ashmem, из Service (процесс A) в Activity (процесс B). В Сервисе я помещаю собственный дескриптор файла в ParcelFileDescriptor, а затем в пакет, и отправляю его через Messenger. Однако, когда я пытаюсь выполнить mmap() с помощью этого файлового дескриптора в Activity, я получаю errno == 9 (EBADF, неверный номер файла).
Создание ашмем региона в Службе JNI:
int fd;
int *buff;
JNIEXPORT jint JNICALL Java_com_example_testservice_Test_getTestFD
/* int Test.getTestFD() */
(JNIEnv * env, jclass jthis) {
fd = open("/dev/ashmem", O_RDWR); // I couldn't find library with ashmem_create_region
ioctl(fd, ASHMEM_SET_NAME, "my_mem");
ioctl(fd, ASHMEM_SET_SIZE, 640*480*12);
buff = mmap(NULL, 640*480*12, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(buff == MAP_FAILED)
return -1;
buff[0] = 4;
buff[1] = 5;
buff[2] = 6;
return fd;
}
Отправка fd из Сервиса в Активность:
int nFD = Test.getTestFD();
ParcelFileDescriptor fd;
try {
fd = ParcelFileDescriptor.fromFd(nFD);
Message reply = Message.obtain(this, msg.what, nFD, 0);
Bundle b = new Bundle(1);
b.putParcelable("fd", fd);
reply.setData(b);
if(msg.replyTo == null) { // Activity asks for FD and we reply to it's message
Log.e("TestService", "Missing replyTo");
} else {
try {
msg.replyTo.send(reply);
} catch (RemoteException e) {
e.printStackTrace();
}
}
} catch (IOException e1) {
e1.printStackTrace();
}
Получение ФД в Деятельности:
Bundle bundle = msg.getData();
ParcelFileDescriptor fd = bundle.getParcelable("fd");
int nFD = fd.getFd();
Log.d("ClientLib", "Received FD (Parcel): "+String.valueOf(nFD));
Log.d("ClientLib", "Received FD (raw): "+String.valueOf(msg.arg1));
int ret = Interface.SetDataFD(nFD); // implementation below
if(ret != 0)
Log.e("ClientLib", "SetDataFD (parcel) failed. Error code: "+String.valueOf(ret));
ret = Interface.SetDataFD(msg.arg1);
if(ret != 0)
Log.e("ClientLib", "SetDataFD (raw) failed. Error code: "+String.valueOf(ret));
Обработка fd в JNI Activity:
int data_fd = -1;
JNIEXPORT
jint JNICALL Java_com_example_clientlib_Interface_SetDataFD
/* int SetDataFD(int fd) */
(JNIEnv * env, jclass jthis, jint fd)
{
data_fd = fd;
int * blah = (int*)mmap(NULL, 16, PROT_READ, MAP_SHARED, data_fd, 0);
if(blah == MAP_FAILED)
return errno;
return 0;
}
Вот что я получаю в logcat:
D/ClientLib(22104): Received FD (Parcel): 53
D/ClientLib(22104): Received FD (raw): 49
E/ClientLib(22104): SetDataFD (parcel) failed. Error code: 9
E/ClientLib(22104): SetDataFD (raw) failed. Error code: 19
Что здесь не так? Я даже не уверен, что это проблема с передачей файлового дескриптора, я не знаю, что еще я могу проверить.
2 ответа
Неважно, работает как надо:). У меня где-то в коде какая-то глупая отладка +9, она правильно возвращала 0. Я оставляю код для справки.
// Я не смог найти библиотеку с помощью ashmem_create_region**
Это часть библиотеки cutils. Вы можете добавить его в свой файл Android.mk следующим образом:
LOCAL_LDLIBS := -lcutils