nanohub: fix event handling for CHRE

Test: scenario is below

cherry-pick ag/1511251
build and update the nanohub OS;
rebuild all the GTS nanoapps and then rebuild GTS itself

gts-tradefed run everything --skip-system-status-check
  com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker
  --module GtsLocationTestCases --test
  com.google.android.location.gts.ContextHubSendEventNanoAppTest#runTest
  --primary-abi-only

Test should pass

Bug: 31975247
Change-Id: I4b1dfa5ee42e8418356bfffe6199dae0bdb84d64
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
diff --git a/firmware/app/chre/chre_test0.app/main.c b/firmware/app/chre/chre_test0.app/main.c
index 46700ff..acdba52 100644
--- a/firmware/app/chre/chre_test0.app/main.c
+++ b/firmware/app/chre/chre_test0.app/main.c
@@ -18,6 +18,8 @@
 #include <inttypes.h>
 #include <chre.h>
 
+#define CHRE_APP_TAG "CHRE App 0: "
+
 /* chre.h does not define printf format attribute for chreLog() */
 void chreLog(enum chreLogLevel level, const char *str, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
 
@@ -40,9 +42,17 @@
 static int cnt;
 static struct MyTimer mTimer;
 
+static void nanoappFreeEvent(uint16_t eventType, void *data)
+{
+    chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "event callback invoked: eventType=%04" PRIX16
+            "; data=%p\n", eventType, data);
+}
+
 // Default implementation for message free
 static void nanoappFreeMessage(void *msg, size_t size)
 {
+    chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "message callback invoked: msg=%p; size=%08zu\n",
+            msg, size);
     chreHeapFree(msg);
 }
 
@@ -51,14 +61,13 @@
     mMyAppId = chreGetAppId();
     mMyTid = chreGetInstanceId();
     cnt = 3;
-    chreSendEvent(EVT_LOCAL_SETUP, NULL, NULL, mMyTid);
-    chreLog(CHRE_LOG_INFO, "CHRE App 0: init");
+    chreSendEvent(EVT_LOCAL_SETUP, (void*)0x87654321, nanoappFreeEvent, mMyTid);
+    chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "init\n");
     return true;
 }
 
 void nanoappEnd(void)
 {
-    chreLog(CHRE_LOG_INFO, "CHRE App 0: terminating");
 }
 
 void nanoappHandleEvent(uint32_t srcTid, uint16_t evtType, const void* evtData)
@@ -66,7 +75,7 @@
     switch (evtType) {
     case  EVT_LOCAL_SETUP:
         mTimer.timerId = chreTimerSet(kOneSecond, &mTimer, false);
-        chreLog(CHRE_LOG_INFO, "CHRE App 0: started with tid %04" PRIX32
+        chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "started with tid %04" PRIX32
                                " timerid %" PRIu32
                                "\n", mMyTid, mTimer.timerId);
         break;
@@ -75,7 +84,7 @@
         const struct MyTimer *t = (const struct MyTimer *)evtData;
         struct ExtMsg *extMsg = chreHeapAlloc(sizeof(*extMsg));
 
-        chreLog(CHRE_LOG_INFO, "CHRE App 0: received timer %" PRIu32
+        chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "received timer %" PRIu32
                                " (TIME: %" PRIu64
                                ") cnt: %d\n", t->timerId, chreGetTime(), cnt);
         extMsg->msg = 0x01;
@@ -90,7 +99,7 @@
         const struct chreMessageFromHostData *msg = (const struct chreMessageFromHostData *)evtData;
         const uint8_t *data = (const uint8_t *)msg->message;
         const size_t size = msg->messageSize;
-        chreLog(CHRE_LOG_INFO, "CHRE App 0: message=%p; code=%d; size=%zu",
+        chreLog(CHRE_LOG_INFO, CHRE_APP_TAG "message=%p; code=%d; size=%zu\n",
                 data, (data && size) ? data[0] : 0, size);
         break;
     }
diff --git a/firmware/app/chre/common/chre_app.c b/firmware/app/chre/common/chre_app.c
index f95402c..d12941a 100644
--- a/firmware/app/chre/common/chre_app.c
+++ b/firmware/app/chre/common/chre_app.c
@@ -70,6 +70,10 @@
         u.msg.messageSize = hdr->size;
         break;
     }
+    default:
+        // ignore any other system events; OS may send them to any app
+        if (evt < EVT_NO_FIRST_USER_EVENT)
+            return;
     }
     nanoappHandleEvent(srcTid, evt, data);
 }
