Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7a6c458 authored by Thomas Joseph Avila's avatar Thomas Joseph Avila Committed by Gerrit Code Review
Browse files

Merge "Remove projects being moved into from system/core into system/memory"

parents cafa75ca c19f6300
Loading
Loading
Loading
Loading

libion/Android.bp

deleted100644 → 0
+0 −29
Original line number Diff line number Diff line
cc_library {
    name: "libion",
    vendor_available: true,
    vndk: {
        enabled: true,
        support_system_process: true,
    },
    srcs: ["ion.c"],
    shared_libs: ["liblog"],
    local_include_dirs: [
        "include",
        "kernel-headers",
    ],
    export_include_dirs: [
        "include",
        "kernel-headers",
    ],
    cflags: ["-Werror"],
}

cc_binary {
    name: "iontest",
    srcs: ["ion_test.c"],
    static_libs: ["libion"],
    shared_libs: ["liblog"],
    cflags: ["-Werror"],
}

subdirs = ["tests"]

libion/OWNERS

deleted100644 → 0
+0 −2
Original line number Diff line number Diff line
sspatil@google.com
hridya@google.com

libion/include/ion/ion.h

deleted100644 → 0
+0 −56
Original line number Diff line number Diff line
/*
 *  ion.c
 *
 * Memory Allocator functions for ion
 *
 *   Copyright 2011 Google, Inc
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#ifndef __SYS_CORE_ION_H
#define __SYS_CORE_ION_H

#include <sys/types.h>
#include <linux/ion.h>

__BEGIN_DECLS

struct ion_handle;

int ion_open();
int ion_close(int fd);
int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask,
              unsigned int flags, ion_user_handle_t *handle);
int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask,
              unsigned int flags, int *handle_fd);
int ion_sync_fd(int fd, int handle_fd);
int ion_free(int fd, ion_user_handle_t handle);
int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot,
            int flags, off_t offset, unsigned char **ptr, int *map_fd);
int ion_share(int fd, ion_user_handle_t handle, int *share_fd);
int ion_import(int fd, int share_fd, ion_user_handle_t *handle);

/**
  * Add 4.12+ kernel ION interfaces here for forward compatibility
  * This should be needed till the pre-4.12+ ION interfaces are backported.
  */
int ion_query_heap_cnt(int fd, int* cnt);
int ion_query_get_heaps(int fd, int cnt, void* buffers);

int ion_is_legacy(int fd);
int ion_is_using_modular_heaps(int fd);

__END_DECLS

#endif /* __SYS_CORE_ION_H */

libion/ion.c

deleted100644 → 0
+0 −234
Original line number Diff line number Diff line
/*
 *  ion.c
 *
 * Memory Allocator functions for ion
 *
 *   Copyright 2011 Google, Inc
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
#define LOG_TAG "ion"

#include <errno.h>
#include <fcntl.h>
#include <linux/ion.h>
#include <stdatomic.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>

#include <ion/ion.h>
#include <linux/ion_4.19.h>

#include <log/log.h>

#define ION_ABI_VERSION_MODULAR_HEAPS 2

enum ion_version { ION_VERSION_UNKNOWN, ION_VERSION_MODERN, ION_VERSION_LEGACY };

static atomic_int g_ion_version = ATOMIC_VAR_INIT(ION_VERSION_UNKNOWN);

int ion_is_legacy(int fd) {
    int version = atomic_load_explicit(&g_ion_version, memory_order_acquire);
    if (version == ION_VERSION_UNKNOWN) {
        /**
          * Check for FREE IOCTL here; it is available only in the old
          * kernels, not the new ones.
          */
        int err = ion_free(fd, (ion_user_handle_t)NULL);
        version = (err == -ENOTTY) ? ION_VERSION_MODERN : ION_VERSION_LEGACY;
        atomic_store_explicit(&g_ion_version, version, memory_order_release);
    }
    return version == ION_VERSION_LEGACY;
}

int ion_open() {
    int fd = open("/dev/ion", O_RDONLY | O_CLOEXEC);
    if (fd < 0) ALOGE("open /dev/ion failed: %s", strerror(errno));

    return fd;
}

