diff options
Diffstat (limited to 'src/listener_android.c')
-rw-r--r-- | src/listener_android.c | 474 |
1 files changed, 474 insertions, 0 deletions
diff --git a/src/listener_android.c b/src/listener_android.c new file mode 100644 index 0000000..00729f4 --- /dev/null +++ b/src/listener_android.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//#include "qurt_mutex.h" +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#include <pthread.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <sys/eventfd.h> + +#include "platform_libs.h" +#include "HAP_farf.h" +#include "verify.h" +#include "mod_table.h" +#include "remote_priv.h" +#include "rpcmem.h" +#include "adsp_listener.h" +#include "listener_buf.h" +#include "shared.h" +#include "AEEstd.h" +#include "fastrpc_apps_user.h" +#include "AEEStdErr.h" + +#define LOGL(format, ...) VERIFY_PRINT_INFO(format, ##__VA_ARGS__) +#ifndef MALLOC +#define MALLOC malloc +#endif + +#ifndef CALLOC +#define CALLOC calloc +#endif + +#ifndef FREE +#define FREE free +#endif + +#ifndef REALLOC +#define REALLOC realloc +#endif + +#ifndef FREEIF +#define FREEIF(pv) \ + do {\ + if(pv) { \ + void* tmp = (void*)pv;\ + pv = 0;\ + FREE(tmp);\ + } \ + } while(0) +#endif + +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/eventfd.h> + +struct listener { + pthread_t thread; + int eventfd; +}; + +static struct listener linfo[NUM_DOMAINS_EXTEND] = +{ [0 ... NUM_DOMAINS_EXTEND - 1] = { .thread = 0, .eventfd = -1 } }; + +//TODO: fix this to work over any number of buffers +// needs qaic to support extra buffers +#define MAX_BUFS 250 +struct invoke_bufs { + adsp_listener_buffer outbufs[MAX_BUFS]; + adsp_listener_buffer inbufs[MAX_BUFS]; + int inbufLenReqs[MAX_BUFS]; + int outbufLenReqs[MAX_BUFS]; + remote_arg args[2*MAX_BUFS]; +}; + +extern void set_thread_context(int domain); + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_remotectl_open)(const char* name, uint32* handle, char* dlStr, int dlerrorLen, int* dlErr) __QAIC_IMPL_ATTRIBUTE +{ + return mod_table_open(name, handle, dlStr, dlerrorLen, dlErr); +} + +__QAIC_IMPL_EXPORT int __QAIC_IMPL(apps_remotectl_close)(uint32 handle, char* errStr, int errStrLen, int* dlErr) __QAIC_IMPL_ATTRIBUTE +{ + return mod_table_close(handle, errStr, errStrLen, dlErr); +} + +#define RPC_FREEIF(heapid, buf) \ +do {\ + if(heapid == -1) {\ + FREEIF(buf);\ + } else {\ + if(buf) {\ + rpcmem_free_internal(buf);\ + buf = 0;\ + }\ + }\ +} while (0) + +static __inline void* rpcmem_realloc(int heapid, uint32 flags, void* buf, int oldsize, int size) { + if(heapid == -1) { + return REALLOC(buf, size); + } else { + void* bufnew = rpcmem_alloc_internal(heapid, flags, size); + if(buf && bufnew) { + memmove(bufnew, buf, oldsize); + rpcmem_free_internal(buf); + buf = NULL; + } + return bufnew; + } +} + +static void* listener(void* arg) { + struct listener* me = (struct listener*)arg; + int numOutBufs = 0; + int nErr = AEE_SUCCESS; + adsp_listener_invoke_ctx ctx = 0; + struct invoke_bufs* bufs = 0; + boolean bNeedMore; + int result = -1; + adsp_listener_remote_handle handle; + uint32 sc; + int ii, inBufsAllocated = 0; + const char* eheap = getenv("ADSP_LISTENER_HEAP_ID"); + int heapid = eheap == 0 ? 0 : (uint32)atoi(eheap); + const char* eflags = getenv("ADSP_LISTENER_HEAP_FLAGS"); + uint32 flags = eflags == 0 ? RPCMEM_HEAP_DEFAULT : (uint32)atoi(eflags); + + if(eheap || eflags) { + FARF(HIGH, "listener using ion heap: %d flags: %x\n", (int)heapid, (int)flags); + } + + VERIFYC(NULL != (bufs = rpcmem_realloc(heapid, flags, 0, 0, sizeof(*bufs))), AEE_ENORPCMEMORY); + memset(bufs, 0, sizeof(*bufs)); + set_thread_context((int)(me - &linfo[0])); + + do { + invoke: + bNeedMore = FALSE; + sc = 0xffffffff; + if(result != AEE_SUCCESS) { + numOutBufs = 0; + } + nErr = __QAIC_HEADER(adsp_listener_next_invoke)( + ctx, result, bufs->outbufs, numOutBufs, &ctx, + &handle, &sc, bufs->inbufs, inBufsAllocated, + bufs->inbufLenReqs, MAX_BUFS, bufs->outbufLenReqs, MAX_BUFS); + if(nErr) { + VERIFY_EPRINTF("listener protocol failure %x\n", nErr); + VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_next_invoke)( + ctx, nErr, 0, 0, &ctx, + &handle, &sc, bufs->inbufs, inBufsAllocated, + bufs->inbufLenReqs, MAX_BUFS, bufs->outbufLenReqs, MAX_BUFS))); + } + + if(MAX_BUFS < REMOTE_SCALARS_INBUFS(sc) || MAX_BUFS < REMOTE_SCALARS_OUTBUFS(sc)) { + result = AEE_EMAXBUFS; + goto invoke; + } + for(ii = 0; ii < (int)REMOTE_SCALARS_INBUFS(sc); ++ii) { + if(bufs->inbufs[ii].dataLen < bufs->inbufLenReqs[ii]) { + if(0 != bufs->inbufLenReqs[ii]) { + bufs->inbufs[ii].data = rpcmem_realloc(heapid, flags, bufs->inbufs[ii].data, bufs->inbufs[ii].dataLen, bufs->inbufLenReqs[ii]); + if(0 == bufs->inbufs[ii].data) { + bufs->inbufs[ii].dataLen = 0; + result = AEE_ENORPCMEMORY; + goto invoke; + } + } + bufs->inbufs[ii].dataLen = bufs->inbufLenReqs[ii]; + inBufsAllocated = STD_MAX(inBufsAllocated, ii + 1); + bNeedMore = TRUE; + } + bufs->args[ii].buf.pv = bufs->inbufs[ii].data; + bufs->args[ii].buf.nLen = bufs->inbufLenReqs[ii]; + } + for(ii = 0; ii < (int)REMOTE_SCALARS_OUTBUFS(sc); ++ii) { + if(bufs->outbufs[ii].dataLen < bufs->outbufLenReqs[ii]) { + if(0 != bufs->outbufLenReqs[ii]) { + bufs->outbufs[ii].data = rpcmem_realloc(heapid, flags, bufs->outbufs[ii].data, bufs->outbufs[ii].dataLen, bufs->outbufLenReqs[ii]); + if(0 == bufs->outbufs[ii].data) { + result = AEE_ENORPCMEMORY; + goto invoke; + } + } + bufs->outbufs[ii].dataLen = bufs->outbufLenReqs[ii]; + } + bufs->args[ii + REMOTE_SCALARS_INBUFS(sc)].buf.pv = bufs->outbufs[ii].data; + bufs->args[ii + REMOTE_SCALARS_INBUFS(sc)].buf.nLen = bufs->outbufLenReqs[ii]; + } + numOutBufs = REMOTE_SCALARS_OUTBUFS(sc); + if(bNeedMore) { + assert(inBufsAllocated >= REMOTE_SCALARS_INBUFS(sc)); + if(0 != (result = __QAIC_HEADER(adsp_listener_invoke_get_in_bufs)(ctx, bufs->inbufs, + REMOTE_SCALARS_INBUFS(sc)))) { + FARF(HIGH, "adsp_listener_invoke_get_in_bufs failed %x\n", result); + goto invoke; + } + } + + result = mod_table_invoke(handle, sc, bufs->args); + } while(1); +bail: + for(ii = 0; ii < MAX_BUFS && bufs; ++ii) { + RPC_FREEIF(heapid, bufs->outbufs[ii].data); + RPC_FREEIF(heapid, bufs->inbufs[ii].data); + } + RPC_FREEIF(heapid, bufs); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: listener thread exiting\n", nErr); + } + return (void*)(uintptr_t)nErr; +} + +static int listener_start_thread(struct listener* me) { + return pthread_create(&me->thread, 0, listener, (void*)me); +} +#define MIN_BUF_SIZE 0x1000 +#define ALIGNB(sz) ((sz) == 0 ? MIN_BUF_SIZE : _SBUF_ALIGN((sz), MIN_BUF_SIZE)) + +static void* listener2(void* arg) { + struct listener* me = (struct listener*)arg; + int nErr = AEE_SUCCESS; + adsp_listener_invoke_ctx ctx = 0; + uint8* outBufs = 0; + int outBufsLen = 0, outBufsCapacity = 0; + uint8* inBufs = 0; + int inBufsLen = 0, inBufsLenReq = 0; + int result = -1; + adsp_listener_remote_handle handle = -1; + uint32 sc = 0; + const char* eheap = getenv("ADSP_LISTENER_HEAP_ID"); + int heapid = eheap == 0 ? -1 : atoi(eheap); + const char* eflags = getenv("ADSP_LISTENER_HEAP_FLAGS"); + uint32 flags = eflags == 0 ? 0 : (uint32)atoi(eflags); + const char* emin = getenv("ADSP_LISTENER_MEM_CACHE_SIZE"); + int cache_size = emin == 0 ? 0 : atoi(emin); + remote_arg args[512]; + struct sbuf buf; + eventfd_t event = 0xff; + + memset(args, 0, sizeof(args)); + set_thread_context((int)(me - &linfo[0])); + if(eheap || eflags || emin) { + FARF(HIGH, "listener using ion heap: %d flags: %x cache: %lld\n", (int)heapid, (int)flags, cache_size); + } + + do { + invoke: + sc = 0xffffffff; + if(result != 0) { + outBufsLen = 0; + } + FARF(HIGH, "responding message for %x %x %x %x", ctx, handle, sc, result); + nErr = __QAIC_HEADER(adsp_listener_next2)( + ctx, result, outBufs, outBufsLen, + &ctx, &handle, &sc, inBufs, inBufsLen, &inBufsLenReq); + FARF(HIGH, "got message for %x %x %x %x", ctx, handle, sc, nErr); + if(nErr) { + VERIFY_EPRINTF("listener protocol failure %x\n", nErr); + if (nErr == AEE_EINTERRUPTED) { + goto invoke; + } + VERIFY(0 == (nErr = __QAIC_HEADER(adsp_listener_next2)( + ctx, nErr, 0, 0, + &ctx, &handle, &sc, inBufs, inBufsLen, + &inBufsLenReq))); + } + if(ALIGNB(inBufsLenReq * 2) < inBufsLen && inBufsLen > cache_size) { + void* buf; + int size = ALIGNB(inBufsLenReq * 2); + if(NULL == (buf = rpcmem_realloc(heapid, flags, inBufs, inBufsLen, size))) { + result = AEE_ENORPCMEMORY; + FARF(HIGH, "rpcmem_realloc shrink failed"); + goto invoke; + } + inBufs = buf; + inBufsLen = size; + } + if(inBufsLenReq > inBufsLen) { + void* buf; + int req; + int oldLen = inBufsLen; + int size = _SBUF_ALIGN(inBufsLenReq, MIN_BUF_SIZE); + if(AEE_SUCCESS == (buf = rpcmem_realloc(heapid, flags, inBufs, inBufsLen, size))) { + result = AEE_ENORPCMEMORY; + FARF(ERROR, "rpcmem_realloc failed"); + goto invoke; + } + inBufs = buf; + inBufsLen = size; + if(0 != (result = __QAIC_HEADER(adsp_listener_get_in_bufs2)(ctx, oldLen, + inBufs + oldLen, + inBufsLen - oldLen, &req))) { + FARF(HIGH, "adsp_listener_invoke_get_in_bufs2 failed %x", result); + goto invoke; + } + if(req > inBufsLen) { + result = AEE_EBADSIZE; + FARF(HIGH, "adsp_listener_invoke_get_in_bufs2 failed %x", result); + goto invoke; + } + } + if(REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc) > 0) { + result = AEE_EINVARGS; + goto invoke; + } + + sbuf_init(&buf, 0, inBufs, inBufsLen); + unpack_in_bufs(&buf, args, REMOTE_SCALARS_INBUFS(sc)); + unpack_out_lens(&buf, args + REMOTE_SCALARS_INBUFS(sc), REMOTE_SCALARS_OUTBUFS(sc)); + + sbuf_init(&buf, 0, 0, 0); + pack_out_bufs(&buf, args + REMOTE_SCALARS_INBUFS(sc), REMOTE_SCALARS_OUTBUFS(sc)); + outBufsLen = sbuf_needed(&buf); + + if(ALIGNB(outBufsLen*2) < outBufsCapacity && outBufsCapacity > cache_size) { + void* buf; + int size = ALIGNB(outBufsLen*2); + if(NULL == (buf = rpcmem_realloc(heapid, flags, outBufs, outBufsCapacity, size))) { + result = AEE_ENORPCMEMORY; + FARF(HIGH, "listener rpcmem_realloc shrink failed"); + goto invoke; + } + outBufs = buf; + outBufsCapacity = size; + } + if(outBufsLen > outBufsCapacity) { + void* buf; + int size = ALIGNB(outBufsLen); + if(NULL == (buf = rpcmem_realloc(heapid, flags, outBufs, outBufsCapacity, size))) { + result = AEE_ENORPCMEMORY; + FARF(ERROR, "listener rpcmem_realloc failed"); + goto invoke; + } + outBufs = buf; + outBufsLen = size; + outBufsCapacity = size; + } + sbuf_init(&buf, 0, outBufs, outBufsLen); + pack_out_bufs(&buf, args + REMOTE_SCALARS_INBUFS(sc), REMOTE_SCALARS_OUTBUFS(sc)); + + result = mod_table_invoke(handle, sc, args); + } while(1); +bail: + RPC_FREEIF(heapid, outBufs); + RPC_FREEIF(heapid, inBufs); + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: listener thread exited", nErr); + } + eventfd_write(me->eventfd, event); + dlerror(); + return (void*)(uintptr_t)nErr; +} +static int listener_start_thread2(struct listener* me) { + return pthread_create(&me->thread, 0, listener2, (void*)me); +} + +extern int apps_remotectl_skel_invoke(uint32 _sc, remote_arg* _pra); +extern int apps_std_skel_invoke(uint32 _sc, remote_arg* _pra); +extern int apps_mem_skel_invoke(uint32 _sc, remote_arg* _pra); +extern int adspmsgd_apps_skel_invoke(uint32_t _sc, remote_arg* _pra); + +#include "adsp_listener_stub.c" +PL_DEP(mod_table) +PL_DEP(apps_std); + +void listener_android_deinit(void) { + PL_DEINIT(mod_table); + PL_DEINIT(apps_std); +} + +int listener_android_init(void) { + int nErr = 0; + + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(mod_table))); + VERIFY(AEE_SUCCESS == (nErr = PL_INIT(apps_std))); + VERIFY(AEE_SUCCESS == (nErr = mod_table_register_const_handle(0, "apps_remotectl", apps_remotectl_skel_invoke))); + VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static("apps_std", apps_std_skel_invoke))); + VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static("apps_mem", apps_mem_skel_invoke))); + VERIFY(AEE_SUCCESS == (nErr = mod_table_register_static("adspmsgd_apps", adspmsgd_apps_skel_invoke))); +bail: + if(nErr != AEE_SUCCESS) { + listener_android_deinit(); + VERIFY_EPRINTF("Error %x: fastrpc listener initialization error", nErr); + } + return nErr; +} + +void listener_android_domain_deinit(int domain) { + struct listener* me = &linfo[domain]; + + FARF(HIGH, "fastrpc listener joining to exit"); + if(me->thread) { + pthread_join(me->thread, 0); + me->thread = 0; + } + FARF(HIGH, "fastrpc listener joined"); + if(me->eventfd != -1) { + close(me->eventfd); + me->eventfd = -1; + } +} + +int listener_android_domain_init(int domain) { + struct listener* me = &linfo[domain]; + int nErr = 0; + + VERIFYC(-1 != (me->eventfd = eventfd(0, 0)), AEE_EINVALIDFD); + nErr = __QAIC_HEADER(adsp_listener_init2)(); + if(AEE_EUNSUPPORTEDAPI == nErr) { + FARF(HIGH, "listener2 initialization error falling back to listener1 %x", nErr); + VERIFY(AEE_SUCCESS == (nErr = __QAIC_HEADER(adsp_listener_init)())); + VERIFY(AEE_SUCCESS == (nErr = listener_start_thread(me))); + } else if(AEE_SUCCESS == nErr) { + FARF(HIGH, "listener2 initialized for domain %d", domain); + VERIFY(AEE_SUCCESS == (nErr = listener_start_thread2(me))); + } + +bail: + if(nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: listener android domain init failed. domain %d\n", nErr, domain); + listener_android_domain_deinit(domain); + } + return nErr; +} + +int listener_android_geteventfd(int domain, int *fd) { + struct listener* me = &linfo[domain]; + int nErr = 0; + + VERIFYC(-1 != me->eventfd, AEE_EINVALIDFD); + *fd = me->eventfd; +bail: + if (nErr != AEE_SUCCESS) { + VERIFY_EPRINTF("Error %x: listener android getevent file descriptor failed for domain %d\n", nErr, domain); + } + return nErr; +} + +PL_DEFINE(listener_android, listener_android_init, listener_android_deinit) |