diff --git a/firmware/os/core/nanohub_chre.c b/firmware/os/core/nanohub_chre.c
index 6a9a4e2..7bb42c8 100644
--- a/firmware/os/core/nanohub_chre.c
+++ b/firmware/os/core/nanohub_chre.c
@@ -45,17 +45,6 @@
  * None of the methods returning uint32_t are cast to uintptr_t
  * This is done in order to let compiler warn us if our assumption is not safe for some reason
  */
-void osChreTaskHandle(struct Task *task, uint32_t evtType, const void *evtData)
-{
-    uint16_t evt = evtType;
-    if (evt < EVT_FIRST_CHRE_USER_EVENT && evt >= EVT_FIRST_CHRE_SYS_EVENT) {
-        evt -= EVT_FIRST_CHRE_SYS_EVENT;
-    } else if (evt >= EVT_FIRST_CHRE_USER_EVENT) {
-        evt = evt - EVT_FIRST_CHRE_USER_EVENT + CHRE_EVENT_FIRST_USER_VALUE;
-    }
-    evtType = EVENT_WITH_ORIGIN(evt, EVENT_GET_ORIGIN(evtType));
-    cpuAppHandle(task->app, &task->platInfo, evtType, evtData);
-}
 
 static inline uint64_t osChreGetAppId(void)
 {
@@ -148,24 +137,33 @@
     heapFree(ptr);
 }
 
+/*
+ * we have no way to verify if this is a CHRE event; just trust the caller to do the right thing
+ */
+void osChreFreeEvent(uint32_t tid, chreEventCompleteFunction *cbFreeEvt, uint32_t evtType, void * evtData)
+{
+    struct Task *chreTask = osTaskFindByTid(tid);
+    struct Task *preempted = osSetCurrentTask(chreTask);
+    if (chreTask && osTaskIsChre(chreTask))
+        osTaskInvokeEventFreeCallback(chreTask, cbFreeEvt, evtType, evtData);
+    osSetCurrentTask(preempted);
+}
+
 static bool osChreSendEvent(uint16_t evtType, void *evtData,
                             chreEventCompleteFunction *evtFreeCallback,
                             uint32_t toTid)
 {
-    uint32_t evt;
-    if (evtType >= CHRE_EVENT_FIRST_USER_VALUE) {
-        evt = evtType - CHRE_EVENT_FIRST_USER_VALUE + EVT_FIRST_CHRE_USER_EVENT;
-        if (evt >= EVT_DEBUG_LOG) {
-            osLog(LOG_INFO, "%s: CHRE User Event %04" PRIX16 " is not compatible with nanohub", __func__, evtType);
-            return false;
-        }
-    } else if (evtType < MAX_CHRE_SYS_EVENTS) {
-        evt = evtType + EVT_FIRST_CHRE_SYS_EVENT;
-    } else {
-        osLog(LOG_INFO, "%s: CHRE System Event %04" PRIX16 " is not compatible with nanohub", __func__, evtType);
+    /*
+     * this primitive may only be used for USER CHRE events;
+     * system events come from the OS itself through different path,
+     * and are interpreted by the CHRE app compatibility library.
+     * therefore, we have to enforce the evtType >= CHRE_EVENT_FIRST_USER_VALUE.
+     */
+    if (evtType < CHRE_EVENT_FIRST_USER_VALUE) {
+        osChreFreeEvent(osGetCurrentTid(), evtFreeCallback, evtType, evtData);
         return false;
     }
-    return osEnqueuePrivateEvtNew(evt, evtData, evtFreeCallback, toTid);
+    return osEnqueuePrivateEvtNew(evtType, evtData, evtFreeCallback, toTid);
 }
 
 static void osChreApiSendEvent(uintptr_t *retValP, va_list args)
@@ -199,7 +197,7 @@
     result = osEnqueueEvtOrFree(EVT_APP_TO_HOST, hostMsg, heapFree);
 
 out:
-    if (freeCallback && message && messageSize)
+    if (freeCallback)
         osTaskInvokeMessageFreeCallback(osGetCurrentTask(), freeCallback, message, messageSize);
     return result;
 }
diff --git a/firmware/os/core/seos.c b/firmware/os/core/seos.c
index 603a55d..450fb66 100644
--- a/firmware/os/core/seos.c
+++ b/firmware/os/core/seos.c
@@ -71,7 +71,7 @@
     return mCurrentTask;
 }
 
