Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

android/ion: userspace test utility for ion buffer sharing

This is a test utility to verify ION buffer sharing in user space
between 2 independent processes.
It uses unix domain socket (with SCM_RIGHTS) as IPC to transfer an FD to
another process to share the same buffer.
This utility demonstrates how ION buffer sharing can be implemented between
two user space processes, using various heap types.

This utility is made to be run as part of kselftest framework in kernel.
The utility is verified on Ubuntu-32 bit system with Linux Kernel 4.14,
using ION system heap.

For more information about the utility please check the README file.

Signed-off-by: Pintu Agarwal <pintu.ping@gmail.com>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

Pintu Agarwal and committed by
Shuah Khan
47a18c42 50656ac6

+1171 -1
+2 -1
tools/testing/selftests/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 - TARGETS = bpf 2 + TARGETS = android 3 + TARGETS += bpf 3 4 TARGETS += breakpoints 4 5 TARGETS += capabilities 5 6 TARGETS += cpufreq
+46
tools/testing/selftests/android/Makefile
··· 1 + SUBDIRS := ion 2 + 3 + TEST_PROGS := run.sh 4 + 5 + .PHONY: all clean 6 + 7 + include ../lib.mk 8 + 9 + all: 10 + @for DIR in $(SUBDIRS); do \ 11 + BUILD_TARGET=$(OUTPUT)/$$DIR; \ 12 + mkdir $$BUILD_TARGET -p; \ 13 + make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ 14 + #SUBDIR test prog name should be in the form: SUBDIR_test.sh 15 + TEST=$$DIR"_test.sh"; \ 16 + if [ -e $$DIR/$$TEST ]; then 17 + rsync -a $$DIR/$$TEST $$BUILD_TARGET/; 18 + fi 19 + done 20 + 21 + override define RUN_TESTS 22 + @cd $(OUTPUT); ./run.sh 23 + endef 24 + 25 + override define INSTALL_RULE 26 + mkdir -p $(INSTALL_PATH) 27 + install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) 28 + 29 + @for SUBDIR in $(SUBDIRS); do \ 30 + BUILD_TARGET=$(OUTPUT)/$$SUBDIR; \ 31 + mkdir $$BUILD_TARGET -p; \ 32 + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \ 33 + done; 34 + endef 35 + 36 + override define EMIT_TESTS 37 + echo "./run.sh" 38 + endef 39 + 40 + override define CLEAN 41 + @for DIR in $(SUBDIRS); do \ 42 + BUILD_TARGET=$(OUTPUT)/$$DIR; \ 43 + mkdir $$BUILD_TARGET -p; \ 44 + make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ 45 + done 46 + endef
+2
tools/testing/selftests/android/ion/.gitignore
··· 1 + ionapp_export 2 + ionapp_import
+16
tools/testing/selftests/android/ion/Makefile
··· 1 + 2 + INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ 3 + CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g 4 + 5 + TEST_GEN_FILES := ionapp_export ionapp_import 6 + 7 + all: $(TEST_GEN_FILES) 8 + 9 + $(TEST_GEN_FILES): ipcsocket.c ionutils.c 10 + 11 + TEST_PROGS := ion_test.sh 12 + 13 + include ../../lib.mk 14 + 15 + $(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c 16 + $(OUTPUT)/ionapp_import: ionapp_import.c ipcsocket.c ionutils.c
+101
tools/testing/selftests/android/ion/README
··· 1 + ION BUFFER SHARING UTILITY 2 + ========================== 3 + File: ion_test.sh : Utility to test ION driver buffer sharing mechanism. 4 + Author: Pintu Kumar <pintu.ping@gmail.com> 5 + 6 + Introduction: 7 + ------------- 8 + This is a test utility to verify ION buffer sharing in user space 9 + between 2 independent processes. 10 + It uses unix domain socket (with SCM_RIGHTS) as IPC to transfer an FD to 11 + another process to share the same buffer. 12 + This utility demonstrates how ION buffer sharing can be implemented between 13 + two user space processes, using various heap types. 14 + The following heap types are supported by ION driver. 15 + ION_HEAP_TYPE_SYSTEM (0) 16 + ION_HEAP_TYPE_SYSTEM_CONTIG (1) 17 + ION_HEAP_TYPE_CARVEOUT (2) 18 + ION_HEAP_TYPE_CHUNK (3) 19 + ION_HEAP_TYPE_DMA (4) 20 + 21 + By default only the SYSTEM and SYSTEM_CONTIG heaps are supported. 22 + Each heap is associated with the respective heap id. 23 + This utility is designed in the form of client/server program. 24 + The server part (ionapp_export) is the exporter of the buffer. 25 + It is responsible for creating an ION client, allocating the buffer based on 26 + the heap id, writing some data to this buffer and then exporting the FD 27 + (associated with this buffer) to another process using socket IPC. 28 + This FD is called as buffer FD (which is different than the ION client FD). 29 + 30 + The client part (ionapp_import) is the importer of the buffer. 31 + It retrives the FD from the socket data and installs into its address space. 32 + This new FD internally points to the same kernel buffer. 33 + So first it reads the data that is stored in this buffer and prints it. 34 + Then it writes the different size of data (it could be different data) to the 35 + same buffer. 36 + Finally the buffer FD must be closed by both the exporter and importer. 37 + Thus the same kernel buffer is shared among two user space processes using 38 + ION driver and only one time allocation. 39 + 40 + Prerequisite: 41 + ------------- 42 + This utility works only if /dev/ion interface is present. 43 + The following configs needs to be enabled in kernel to include ion driver. 44 + CONFIG_ANDROID=y 45 + CONFIG_STAGING=y 46 + CONFIG_ION=y 47 + CONFIG_ION_SYSTEM_HEAP=y 48 + 49 + This utility requires to be run as root user. 50 + 51 + 52 + Compile and test: 53 + ----------------- 54 + This utility is made to be run as part of kselftest framework in kernel. 55 + To compile and run using kselftest you can simply do the following from the 56 + kernel top directory. 57 + linux$ make TARGETS=android kselftest 58 + Or you can also use: 59 + linux$ make -C tools/testing/selftests TARGETS=android run_tests 60 + Using the selftest it can directly execute the ion_test.sh script to test the 61 + buffer sharing using ion system heap. 62 + Currently the heap size is hard coded as just 10 bytes inside this script. 63 + You need to be a root user to run under selftest. 64 + 65 + You can also compile and test manually using the following steps: 66 + ion$ make 67 + These will generate 2 executable: ionapp_export, ionapp_import 68 + Now you can run the export and import manually by specifying the heap type 69 + and the heap size. 70 + You can also directly execute the shell script to run the test automatically. 71 + Simply use the following command to run the test. 72 + ion$ sudo ./ion_test.sh 73 + 74 + Test Results: 75 + ------------- 76 + The utility is verified on Ubuntu-32 bit system with Linux Kernel 4.14. 77 + Here is the snapshot of the test result using kselftest. 78 + 79 + linux# make TARGETS=android kselftest 80 + heap_type: 0, heap_size: 10 81 + -------------------------------------- 82 + heap type: 0 83 + heap id: 1 84 + heap name: ion_system_heap 85 + -------------------------------------- 86 + Fill buffer content: 87 + 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 88 + Sharing fd: 6, Client fd: 5 89 + <ion_close_buffer_fd>: buffer release successfully.... 90 + Received buffer fd: 4 91 + Read buffer content: 92 + 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0x0 0x0 0x0 0x0 0x0 0x0 93 + 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 94 + Fill buffer content: 95 + 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 96 + 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 0xfd 97 + 0xfd 0xfd 98 + <ion_close_buffer_fd>: buffer release successfully.... 99 + ion_test.sh: heap_type: 0 - [PASS] 100 + 101 + ion_test.sh: done
+4
tools/testing/selftests/android/ion/config
··· 1 + CONFIG_ANDROID=y 2 + CONFIG_STAGING=y 3 + CONFIG_ION=y 4 + CONFIG_ION_SYSTEM_HEAP=y
+143
tools/testing/selftests/android/ion/ion.h
··· 1 + /* 2 + * ion.h 3 + * 4 + * Copyright (C) 2011 Google, Inc. 5 + * 6 + * This software is licensed under the terms of the GNU General Public 7 + * License version 2, as published by the Free Software Foundation, and 8 + * may be copied, distributed, and modified under those terms. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + */ 16 + 17 + /* This file is copied from drivers/staging/android/uapi/ion.h 18 + * This local copy is required for the selftest to pass, when build 19 + * outside the kernel source tree. 20 + * Please keep this file in sync with its original file until the 21 + * ion driver is moved outside the staging tree. 22 + */ 23 + 24 + #ifndef _UAPI_LINUX_ION_H 25 + #define _UAPI_LINUX_ION_H 26 + 27 + #include <linux/ioctl.h> 28 + #include <linux/types.h> 29 + 30 + /** 31 + * enum ion_heap_types - list of all possible types of heaps 32 + * @ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc 33 + * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc 34 + * @ION_HEAP_TYPE_CARVEOUT: memory allocated from a prereserved 35 + * carveout heap, allocations are physically 36 + * contiguous 37 + * @ION_HEAP_TYPE_DMA: memory allocated via DMA API 38 + * @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask 39 + * is used to identify the heaps, so only 32 40 + * total heap types are supported 41 + */ 42 + enum ion_heap_type { 43 + ION_HEAP_TYPE_SYSTEM, 44 + ION_HEAP_TYPE_SYSTEM_CONTIG, 45 + ION_HEAP_TYPE_CARVEOUT, 46 + ION_HEAP_TYPE_CHUNK, 47 + ION_HEAP_TYPE_DMA, 48 + ION_HEAP_TYPE_CUSTOM, /* 49 + * must be last so device specific heaps always 50 + * are at the end of this enum 51 + */ 52 + }; 53 + 54 + #define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8) 55 + 56 + /** 57 + * allocation flags - the lower 16 bits are used by core ion, the upper 16 58 + * bits are reserved for use by the heaps themselves. 59 + */ 60 + 61 + /* 62 + * mappings of this buffer should be cached, ion will do cache maintenance 63 + * when the buffer is mapped for dma 64 + */ 65 + #define ION_FLAG_CACHED 1 66 + 67 + /** 68 + * DOC: Ion Userspace API 69 + * 70 + * create a client by opening /dev/ion 71 + * most operations handled via following ioctls 72 + * 73 + */ 74 + 75 + /** 76 + * struct ion_allocation_data - metadata passed from userspace for allocations 77 + * @len: size of the allocation 78 + * @heap_id_mask: mask of heap ids to allocate from 79 + * @flags: flags passed to heap 80 + * @handle: pointer that will be populated with a cookie to use to 81 + * refer to this allocation 82 + * 83 + * Provided by userspace as an argument to the ioctl 84 + */ 85 + struct ion_allocation_data { 86 + __u64 len; 87 + __u32 heap_id_mask; 88 + __u32 flags; 89 + __u32 fd; 90 + __u32 unused; 91 + }; 92 + 93 + #define MAX_HEAP_NAME 32 94 + 95 + /** 96 + * struct ion_heap_data - data about a heap 97 + * @name - first 32 characters of the heap name 98 + * @type - heap type 99 + * @heap_id - heap id for the heap 100 + */ 101 + struct ion_heap_data { 102 + char name[MAX_HEAP_NAME]; 103 + __u32 type; 104 + __u32 heap_id; 105 + __u32 reserved0; 106 + __u32 reserved1; 107 + __u32 reserved2; 108 + }; 109 + 110 + /** 111 + * struct ion_heap_query - collection of data about all heaps 112 + * @cnt - total number of heaps to be copied 113 + * @heaps - buffer to copy heap data 114 + */ 115 + struct ion_heap_query { 116 + __u32 cnt; /* Total number of heaps to be copied */ 117 + __u32 reserved0; /* align to 64bits */ 118 + __u64 heaps; /* buffer to be populated */ 119 + __u32 reserved1; 120 + __u32 reserved2; 121 + }; 122 + 123 + #define ION_IOC_MAGIC 'I' 124 + 125 + /** 126 + * DOC: ION_IOC_ALLOC - allocate memory 127 + * 128 + * Takes an ion_allocation_data struct and returns it with the handle field 129 + * populated with the opaque handle for the allocation. 130 + */ 131 + #define ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ 132 + struct ion_allocation_data) 133 + 134 + /** 135 + * DOC: ION_IOC_HEAP_QUERY - information about available heaps 136 + * 137 + * Takes an ion_heap_query structure and populates information about 138 + * available Ion heaps. 139 + */ 140 + #define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \ 141 + struct ion_heap_query) 142 + 143 + #endif /* _UAPI_LINUX_ION_H */
+55
tools/testing/selftests/android/ion/ion_test.sh
··· 1 + #!/bin/bash 2 + 3 + heapsize=4096 4 + TCID="ion_test.sh" 5 + errcode=0 6 + 7 + run_test() 8 + { 9 + heaptype=$1 10 + ./ionapp_export -i $heaptype -s $heapsize & 11 + sleep 1 12 + ./ionapp_import 13 + if [ $? -ne 0 ]; then 14 + echo "$TCID: heap_type: $heaptype - [FAIL]" 15 + errcode=1 16 + else 17 + echo "$TCID: heap_type: $heaptype - [PASS]" 18 + fi 19 + sleep 1 20 + echo "" 21 + } 22 + 23 + check_root() 24 + { 25 + uid=$(id -u) 26 + if [ $uid -ne 0 ]; then 27 + echo $TCID: must be run as root >&2 28 + exit 0 29 + fi 30 + } 31 + 32 + check_device() 33 + { 34 + DEVICE=/dev/ion 35 + if [ ! -e $DEVICE ]; then 36 + echo $TCID: No $DEVICE device found >&2 37 + echo $TCID: May be CONFIG_ION is not set >&2 38 + exit 0 39 + fi 40 + } 41 + 42 + main_function() 43 + { 44 + check_device 45 + check_root 46 + 47 + # ION_SYSTEM_HEAP TEST 48 + run_test 0 49 + # ION_SYSTEM_CONTIG_HEAP TEST 50 + run_test 1 51 + } 52 + 53 + main_function 54 + echo "$TCID: done" 55 + exit $errcode
+135
tools/testing/selftests/android/ion/ionapp_export.c
··· 1 + /* 2 + * ionapp_export.c 3 + * 4 + * It is a user space utility to create and export android 5 + * ion memory buffer fd to another process using unix domain socket as IPC. 6 + * This acts like a server for ionapp_import(client). 7 + * So, this server has to be started first before the client. 8 + * 9 + * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com> 10 + * 11 + * This software is licensed under the terms of the GNU General Public 12 + * License version 2, as published by the Free Software Foundation, and 13 + * may be copied, distributed, and modified under those terms. 14 + * 15 + * This program is distributed in the hope that it will be useful, 16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 + * GNU General Public License for more details. 19 + * 20 + */ 21 + 22 + #include <stdio.h> 23 + #include <stdlib.h> 24 + #include <string.h> 25 + #include <unistd.h> 26 + #include <errno.h> 27 + #include <sys/time.h> 28 + #include "ionutils.h" 29 + #include "ipcsocket.h" 30 + 31 + 32 + void print_usage(int argc, char *argv[]) 33 + { 34 + printf("Usage: %s [-h <help>] [-i <heap id>] [-s <size in bytes>]\n", 35 + argv[0]); 36 + } 37 + 38 + int main(int argc, char *argv[]) 39 + { 40 + int opt, ret, status, heapid; 41 + int sockfd, client_fd, shared_fd; 42 + unsigned char *map_buf; 43 + unsigned long map_len, heap_type, heap_size, flags; 44 + struct ion_buffer_info info; 45 + struct socket_info skinfo; 46 + 47 + if (argc < 2) { 48 + print_usage(argc, argv); 49 + return -1; 50 + } 51 + 52 + heap_size = 0; 53 + flags = 0; 54 + 55 + while ((opt = getopt(argc, argv, "hi:s:")) != -1) { 56 + switch (opt) { 57 + case 'h': 58 + print_usage(argc, argv); 59 + exit(0); 60 + break; 61 + case 'i': 62 + heapid = atoi(optarg); 63 + switch (heapid) { 64 + case 0: 65 + heap_type = ION_HEAP_TYPE_SYSTEM; 66 + break; 67 + case 1: 68 + heap_type = ION_HEAP_TYPE_SYSTEM_CONTIG; 69 + break; 70 + default: 71 + printf("ERROR: heap type not supported\n"); 72 + exit(1); 73 + } 74 + break; 75 + case 's': 76 + heap_size = atoi(optarg); 77 + break; 78 + default: 79 + print_usage(argc, argv); 80 + exit(1); 81 + break; 82 + } 83 + } 84 + 85 + if (heap_size <= 0) { 86 + printf("heap_size cannot be 0\n"); 87 + print_usage(argc, argv); 88 + exit(1); 89 + } 90 + 91 + printf("heap_type: %ld, heap_size: %ld\n", heap_type, heap_size); 92 + info.heap_type = heap_type; 93 + info.heap_size = heap_size; 94 + info.flag_type = flags; 95 + 96 + /* This is server: open the socket connection first */ 97 + /* Here; 1 indicates server or exporter */ 98 + status = opensocket(&sockfd, SOCKET_NAME, 1); 99 + if (status < 0) { 100 + fprintf(stderr, "<%s>: Failed opensocket.\n", __func__); 101 + goto err_socket; 102 + } 103 + skinfo.sockfd = sockfd; 104 + 105 + ret = ion_export_buffer_fd(&info); 106 + if (ret < 0) { 107 + fprintf(stderr, "FAILED: ion_get_buffer_fd\n"); 108 + goto err_export; 109 + } 110 + client_fd = info.ionfd; 111 + shared_fd = info.buffd; 112 + map_buf = info.buffer; 113 + map_len = info.buflen; 114 + write_buffer(map_buf, map_len); 115 + 116 + /* share ion buf fd with other user process */ 117 + printf("Sharing fd: %d, Client fd: %d\n", shared_fd, client_fd); 118 + skinfo.datafd = shared_fd; 119 + skinfo.buflen = map_len; 120 + 121 + ret = socket_send_fd(&skinfo); 122 + if (ret < 0) { 123 + fprintf(stderr, "FAILED: socket_send_fd\n"); 124 + goto err_send; 125 + } 126 + 127 + err_send: 128 + err_export: 129 + ion_close_buffer_fd(&info); 130 + 131 + err_socket: 132 + closesocket(sockfd, SOCKET_NAME); 133 + 134 + return 0; 135 + }
+88
tools/testing/selftests/android/ion/ionapp_import.c
··· 1 + /* 2 + * ionapp_import.c 3 + * 4 + * It is a user space utility to receive android ion memory buffer fd 5 + * over unix domain socket IPC that can be exported by ionapp_export. 6 + * This acts like a client for ionapp_export. 7 + * 8 + * Copyright (C) 2017 Pintu Kumar <pintu.ping@gmail.com> 9 + * 10 + * This software is licensed under the terms of the GNU General Public 11 + * License version 2, as published by the Free Software Foundation, and 12 + * may be copied, distributed, and modified under those terms. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + */ 20 + 21 + #include <stdio.h> 22 + #include <stdlib.h> 23 + #include <unistd.h> 24 + #include <string.h> 25 + #include "ionutils.h" 26 + #include "ipcsocket.h" 27 + 28 + 29 + int main(void) 30 + { 31 + int ret, status; 32 + int sockfd, shared_fd; 33 + unsigned char *map_buf; 34 + unsigned long map_len; 35 + struct ion_buffer_info info; 36 + struct socket_info skinfo; 37 + 38 + /* This is the client part. Here 0 means client or importer */ 39 + status = opensocket(&sockfd, SOCKET_NAME, 0); 40 + if (status < 0) { 41 + fprintf(stderr, "No exporter exists...\n"); 42 + ret = status; 43 + goto err_socket; 44 + } 45 + 46 + skinfo.sockfd = sockfd; 47 + 48 + ret = socket_receive_fd(&skinfo); 49 + if (ret < 0) { 50 + fprintf(stderr, "Failed: socket_receive_fd\n"); 51 + goto err_recv; 52 + } 53 + 54 + shared_fd = skinfo.datafd; 55 + printf("Received buffer fd: %d\n", shared_fd); 56 + if (shared_fd <= 0) { 57 + fprintf(stderr, "ERROR: improper buf fd\n"); 58 + ret = -1; 59 + goto err_fd; 60 + } 61 + 62 + memset(&info, 0, sizeof(info)); 63 + info.buffd = shared_fd; 64 + info.buflen = ION_BUFFER_LEN; 65 + 66 + ret = ion_import_buffer_fd(&info); 67 + if (ret < 0) { 68 + fprintf(stderr, "Failed: ion_use_buffer_fd\n"); 69 + goto err_import; 70 + } 71 + 72 + map_buf = info.buffer; 73 + map_len = info.buflen; 74 + read_buffer(map_buf, map_len); 75 + 76 + /* Write probably new data to the same buffer again */ 77 + map_len = ION_BUFFER_LEN; 78 + write_buffer(map_buf, map_len); 79 + 80 + err_import: 81 + ion_close_buffer_fd(&info); 82 + err_fd: 83 + err_recv: 84 + err_socket: 85 + closesocket(sockfd, SOCKET_NAME); 86 + 87 + return ret; 88 + }
+259
tools/testing/selftests/android/ion/ionutils.c
··· 1 + #include <stdio.h> 2 + #include <string.h> 3 + #include <unistd.h> 4 + #include <fcntl.h> 5 + #include <errno.h> 6 + //#include <stdint.h> 7 + #include <sys/ioctl.h> 8 + #include <sys/mman.h> 9 + #include "ionutils.h" 10 + #include "ipcsocket.h" 11 + 12 + 13 + void write_buffer(void *buffer, unsigned long len) 14 + { 15 + int i; 16 + unsigned char *ptr = (unsigned char *)buffer; 17 + 18 + if (!ptr) { 19 + fprintf(stderr, "<%s>: Invalid buffer...\n", __func__); 20 + return; 21 + } 22 + 23 + printf("Fill buffer content:\n"); 24 + memset(ptr, 0xfd, len); 25 + for (i = 0; i < len; i++) 26 + printf("0x%x ", ptr[i]); 27 + printf("\n"); 28 + } 29 + 30 + void read_buffer(void *buffer, unsigned long len) 31 + { 32 + int i; 33 + unsigned char *ptr = (unsigned char *)buffer; 34 + 35 + if (!ptr) { 36 + fprintf(stderr, "<%s>: Invalid buffer...\n", __func__); 37 + return; 38 + } 39 + 40 + printf("Read buffer content:\n"); 41 + for (i = 0; i < len; i++) 42 + printf("0x%x ", ptr[i]); 43 + printf("\n"); 44 + } 45 + 46 + int ion_export_buffer_fd(struct ion_buffer_info *ion_info) 47 + { 48 + int i, ret, ionfd, buffer_fd; 49 + unsigned int heap_id; 50 + unsigned long maplen; 51 + unsigned char *map_buffer; 52 + struct ion_allocation_data alloc_data; 53 + struct ion_heap_query query; 54 + struct ion_heap_data heap_data[MAX_HEAP_COUNT]; 55 + 56 + if (!ion_info) { 57 + fprintf(stderr, "<%s>: Invalid ion info\n", __func__); 58 + return -1; 59 + } 60 + 61 + /* Create an ION client */ 62 + ionfd = open(ION_DEVICE, O_RDWR); 63 + if (ionfd < 0) { 64 + fprintf(stderr, "<%s>: Failed to open ion client: %s\n", 65 + __func__, strerror(errno)); 66 + return -1; 67 + } 68 + 69 + memset(&query, 0, sizeof(query)); 70 + query.cnt = MAX_HEAP_COUNT; 71 + query.heaps = (unsigned long int)&heap_data[0]; 72 + /* Query ION heap_id_mask from ION heap */ 73 + ret = ioctl(ionfd, ION_IOC_HEAP_QUERY, &query); 74 + if (ret < 0) { 75 + fprintf(stderr, "<%s>: Failed: ION_IOC_HEAP_QUERY: %s\n", 76 + __func__, strerror(errno)); 77 + goto err_query; 78 + } 79 + 80 + heap_id = MAX_HEAP_COUNT + 1; 81 + for (i = 0; i < query.cnt; i++) { 82 + if (heap_data[i].type == ion_info->heap_type) { 83 + printf("--------------------------------------\n"); 84 + printf("heap type: %d\n", heap_data[i].type); 85 + printf(" heap id: %d\n", heap_data[i].heap_id); 86 + printf("heap name: %s\n", heap_data[i].name); 87 + printf("--------------------------------------\n"); 88 + heap_id = heap_data[i].heap_id; 89 + break; 90 + } 91 + } 92 + 93 + if (heap_id > MAX_HEAP_COUNT) { 94 + fprintf(stderr, "<%s>: ERROR: heap type does not exists\n", 95 + __func__); 96 + goto err_heap; 97 + } 98 + 99 + alloc_data.len = ion_info->heap_size; 100 + alloc_data.heap_id_mask = 1 << heap_id; 101 + alloc_data.flags = ion_info->flag_type; 102 + 103 + /* Allocate memory for this ION client as per heap_type */ 104 + ret = ioctl(ionfd, ION_IOC_ALLOC, &alloc_data); 105 + if (ret < 0) { 106 + fprintf(stderr, "<%s>: Failed: ION_IOC_ALLOC: %s\n", 107 + __func__, strerror(errno)); 108 + goto err_alloc; 109 + } 110 + 111 + /* This will return a valid buffer fd */ 112 + buffer_fd = alloc_data.fd; 113 + maplen = alloc_data.len; 114 + 115 + if (buffer_fd < 0 || maplen <= 0) { 116 + fprintf(stderr, "<%s>: Invalid map data, fd: %d, len: %ld\n", 117 + __func__, buffer_fd, maplen); 118 + goto err_fd_data; 119 + } 120 + 121 + /* Create memory mapped buffer for the buffer fd */ 122 + map_buffer = (unsigned char *)mmap(NULL, maplen, PROT_READ|PROT_WRITE, 123 + MAP_SHARED, buffer_fd, 0); 124 + if (map_buffer == MAP_FAILED) { 125 + fprintf(stderr, "<%s>: Failed: mmap: %s\n", 126 + __func__, strerror(errno)); 127 + goto err_mmap; 128 + } 129 + 130 + ion_info->ionfd = ionfd; 131 + ion_info->buffd = buffer_fd; 132 + ion_info->buffer = map_buffer; 133 + ion_info->buflen = maplen; 134 + 135 + return 0; 136 + 137 + munmap(map_buffer, maplen); 138 + 139 + err_fd_data: 140 + err_mmap: 141 + /* in case of error: close the buffer fd */ 142 + if (buffer_fd) 143 + close(buffer_fd); 144 + 145 + err_query: 146 + err_heap: 147 + err_alloc: 148 + /* In case of error: close the ion client fd */ 149 + if (ionfd) 150 + close(ionfd); 151 + 152 + return -1; 153 + } 154 + 155 + int ion_import_buffer_fd(struct ion_buffer_info *ion_info) 156 + { 157 + int buffd; 158 + unsigned char *map_buf; 159 + unsigned long map_len; 160 + 161 + if (!ion_info) { 162 + fprintf(stderr, "<%s>: Invalid ion info\n", __func__); 163 + return -1; 164 + } 165 + 166 + map_len = ion_info->buflen; 167 + buffd = ion_info->buffd; 168 + 169 + if (buffd < 0 || map_len <= 0) { 170 + fprintf(stderr, "<%s>: Invalid map data, fd: %d, len: %ld\n", 171 + __func__, buffd, map_len); 172 + goto err_buffd; 173 + } 174 + 175 + map_buf = (unsigned char *)mmap(NULL, map_len, PROT_READ|PROT_WRITE, 176 + MAP_SHARED, buffd, 0); 177 + if (map_buf == MAP_FAILED) { 178 + printf("<%s>: Failed - mmap: %s\n", 179 + __func__, strerror(errno)); 180 + goto err_mmap; 181 + } 182 + 183 + ion_info->buffer = map_buf; 184 + ion_info->buflen = map_len; 185 + 186 + return 0; 187 + 188 + err_mmap: 189 + if (buffd) 190 + close(buffd); 191 + 192 + err_buffd: 193 + return -1; 194 + } 195 + 196 + void ion_close_buffer_fd(struct ion_buffer_info *ion_info) 197 + { 198 + if (ion_info) { 199 + /* unmap the buffer properly in the end */ 200 + munmap(ion_info->buffer, ion_info->buflen); 201 + /* close the buffer fd */ 202 + if (ion_info->buffd > 0) 203 + close(ion_info->buffd); 204 + /* Finally, close the client fd */ 205 + if (ion_info->ionfd > 0) 206 + close(ion_info->ionfd); 207 + printf("<%s>: buffer release successfully....\n", __func__); 208 + } 209 + } 210 + 211 + int socket_send_fd(struct socket_info *info) 212 + { 213 + int status; 214 + int fd, sockfd; 215 + struct socketdata skdata; 216 + 217 + if (!info) { 218 + fprintf(stderr, "<%s>: Invalid socket info\n", __func__); 219 + return -1; 220 + } 221 + 222 + sockfd = info->sockfd; 223 + fd = info->datafd; 224 + memset(&skdata, 0, sizeof(skdata)); 225 + skdata.data = fd; 226 + skdata.len = sizeof(skdata.data); 227 + status = sendtosocket(sockfd, &skdata); 228 + if (status < 0) { 229 + fprintf(stderr, "<%s>: Failed: sendtosocket\n", __func__); 230 + return -1; 231 + } 232 + 233 + return 0; 234 + } 235 + 236 + int socket_receive_fd(struct socket_info *info) 237 + { 238 + int status; 239 + int fd, sockfd; 240 + struct socketdata skdata; 241 + 242 + if (!info) { 243 + fprintf(stderr, "<%s>: Invalid socket info\n", __func__); 244 + return -1; 245 + } 246 + 247 + sockfd = info->sockfd; 248 + memset(&skdata, 0, sizeof(skdata)); 249 + status = receivefromsocket(sockfd, &skdata); 250 + if (status < 0) { 251 + fprintf(stderr, "<%s>: Failed: receivefromsocket\n", __func__); 252 + return -1; 253 + } 254 + 255 + fd = (int)skdata.data; 256 + info->datafd = fd; 257 + 258 + return status; 259 + }
+55
tools/testing/selftests/android/ion/ionutils.h
··· 1 + #ifndef __ION_UTILS_H 2 + #define __ION_UTILS_H 3 + 4 + #include "ion.h" 5 + 6 + #define SOCKET_NAME "ion_socket" 7 + #define ION_DEVICE "/dev/ion" 8 + 9 + #define ION_BUFFER_LEN 4096 10 + #define MAX_HEAP_COUNT ION_HEAP_TYPE_CUSTOM 11 + 12 + struct socket_info { 13 + int sockfd; 14 + int datafd; 15 + unsigned long buflen; 16 + }; 17 + 18 + struct ion_buffer_info { 19 + int ionfd; 20 + int buffd; 21 + unsigned int heap_type; 22 + unsigned int flag_type; 23 + unsigned long heap_size; 24 + unsigned long buflen; 25 + unsigned char *buffer; 26 + }; 27 + 28 + 29 + /* This is used to fill the data into the mapped buffer */ 30 + void write_buffer(void *buffer, unsigned long len); 31 + 32 + /* This is used to read the data from the exported buffer */ 33 + void read_buffer(void *buffer, unsigned long len); 34 + 35 + /* This is used to create an ION buffer FD for the kernel buffer 36 + * So you can export this same buffer to others in the form of FD 37 + */ 38 + int ion_export_buffer_fd(struct ion_buffer_info *ion_info); 39 + 40 + /* This is used to import or map an exported FD. 41 + * So we point to same buffer without making a copy. Hence zero-copy. 42 + */ 43 + int ion_import_buffer_fd(struct ion_buffer_info *ion_info); 44 + 45 + /* This is used to close all references for the ION client */ 46 + void ion_close_buffer_fd(struct ion_buffer_info *ion_info); 47 + 48 + /* This is used to send FD to another process using socket IPC */ 49 + int socket_send_fd(struct socket_info *skinfo); 50 + 51 + /* This is used to receive FD from another process using socket IPC */ 52 + int socket_receive_fd(struct socket_info *skinfo); 53 + 54 + 55 + #endif
+227
tools/testing/selftests/android/ion/ipcsocket.c
··· 1 + #include <stdio.h> 2 + #include <stdlib.h> 3 + #include <string.h> 4 + #include <unistd.h> 5 + #include <sys/types.h> 6 + #include <sys/socket.h> 7 + #include <sys/time.h> 8 + #include <sys/un.h> 9 + #include <errno.h> 10 + 11 + #include "ipcsocket.h" 12 + 13 + 14 + int opensocket(int *sockfd, const char *name, int connecttype) 15 + { 16 + int ret, temp = 1; 17 + 18 + if (!name || strlen(name) > MAX_SOCK_NAME_LEN) { 19 + fprintf(stderr, "<%s>: Invalid socket name.\n", __func__); 20 + return -1; 21 + } 22 + 23 + ret = socket(PF_LOCAL, SOCK_STREAM, 0); 24 + if (ret < 0) { 25 + fprintf(stderr, "<%s>: Failed socket: <%s>\n", 26 + __func__, strerror(errno)); 27 + return ret; 28 + } 29 + 30 + *sockfd = ret; 31 + if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, 32 + (char *)&temp, sizeof(int)) < 0) { 33 + fprintf(stderr, "<%s>: Failed setsockopt: <%s>\n", 34 + __func__, strerror(errno)); 35 + goto err; 36 + } 37 + 38 + sprintf(sock_name, "/tmp/%s", name); 39 + 40 + if (connecttype == 1) { 41 + /* This is for Server connection */ 42 + struct sockaddr_un skaddr; 43 + int clientfd; 44 + socklen_t sklen; 45 + 46 + unlink(sock_name); 47 + memset(&skaddr, 0, sizeof(skaddr)); 48 + skaddr.sun_family = AF_LOCAL; 49 + strcpy(skaddr.sun_path, sock_name); 50 + 51 + ret = bind(*sockfd, (struct sockaddr *)&skaddr, 52 + SUN_LEN(&skaddr)); 53 + if (ret < 0) { 54 + fprintf(stderr, "<%s>: Failed bind: <%s>\n", 55 + __func__, strerror(errno)); 56 + goto err; 57 + } 58 + 59 + ret = listen(*sockfd, 5); 60 + if (ret < 0) { 61 + fprintf(stderr, "<%s>: Failed listen: <%s>\n", 62 + __func__, strerror(errno)); 63 + goto err; 64 + } 65 + 66 + memset(&skaddr, 0, sizeof(skaddr)); 67 + sklen = sizeof(skaddr); 68 + 69 + ret = accept(*sockfd, (struct sockaddr *)&skaddr, 70 + (socklen_t *)&sklen); 71 + if (ret < 0) { 72 + fprintf(stderr, "<%s>: Failed accept: <%s>\n", 73 + __func__, strerror(errno)); 74 + goto err; 75 + } 76 + 77 + clientfd = ret; 78 + *sockfd = clientfd; 79 + } else { 80 + /* This is for client connection */ 81 + struct sockaddr_un skaddr; 82 + 83 + memset(&skaddr, 0, sizeof(skaddr)); 84 + skaddr.sun_family = AF_LOCAL; 85 + strcpy(skaddr.sun_path, sock_name); 86 + 87 + ret = connect(*sockfd, (struct sockaddr *)&skaddr, 88 + SUN_LEN(&skaddr)); 89 + if (ret < 0) { 90 + fprintf(stderr, "<%s>: Failed connect: <%s>\n", 91 + __func__, strerror(errno)); 92 + goto err; 93 + } 94 + } 95 + 96 + return 0; 97 + 98 + err: 99 + if (*sockfd) 100 + close(*sockfd); 101 + 102 + return ret; 103 + } 104 + 105 + int sendtosocket(int sockfd, struct socketdata *skdata) 106 + { 107 + int ret, buffd; 108 + unsigned int len; 109 + char cmsg_b[CMSG_SPACE(sizeof(int))]; 110 + struct cmsghdr *cmsg; 111 + struct msghdr msgh; 112 + struct iovec iov; 113 + struct timeval timeout; 114 + fd_set selFDs; 115 + 116 + if (!skdata) { 117 + fprintf(stderr, "<%s>: socketdata is NULL\n", __func__); 118 + return -1; 119 + } 120 + 121 + FD_ZERO(&selFDs); 122 + FD_SET(0, &selFDs); 123 + FD_SET(sockfd, &selFDs); 124 + timeout.tv_sec = 20; 125 + timeout.tv_usec = 0; 126 + 127 + ret = select(sockfd+1, NULL, &selFDs, NULL, &timeout); 128 + if (ret < 0) { 129 + fprintf(stderr, "<%s>: Failed select: <%s>\n", 130 + __func__, strerror(errno)); 131 + return -1; 132 + } 133 + 134 + if (FD_ISSET(sockfd, &selFDs)) { 135 + buffd = skdata->data; 136 + len = skdata->len; 137 + memset(&msgh, 0, sizeof(msgh)); 138 + msgh.msg_control = &cmsg_b; 139 + msgh.msg_controllen = CMSG_LEN(len); 140 + iov.iov_base = "OK"; 141 + iov.iov_len = 2; 142 + msgh.msg_iov = &iov; 143 + msgh.msg_iovlen = 1; 144 + cmsg = CMSG_FIRSTHDR(&msgh); 145 + cmsg->cmsg_level = SOL_SOCKET; 146 + cmsg->cmsg_type = SCM_RIGHTS; 147 + cmsg->cmsg_len = CMSG_LEN(len); 148 + memcpy(CMSG_DATA(cmsg), &buffd, len); 149 + 150 + ret = sendmsg(sockfd, &msgh, MSG_DONTWAIT); 151 + if (ret < 0) { 152 + fprintf(stderr, "<%s>: Failed sendmsg: <%s>\n", 153 + __func__, strerror(errno)); 154 + return -1; 155 + } 156 + } 157 + 158 + return 0; 159 + } 160 + 161 + int receivefromsocket(int sockfd, struct socketdata *skdata) 162 + { 163 + int ret, buffd; 164 + unsigned int len = 0; 165 + char cmsg_b[CMSG_SPACE(sizeof(int))]; 166 + struct cmsghdr *cmsg; 167 + struct msghdr msgh; 168 + struct iovec iov; 169 + fd_set recvFDs; 170 + char data[32]; 171 + 172 + if (!skdata) { 173 + fprintf(stderr, "<%s>: socketdata is NULL\n", __func__); 174 + return -1; 175 + } 176 + 177 + FD_ZERO(&recvFDs); 178 + FD_SET(0, &recvFDs); 179 + FD_SET(sockfd, &recvFDs); 180 + 181 + ret = select(sockfd+1, &recvFDs, NULL, NULL, NULL); 182 + if (ret < 0) { 183 + fprintf(stderr, "<%s>: Failed select: <%s>\n", 184 + __func__, strerror(errno)); 185 + return -1; 186 + } 187 + 188 + if (FD_ISSET(sockfd, &recvFDs)) { 189 + len = sizeof(buffd); 190 + memset(&msgh, 0, sizeof(msgh)); 191 + msgh.msg_control = &cmsg_b; 192 + msgh.msg_controllen = CMSG_LEN(len); 193 + iov.iov_base = data; 194 + iov.iov_len = sizeof(data)-1; 195 + msgh.msg_iov = &iov; 196 + msgh.msg_iovlen = 1; 197 + cmsg = CMSG_FIRSTHDR(&msgh); 198 + cmsg->cmsg_level = SOL_SOCKET; 199 + cmsg->cmsg_type = SCM_RIGHTS; 200 + cmsg->cmsg_len = CMSG_LEN(len); 201 + 202 + ret = recvmsg(sockfd, &msgh, MSG_DONTWAIT); 203 + if (ret < 0) { 204 + fprintf(stderr, "<%s>: Failed recvmsg: <%s>\n", 205 + __func__, strerror(errno)); 206 + return -1; 207 + } 208 + 209 + memcpy(&buffd, CMSG_DATA(cmsg), len); 210 + skdata->data = buffd; 211 + skdata->len = len; 212 + } 213 + return 0; 214 + } 215 + 216 + int closesocket(int sockfd, char *name) 217 + { 218 + char sockname[MAX_SOCK_NAME_LEN]; 219 + 220 + if (sockfd) 221 + close(sockfd); 222 + sprintf(sockname, "/tmp/%s", name); 223 + unlink(sockname); 224 + shutdown(sockfd, 2); 225 + 226 + return 0; 227 + }
+35
tools/testing/selftests/android/ion/ipcsocket.h
··· 1 + 2 + #ifndef _IPCSOCKET_H 3 + #define _IPCSOCKET_H 4 + 5 + 6 + #define MAX_SOCK_NAME_LEN 64 7 + 8 + char sock_name[MAX_SOCK_NAME_LEN]; 9 + 10 + /* This structure is responsible for holding the IPC data 11 + * data: hold the buffer fd 12 + * len: just the length of 32-bit integer fd 13 + */ 14 + struct socketdata { 15 + int data; 16 + unsigned int len; 17 + }; 18 + 19 + /* This API is used to open the IPC socket connection 20 + * name: implies a unique socket name in the system 21 + * connecttype: implies server(0) or client(1) 22 + */ 23 + int opensocket(int *sockfd, const char *name, int connecttype); 24 + 25 + /* This is the API to send socket data over IPC socket */ 26 + int sendtosocket(int sockfd, struct socketdata *data); 27 + 28 + /* This is the API to receive socket data over IPC socket */ 29 + int receivefromsocket(int sockfd, struct socketdata *data); 30 + 31 + /* This is the API to close the socket connection */ 32 + int closesocket(int sockfd, char *name); 33 + 34 + 35 + #endif
+3
tools/testing/selftests/android/run.sh
··· 1 + #!/bin/sh 2 + 3 + (cd ion; ./ion_test.sh)