Android's Binder IPC like many other alternatives supports file transfer. However this is a most efficient implementation of constant order, irrespective of the file size. This makes is very suitable to transfer pictures, videos etc of many mega bytes in size from one application to the other. So how does this work and how is this different from traditional linux approach?
Well, there isn't any file manipulation like opening the file, reading and streaming its contents. Instead, its just a smart manipulation of the file descriptors in the source and destination process space. Most of binder logic is loaded as a kernel module and it gets to run with enough permissions to manipulate process file descriptor table. Its implemented by a special binder transaction BINDER_TYPE_FD. Upon request, binder determines if the target of the transaction can accept files and if so, gets a reference to the destination process's file descriptor table and an unused file descriptor from the same. This new descriptor is marked as open in the file table and to be closed when the destination process quits or terminates.
int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
{
struct files_struct *files = proc->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
fd = find_next_zero_bit(fdt->open_fds->fds_bits,
fdt->max_fds,
files->next_fd);
FD_SET(fd, fdt->open_fds);
if (flags & O_CLOEXEC)
FD_SET(fd, fdt->close_on_exec);
else
FD_CLR(fd, fdt->close_on_exec);
files->next_fd = fd + 1;
spin_unlock(&files->file_lock);
return fd;
}
Now, this new file descriptor is just made to point to the file that was being shared by the source process and thats all it took to share a file.
struct files_struct *files = targetproc->files;
struct fdtable * fdt = files_fdtable(files);
rcu_assign_pointer(fdt->fd[fd], sourcefile);
The file table operation guarantees constant order performance for all file sizes with a perquisite being that both process be based on binder framework.
Well, there isn't any file manipulation like opening the file, reading and streaming its contents. Instead, its just a smart manipulation of the file descriptors in the source and destination process space. Most of binder logic is loaded as a kernel module and it gets to run with enough permissions to manipulate process file descriptor table. Its implemented by a special binder transaction BINDER_TYPE_FD. Upon request, binder determines if the target of the transaction can accept files and if so, gets a reference to the destination process's file descriptor table and an unused file descriptor from the same. This new descriptor is marked as open in the file table and to be closed when the destination process quits or terminates.
int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
{
struct files_struct *files = proc->files;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
fd = find_next_zero_bit(fdt->open_fds->fds_bits,
fdt->max_fds,
files->next_fd);
FD_SET(fd, fdt->open_fds);
if (flags & O_CLOEXEC)
FD_SET(fd, fdt->close_on_exec);
else
FD_CLR(fd, fdt->close_on_exec);
files->next_fd = fd + 1;
spin_unlock(&files->file_lock);
return fd;
}
Now, this new file descriptor is just made to point to the file that was being shared by the source process and thats all it took to share a file.
struct files_struct *files = targetproc->files;
struct fdtable * fdt = files_fdtable(files);
rcu_assign_pointer(fdt->fd[fd], sourcefile);
The file table operation guarantees constant order performance for all file sizes with a perquisite being that both process be based on binder framework.
No comments:
Post a Comment