-static struct Task *osSetCurrentTask(struct Task *task)
+struct Task *osSetCurrentTask(struct Task *task)
 {
     struct Task *old = mCurrentTask;
     while (true) {
@@ -90,11 +90,6 @@
     return (atomicReadByte(&task->flags) & mask) != 0;
 }
 
-static bool osTaskIsChre(const struct Task *task)
-{
-    return (task->app->hdr.fwFlags & FL_APP_HDR_CHRE) != 0;
-}
-
 bool osAppIsChre(uint16_t tid)
 {
     struct Task *task = osTaskFindByTid(tid);
@@ -321,11 +316,8 @@
 static inline void osTaskHandle(struct Task *task, uint32_t evtType, const void* evtData)
 {
     struct Task *preempted = osSetCurrentTask(task);
-    uint16_t evt = EVENT_GET_EVENT(evtType);
-    if (osTaskIsChre(task))
-        osChreTaskHandle(task, evtType, evtData);
-    else
-        cpuAppHandle(task->app, &task->platInfo, evt, evtData);
+    cpuAppHandle(task->app, &task->platInfo,
+                 osTaskIsChre(task) ? evtType : EVENT_GET_EVENT(evtType), evtData);
     osSetCurrentTask(preempted);
 }
 
@@ -340,7 +332,9 @@
 {
     if (!task || !freeCallback)
         return;
-    cpuAppInvoke(task->app, &task->platInfo, (void (*)(uintptr_t,uintptr_t))freeCallback, (uintptr_t)event, (uintptr_t)data);
+    cpuAppInvoke(task->app, &task->platInfo,
+                 (void (*)(uintptr_t,uintptr_t))freeCallback,
+                 (uintptr_t)event, (uintptr_t)data);
 }
 
 void osEventHeapFree(uint16_t event, void *data)
@@ -350,33 +344,30 @@
 
 static void handleEventFreeing(uint32_t evtType, void *evtData, TaggedPtr evtFreeData) // watch out, this is synchronous
 {
-    uint16_t evt;
-    uint16_t tid;
-    struct Task *srcTask;
+    struct Task *srcTask = osTaskFindByTid(EVENT_GET_ORIGIN(evtType));
 
     if (!taggedPtrToUint(evtFreeData) || !evtData)
         return;
 
-    evt = EVENT_GET_EVENT(evtType);
-    tid = EVENT_GET_ORIGIN(evtType);
-    srcTask = osTaskFindByTid(tid);
+    if (!srcTask) {
+        osLog(LOG_ERROR, "ERROR: Failed to find task to free event: evtType=%08" PRIX32 "\n", evtType);
+        return;
+    }
+
+    // release non-CHRE event; we can't determine if this is CHRE or non-CHRE event, but
+    // this method is only called to release non-CHRE events, so we make use of that fact
 
     if (taggedPtrIsPtr(evtFreeData)) {
-        struct Task *task = osGetCurrentTask();
-        if ((task->app->hdr.fwFlags & FL_APP_HDR_CHRE)) {
-            osTaskInvokeEventFreeCallback(task, (void (*)(uint16_t, void *))taggedPtrToPtr(evtFreeData),
-                                          evt, evtData);
-        } else {
-            ((EventFreeF)taggedPtrToPtr(evtFreeData))(evtData);
-        }
+        // this is for internal non-CHRE tasks, and CHRE tasks
+        // System may schedule non-CHRE events on behalf of CHRE app;
+        // this is the place we release them
+        struct Task *preempted = osSetCurrentTask(srcTask);
+        ((EventFreeF)taggedPtrToPtr(evtFreeData))(evtData);
+        osSetCurrentTask(preempted);
     } else {
+        // this is for external non-CHRE tasks
         struct AppEventFreeData fd = {.evtType = evtType, .evtData = evtData};
-        struct Task* task = osTaskFindByTid(taggedPtrToUint(evtFreeData));
-
-        if (!task)
-            osLog(LOG_ERROR, "EINCEPTION: Failed to find app to call app to free event sent to app(s).\n");
-        else
-            osTaskHandle(task, EVT_APP_FREE_EVT_DATA, &fd);
+        osTaskHandle(srcTask, EVT_APP_FREE_EVT_DATA, &fd);
     }
     osTaskAddIoCount(srcTask, -1);
 }
@@ -716,7 +707,7 @@
         osTaskHandle(task, EVT_APP_STOP, NULL);
         osEnqueueEvtOrFree(EVT_APP_END, task, NULL);
     } else {
-        osTaskEnd(task);
+        osTaskEnd(task); // calls app END() and Release()
         osUnloadApp(task);
     }
 
@@ -726,9 +717,13 @@
 
 void osTaskAbort(struct Task *task)
 {
-    osRemoveTask(task);
-    osTaskRelease(task);
-    osUnloadApp(task);
+    if (!task)
+        return;
+
+    osRemoveTask(task); // remove from active task list
+    // do not call app END()
+    osTaskRelease(task); // release all system resources
+    osUnloadApp(task); // destroy platform app object in RAM
 }
 
 static bool osExtAppFind(struct SegmentIterator *it, uint64_t appId)
@@ -990,7 +985,8 @@
 
     case EVT_PRIVATE_EVT:
         task = osTaskFindByTid(da->privateEvt.toTid);
-        evtType = EVENT_WITH_ORIGIN(da->privateEvt.evtType, da->privateEvt.fromTid);
+        evtType = EVENT_WITH_ORIGIN(da->privateEvt.evtType & EVT_MASK, da->privateEvt.fromTid);
+        evtData = da->privateEvt.evtData;
         if (task) {
             //private events cannot be retained
             TaggedPtr *tmp = mCurEvtEventFreeingInfo;
@@ -998,8 +994,13 @@
             osTaskHandle(task, evtType, da->privateEvt.evtData);
             mCurEvtEventFreeingInfo = tmp;
         }
-
-        handleEventFreeing(evtType, da->privateEvt.evtData, da->privateEvt.evtFreeInfo);
+        if ((da->privateEvt.evtType >> 16) == EVT_PRIVATE_CLASS_CHRE) {
+            osChreFreeEvent(da->privateEvt.fromTid,
+                            (void (*)(uint16_t, void *))taggedPtrToPtr(da->privateEvt.evtFreeInfo),
+                            evtType, evtData);
+        } else {
+            handleEventFreeing(evtType, evtData, da->privateEvt.evtFreeInfo);
+        }
         break;
     }
     osSetCurrentTask(preempted);