int ion_close(int fd) {
    int ret = close(fd);
    if (ret < 0) return -errno;
    return ret;
}

static int ion_ioctl(int fd, int req, void* arg) {
    int ret = ioctl(fd, req, arg);
    if (ret < 0) {
        ALOGE("ioctl %x failed with code %d: %s", req, ret, strerror(errno));
        return -errno;
    }
    return ret;
}

int ion_is_using_modular_heaps(int fd) {
    int ion_abi_version = 0;
    int ret = 0;

    ret = ion_ioctl(fd, ION_IOC_ABI_VERSION, &ion_abi_version);
    return (ret == 0 && ion_abi_version >= ION_ABI_VERSION_MODULAR_HEAPS);
}

int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags,
              ion_user_handle_t* handle) {
    int ret = 0;

    if ((handle == NULL) || (!ion_is_legacy(fd))) return -EINVAL;

    struct ion_allocation_data data = {
        .len = len, .align = align, .heap_id_mask = heap_mask, .flags = flags,
    };

    ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
    if (ret < 0) return ret;

    *handle = data.handle;

    return ret;
}

int ion_free(int fd, ion_user_handle_t handle) {
    struct ion_handle_data data = {
        .handle = handle,
    };
    return ion_ioctl(fd, ION_IOC_FREE, &data);
}

int ion_map(int fd, ion_user_handle_t handle, size_t length, int prot, int flags, off_t offset,
            unsigned char** ptr, int* map_fd) {
    if (!ion_is_legacy(fd)) return -EINVAL;
    int ret;
    unsigned char* tmp_ptr;
    struct ion_fd_data data = {
        .handle = handle,
    };

    if (map_fd == NULL) return -EINVAL;
    if (ptr == NULL) return -EINVAL;

    ret = ion_ioctl(fd, ION_IOC_MAP, &data);
    if (ret < 0) return ret;
    if (data.fd < 0) {
        ALOGE("map ioctl returned negative fd");
        return -EINVAL;
    }
    tmp_ptr = mmap(NULL, length, prot, flags, data.fd, offset);
    if (tmp_ptr == MAP_FAILED) {
        ALOGE("mmap failed: %s", strerror(errno));
        return -errno;
    }
    *map_fd = data.fd;
    *ptr = tmp_ptr;
    return ret;
}

int ion_share(int fd, ion_user_handle_t handle, int* share_fd) {
    int ret;
    struct ion_fd_data data = {
        .handle = handle,
    };

    if (!ion_is_legacy(fd)) return -EINVAL;
    if (share_fd == NULL) return -EINVAL;

    ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
    if (ret < 0) return ret;
    if (data.fd < 0) {
        ALOGE("share ioctl returned negative fd");
        return -EINVAL;
    }
    *share_fd = data.fd;
    return ret;
}

int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, unsigned int flags,
                 int* handle_fd) {
    ion_user_handle_t handle;
    int ret;

    if (!handle_fd) return -EINVAL;

    if (!ion_is_legacy(fd)) {
        struct ion_new_allocation_data data = {
            .len = len,
            .heap_id_mask = heap_mask,
            .flags = flags,
        };

        ret = ion_ioctl(fd, ION_IOC_NEW_ALLOC, &data);
        if (ret < 0) return ret;
        *handle_fd = data.fd;
    } else {
        ret = ion_alloc(fd, len, align, heap_mask, flags, &handle);
        if (ret < 0) return ret;
        ret = ion_share(fd, handle, handle_fd);
        ion_free(fd, handle);
    }
    return ret;
}

int ion_import(int fd, int share_fd, ion_user_handle_t* handle) {
    int ret;
    struct ion_fd_data data = {
        .fd = share_fd,
    };

    if (!ion_is_legacy(fd)) return -EINVAL;

    if (handle == NULL) return -EINVAL;

    ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
    if (ret < 0) return ret;
    *handle = data.handle;
    return ret;
}

int ion_sync_fd(int fd, int handle_fd) {
    struct ion_fd_data data = {
        .fd = handle_fd,
    };

    if (!ion_is_legacy(fd)) return -EINVAL;

    return ion_ioctl(fd, ION_IOC_SYNC, &data);
}

