0

I have written an example of android ion usage:

The father process creates a pipe, then opens "/dev/ion" device, ioctl of ION_IOC_ALLOC, ioctl of ION_IOC_MAP and mmap, and finally I delivered the fd returned by ION_IOC_MAP and the length to the child process by pipe.

The child process reads fd and length from pipe, and the read is ok, but when I do ION_IOC_IMPORT, this returned -1, and the errno is 9, perror is "Bad file descriptor".

The two processes are root user and selinux is permissive.

Father process key code:

ion_fd = open("/dev/ion", O_RDONLY);
if (ion_fd < 0) {
    ALOGE("Failed to open ion device\n");
    return -EIO;
}

alloc_data.len = 0x1000;
alloc_data.align = 0x1000;
alloc_data.heap_id_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
alloc_data.flags = ION_SECURE;
rc = ioctl(ion_fd, ION_IOC_ALLOC, &alloc_data);
if (rc) {
    ALOGE( "Failed to allocate uspace ion buffer\n");
    goto uimp_alloc_err;
}
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);
if (rc < 0) {
    ALOGE("unable to ion map buffer\n");
    goto uimp_map_err;
}
map_fd = fd_data.fd;
addr = mmap(NULL, alloc_data.len,
                PROT_READ | PROT_WRITE,
                MAP_SHARED , map_fd, 0);
if (!addr) {
    ALOGE("mmap failed\n");
    rc = -EIO;
    goto uimp_mmap_err;
}
write_pattern((unsigned long)addr, alloc_data.len);
fd_data.handle = alloc_data.handle;
rc = ioctl(ion_fd, ION_IOC_SHARE, &fd_data);
if (rc < 0) {
    ALOGE( "unable to share ion buffer\n");
    goto uimp_share_err;
}

itoa(fd_data.fd, ubuf, sizeof(int) * 8);
if (0 > sock_write(wr_fd, ubuf, sizeof(int) * 8))
    goto uimp_sock_err;
itoa(alloc_data.len, ubuf, sizeof(int) * 8);
if (0 > sock_write(wr_fd, ubuf, sizeof(int) * 8))
    goto uimp_sock_err;

do {
    tpid = wait(&child_status);
} while (tpid != child_pid);

Child process key code:

if (0 > sock_read(fd, cbuf, sizeof(int) * 8))
    return -EIO;
fd_data.fd = atoi(cbuf);
/* receive buf length */
if (0 > sock_read(fd, cbuf, sizeof(int) * 8))
    return -EIO;
size = atoi(cbuf);

ion_fd = open("/dev/ion", O_RDONLY);
if (ion_fd < 0) {
    rc = -EINVAL;
    goto child_args_err;
}
rc = ioctl(ion_fd, ION_IOC_IMPORT, &fd_data); // it failed here
if (rc) {
    ALOGE( "ION_IOC_IMPORT failed %d errno %d\n", rc, errno);
    perror("ioctl");
    rc = -EIO;
    goto child_imp_err;
}
addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
                MAP_SHARED, fd_data.fd, 0);
if (!addr) {
    perror("mmap");
    rc = -EIO;
    goto child_mmap_err;
}
caffreyd
  • 1,151
  • 1
  • 17
  • 25
Ben Zhu
  • 1
  • 3

2 Answers2

1

File descriptors (fds) are per process and therefore, cannot be shared between processes just by passing a descriptor (which is a simple int) - that's why you are getting the error. In Android, you can take two approaches to solve this: 1. Use Android's Binder, by having both processes realize a class which inherits IInterface and all that jazz (see for example: https://github.com/gburca/BinderDemo), However, I believe this is a lot of overkill just for a one time sharing of an fd so... 2. I prefer to use good ol' fashioned Unix, which provides the means to duplicate an fd if it is passed via a socket. Just google up the magic word: SCM_RIGHTS and you should be able to find tons of examples.

0

Instead of rc = ioctl(ion_fd, ION_IOC_MAP, &fd_data);, use rc = ioctl(ion_fd, **ION_IOC_SHARE**, &fd_data); It will solve this.

reference: https://groleo.wordpress.com/2012/07/24/ion-buffer-sharing-mechanism/

maazza
  • 7,016
  • 15
  • 63
  • 96