@@ -1206,7 +1207,7 @@
     if (taggedPtrToUint(evtFreeInfo) && evtData)
         osTaskAddIoCount(task, 1);
 
-    act->privateEvt.evtType = evtType & EVT_MASK;
+    act->privateEvt.evtType = evtType;
     act->privateEvt.evtData = evtData;
     act->privateEvt.evtFreeInfo = evtFreeInfo;
     act->privateEvt.fromTid = task->tid;
@@ -1218,13 +1219,14 @@
     return result;
 }
 
+// only called to send events for CHRE apps
 bool osEnqueuePrivateEvtNew(uint16_t evtType, void *evtData,
                                    void (*evtFreeCallback)(uint16_t evtType, void *evtData),
                                    uint32_t toTid)
 {
-    if (!osEnqueuePrivateEvtEx(evtType, evtData, taggedPtrMakeFromPtr(evtFreeCallback), toTid)) {
-        handleEventFreeing(EVENT_WITH_ORIGIN(evtType, osGetCurrentTid()),
-                           evtData, taggedPtrMakeFromPtr(evtFreeCallback));
+    if (!osEnqueuePrivateEvtEx(evtType | (EVT_PRIVATE_CLASS_CHRE << 16), evtData,
+                               taggedPtrMakeFromPtr(evtFreeCallback), toTid)) {
+        osChreFreeEvent(osGetCurrentTid(), evtFreeCallback, evtType, evtData);
         return false;
     }
     return true;
@@ -1232,13 +1234,13 @@
 
 bool osEnqueuePrivateEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF, uint32_t toTid)
 {
-    return osEnqueuePrivateEvtEx(evtType, evtData, taggedPtrMakeFromPtr(evtFreeF), toTid);
+    return osEnqueuePrivateEvtEx(evtType & EVT_MASK, evtData, taggedPtrMakeFromPtr(evtFreeF), toTid);
 }
 
 bool osEnqueuePrivateEvtAsApp(uint32_t evtType, void *evtData, uint32_t fromAppTid, uint32_t toTid)
 {
     (void)fromAppTid;
-    return osEnqueuePrivateEvtEx(evtType, evtData, taggedPtrMakeFromUint(osGetCurrentTid()), toTid);
+    return osEnqueuePrivateEvtEx(evtType & EVT_MASK, evtData, taggedPtrMakeFromUint(osGetCurrentTid()), toTid);
 }
 
 bool osTidById(uint64_t *appId, uint32_t *tid)
diff --git a/firmware/os/cpu/cortexm4/appSupport.c b/firmware/os/cpu/cortexm4/appSupport.c
index 5c6605c..41bf8a3 100644
--- a/firmware/os/cpu/cortexm4/appSupport.c
+++ b/firmware/os/cpu/cortexm4/appSupport.c
@@ -202,6 +202,7 @@
         (void)callWithR9((const void*)APP_FLASH_RELOC_BASE(app), app->vec.end, platInfo->data, 0, 0);
     else
         APP_VEC(app)->end();
+    osLog(LOG_INFO, "App ID %016" PRIX64 "; TID=%04" PRIX32 " terminated\n", app->hdr.appId, osGetCurrentTid());
 }
 
 void cpuAppHandle(const struct AppHdr *app, struct PlatAppInfo *platInfo, uint32_t evtType, const void* evtData)