int ion_query_heap_cnt(int fd, int* cnt) {
    int ret;
    struct ion_heap_query query;

    if (!cnt) return -EINVAL;
    memset(&query, 0, sizeof(query));

    ret = ion_ioctl(fd, ION_IOC_HEAP_QUERY, &query);
    if (ret < 0) return ret;

    *cnt = query.cnt;
    return ret;
}

int ion_query_get_heaps(int fd, int cnt, void* buffers) {
    int ret;
    struct ion_heap_query query = {
        .cnt = cnt, .heaps = (uintptr_t)buffers,
    };

    ret = ion_ioctl(fd, ION_IOC_HEAP_QUERY, &query);
    return ret;
}

libion/ion_test.c

deleted100644 → 0
+0 −289
Original line number Diff line number Diff line
/*
 *   Copyright 2013 Google, Inc
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <ion/ion.h>
#include <linux/ion.h>

size_t len = 1024*1024, align = 0;
int prot = PROT_READ | PROT_WRITE;
int map_flags = MAP_SHARED;
int alloc_flags = 0;
int heap_mask = 1;
int test = -1;
size_t stride;

int _ion_alloc_test(int *fd, ion_user_handle_t *handle)
{
    int ret;

    *fd = ion_open();
    if (*fd < 0)
        return *fd;

    ret = ion_alloc(*fd, len, align, heap_mask, alloc_flags, handle);

    if (ret)
        printf("%s failed: %s\n", __func__, strerror(ret));
    return ret;
}

void ion_alloc_test()
{
    int fd, ret;
    ion_user_handle_t handle;

    if(_ion_alloc_test(&fd, &handle))
        return;

    ret = ion_free(fd, handle);
    if (ret) {
        printf("%s failed: %s %d\n", __func__, strerror(ret), handle);
        return;
    }
    ion_close(fd);
    printf("ion alloc test: passed\n");
}

void ion_map_test()
{
    int fd, map_fd, ret;
    size_t i;
    ion_user_handle_t handle;
    unsigned char *ptr;

    if(_ion_alloc_test(&fd, &handle))
        return;

    ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd);
    if (ret)
        return;

    for (i = 0; i < len; i++) {
        ptr[i] = (unsigned char)i;
    }
    for (i = 0; i < len; i++)
        if (ptr[i] != (unsigned char)i)
            printf("%s failed wrote %zu read %d from mapped "
                   "memory\n", __func__, i, ptr[i]);
    /* clean up properly */
    ret = ion_free(fd, handle);
    ion_close(fd);
    munmap(ptr, len);
    close(map_fd);

    _ion_alloc_test(&fd, &handle);
    close(fd);

#if 0
    munmap(ptr, len);
    close(map_fd);
    ion_close(fd);

    _ion_alloc_test(len, align, flags, &fd, &handle);
    close(map_fd);
    ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd);
    /* don't clean up */
#endif
}

void ion_share_test()