diff --git a/firmware/os/inc/chreApi.h b/firmware/os/inc/chreApi.h
index 8f1ddc6..ef43429 100644
--- a/firmware/os/inc/chreApi.h
+++ b/firmware/os/inc/chreApi.h
@@ -60,5 +60,7 @@
 
 //called by os entry point to export the api
 void osChreApiExport(void);
+// release CHRE event and optionally call completion callback
+void osChreFreeEvent(uint32_t tid, void (*free_info)(uint16_t, void *), uint32_t evtType, void * evtData);
 
 #endif
diff --git a/firmware/os/inc/eventnums.h b/firmware/os/inc/eventnums.h
index 1bb2c6c..e22fa04 100644
--- a/firmware/os/inc/eventnums.h
+++ b/firmware/os/inc/eventnums.h
@@ -20,8 +20,6 @@
 #include <stdint.h>
 #include "toolchain.h"
 
-#define MAX_CHRE_SYS_EVENTS             0x100
-
 /* These define ranges of reserved events */
 // local events are 16-bit always
 #define EVT_NO_FIRST_USER_EVENT          0x00000100    //all events lower than this are reserved for the OS. all of them are nondiscardable necessarily!
@@ -31,8 +29,6 @@
 #define EVT_APP_TO_HOST                  0x00000401    //app data to host. Type is struct HostHubRawPacket
 #define EVT_MARSHALLED_SENSOR_DATA       0x00000402    //marshalled event data. Type is MarshalledUserEventData
 #define EVT_RESET_REASON                 0x00000403    //reset reason to host.
-#define EVT_FIRST_CHRE_SYS_EVENT         0x00000500
-#define EVT_FIRST_CHRE_USER_EVENT        (EVT_FIRST_CHRE_SYS_EVENT + MAX_CHRE_SYS_EVENTS)
 #define EVT_DEBUG_LOG                    0x00007F01    // send message payload to Linux kernel log
 #define EVT_MASK                         0x0000FFFF
 
diff --git a/firmware/os/inc/seos_priv.h b/firmware/os/inc/seos_priv.h
index 214d65a..b38cf4b 100644
--- a/firmware/os/inc/seos_priv.h
+++ b/firmware/os/inc/seos_priv.h
@@ -20,7 +20,6 @@
 #include <inttypes.h>
 #include <seos.h>
 
-#define EVT_PRIVATE_EVT              0x00000003
 #define NO_NODE (TaskIndex)(-1)
 #define for_each_task(listHead, task) for (task = osTaskByIdx((listHead)->next); task; task = osTaskByIdx(task->list.next))
 
@@ -31,6 +30,9 @@
 #define EVT_SUBSCRIBE_TO_EVT         0x00000000
 #define EVT_UNSUBSCRIBE_TO_EVT       0x00000001
 #define EVT_DEFERRED_CALLBACK        0x00000002
+#define EVT_PRIVATE_EVT              0x00000003
+
+#define EVT_PRIVATE_CLASS_CHRE       0x00000001
 
 #define EVENT_WITH_ORIGIN(evt, origin)       (((evt) & EVT_MASK) | ((origin) << (32 - TASK_TID_BITS)))
 #define EVENT_GET_ORIGIN(evt) ((evt) >> (32 - TASK_TID_BITS))
@@ -106,12 +108,18 @@
 
 uint8_t osTaskIndex(struct Task *task);
 struct Task *osGetCurrentTask();
+struct Task *osSetCurrentTask(struct Task *task);
 struct Task *osTaskFindByTid(uint32_t tid);
 void osTaskAbort(struct Task *task);
 void osTaskInvokeMessageFreeCallback(struct Task *task, void (*freeCallback)(void *, size_t), void *message, uint32_t messageSize);
 void osTaskInvokeEventFreeCallback(struct Task *task, void (*freeCallback)(uint16_t, void *), uint16_t event, void *data);
 void osChreTaskHandle(struct Task *task, uint32_t evtType, const void *evtData);
 
+static inline bool osTaskIsChre(const struct Task *task)
+{
+    return (task->app->hdr.fwFlags & FL_APP_HDR_CHRE) != 0;
+}
+
 static inline void osTaskMakeNewTid(struct Task *task)
 {
     task->tid = ((task->tid + TASK_TID_INCREMENT) & TASK_TID_COUNTER_MASK) |