{
    ion_user_handle_t handle;
    int sd[2];
    int num_fd = 1;
    struct iovec count_vec = {
        .iov_base = &num_fd,
        .iov_len = sizeof num_fd,
    };
    char buf[CMSG_SPACE(sizeof(int))];
    socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
    if (fork()) {
        struct msghdr msg = {
            .msg_control = buf,
            .msg_controllen = sizeof buf,
            .msg_iov = &count_vec,
            .msg_iovlen = 1,
        };

        struct cmsghdr *cmsg;
        int fd, share_fd, ret;
        char *ptr;
        /* parent */
        if(_ion_alloc_test(&fd, &handle))
            return;
        ret = ion_share(fd, handle, &share_fd);
        if (ret)
            printf("share failed %s\n", strerror(errno));
        ptr = mmap(NULL, len, prot, map_flags, share_fd, 0);
        if (ptr == MAP_FAILED) {
            return;
        }
        strcpy(ptr, "master");
        cmsg = CMSG_FIRSTHDR(&msg);
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;
        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
        *(int *)CMSG_DATA(cmsg) = share_fd;
        /* send the fd */
        printf("master? [%10s] should be [master]\n", ptr);
        printf("master sending msg 1\n");
        sendmsg(sd[0], &msg, 0);
        if (recvmsg(sd[0], &msg, 0) < 0)
            perror("master recv msg 2");
        printf("master? [%10s] should be [child]\n", ptr);

        /* send ping */
        sendmsg(sd[0], &msg, 0);
        printf("master->master? [%10s]\n", ptr);
        if (recvmsg(sd[0], &msg, 0) < 0)
            perror("master recv 1");
        close(fd);
        _exit(0);
    } else {
        struct cmsghdr *cmsg;
        char* ptr;
        int fd, recv_fd;
        char* child_buf[100];
        /* child */
        struct iovec count_vec = {
            .iov_base = child_buf,
            .iov_len = sizeof child_buf,
        };

        struct msghdr child_msg = {
            .msg_control = buf,
            .msg_controllen = sizeof buf,
            .msg_iov = &count_vec,
            .msg_iovlen = 1,
        };

        if (recvmsg(sd[1], &child_msg, 0) < 0)
            perror("child recv msg 1");
        cmsg = CMSG_FIRSTHDR(&child_msg);
        if (cmsg == NULL) {
            printf("no cmsg rcvd in child");
            return;
        }
        recv_fd = *(int*)CMSG_DATA(cmsg);
        if (recv_fd < 0) {
            printf("could not get recv_fd from socket");
            return;
        }
        printf("child %d\n", recv_fd);
        fd = ion_open();
        ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0);
        if (ptr == MAP_FAILED) {
            return;
        }
        printf("child? [%10s] should be [master]\n", ptr);
        strcpy(ptr, "child");
        printf("child sending msg 2\n");
        sendmsg(sd[1], &child_msg, 0);
        close(fd);
    }
}

int main(int argc, char* argv[]) {
    int c;
    enum tests {
        ALLOC_TEST = 0, MAP_TEST, SHARE_TEST,
    };

    while (1) {
        static struct option opts[] = {
            {"alloc", no_argument, 0, 'a'},
            {"alloc_flags", required_argument, 0, 'f'},
            {"heap_mask", required_argument, 0, 'h'},
            {"map", no_argument, 0, 'm'},
            {"share", no_argument, 0, 's'},
            {"len", required_argument, 0, 'l'},
            {"align", required_argument, 0, 'g'},
            {"map_flags", required_argument, 0, 'z'},
            {"prot", required_argument, 0, 'p'},
        };
        int i = 0;
        c = getopt_long(argc, argv, "af:h:l:mr:st", opts, &i);
        if (c == -1)
            break;

        switch (c) {
        case 'l':
            len = atol(optarg);
            break;
        case 'g':
            align = atol(optarg);
            break;
        case 'z':
            map_flags = 0;
            map_flags |= strstr(optarg, "PROT_EXEC") ? PROT_EXEC : 0;
            map_flags |= strstr(optarg, "PROT_READ") ? PROT_READ: 0;
            map_flags |= strstr(optarg, "PROT_WRITE") ? PROT_WRITE: 0;
            map_flags |= strstr(optarg, "PROT_NONE") ? PROT_NONE: 0;
            break;
        case 'p':
            prot = 0;
            prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0;
            prot |= strstr(optarg, "MAP_SHARED") ? MAP_SHARED : 0;
            break;
        case 'f':
            alloc_flags = atol(optarg);
            break;
        case 'h':
            heap_mask = atol(optarg);
            break;
        case 'a':
            test = ALLOC_TEST;
            break;
        case 'm':
            test = MAP_TEST;
            break;
        case 's':
            test = SHARE_TEST;
            break;
        }
    }
    printf("test %d, len %zu, align %zu, map_flags %d, prot %d, heap_mask %d,"
           " alloc_flags %d\n", test, len, align, map_flags, prot,
           heap_mask, alloc_flags);
    switch (test) {
        case ALLOC_TEST:
            ion_alloc_test();
            break;
        case MAP_TEST:
            ion_map_test();
            break;
        case SHARE_TEST:
            ion_share_test();
            break;
        default:
            printf("must specify a test (alloc, map, share)\n");
    }
    return 0;
}
Loading