/* * Copyright (C) 2021 The Android Open Source Project * * 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 CHRE_SIMULATION_TEST_UTIL_H_ #define CHRE_SIMULATION_TEST_UTIL_H_ #include #include #include "chre/core/event_loop_manager.h" #include "chre/core/nanoapp.h" #include "chre/util/unique_ptr.h" #include "test_event.h" #include "test_event_queue.h" namespace chre { struct TestNanoapp; /** * @return the statically loaded nanoapp based on the arguments. * * @see chreNslNanoappInfo for param descriptions. */ UniquePtr createStaticNanoapp( const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms, decltype(nanoappStart) *startFunc, decltype(nanoappHandleEvent) *handleEventFunc, decltype(nanoappEnd) *endFunc); /** * Deletes memory allocated by createStaticNanoapp. * * This function must be called when the nanoapp is no more used. */ void deleteNanoappInfos(); /** * Default CHRE nanoapp entry points that don't do anything. */ bool defaultNanoappStart(); void defaultNanoappHandleEvent(uint32_t senderInstanceId, uint16_t eventType, const void *eventData); void defaultNanoappEnd(); /** * Create static nanoapp and load it in CHRE. * * This function returns after the nanoapp start has been executed. * * @see createStatic Nanoapp. */ void loadNanoapp(const char *name, uint64_t appId, uint32_t appVersion, uint32_t appPerms, decltype(nanoappStart) *startFunc, decltype(nanoappHandleEvent) *handleEventFunc, decltype(nanoappEnd) *endFunc); /** * Create a static nanoapp and load it in CHRE. * * This function returns after the nanoapp start has been executed. * * @return An instance of the TestNanoapp. */ template Nanoapp loadNanoapp() { static_assert(std::is_base_of::value); Nanoapp app; loadNanoapp(app.name, app.id, app.version, app.perms, app.start, app.handleEvent, app.end); return app; } /** * Unload a test nanoapp. * * This function returns after the nanoapp end has been executed. * * @param app An instance of TestNanoapp. */ template void unloadNanoapp(Nanoapp app) { static_assert(std::is_base_of::value); unloadNanoapp(app.id); } /** * Unload nanoapp corresponding to appId. * * This function returns after the nanoapp end has been executed. * * @param appId App Id of nanoapp to be unloaded. */ template <> void unloadNanoapp(uint64_t appId); /** * A convenience deferred callback function that can be used to start an already * loaded nanoapp. * * @param type The callback type. * @param nanoapp A pointer to the nanoapp that is already loaded. */ void testFinishLoadingNanoappCallback(SystemCallbackType type, UniquePtr &&nanoapp); /** * A convenience deferred callback function to unload a nanoapp. * * @param type The callback type. * @param data The data containing the appId. * @param extraData Extra data. */ void testFinishUnloadingNanoappCallback(uint16_t type, void *data, void *extraData); /** * Test nanoapp. * * Tests typically inherit this struct to test the nanoapp behavior. * The bulk of the code should be in the handleEvent closure to respond to * events sent to the nanoapp by the platform and by the sendEventToNanoapp * function. start and end can be use to setup and cleanup the test environment * around each test. * * Note: end is only executed when the nanoapp is explicitly unloaded. */ struct TestNanoapp { const char *name = "Test"; uint64_t id = 0x0123456789abcdef; uint32_t version = 0; uint32_t perms = NanoappPermissions::CHRE_PERMS_NONE; bool (*start)() = []() { return true; }; void (*handleEvent)(uint32_t senderInstanceId, uint16_t eventType, const void *eventData) = [](uint32_t, uint16_t, const void *) {}; void (*end)() = []() {}; }; /** * Deallocate the memory allocated for a TestEvent. */ void freeTestEventDataCallback(uint16_t /*eventType*/, void *eventData); /** * Sends a message to a nanoapp. * * This function is typically used to execute code in the context of the * nanoapp in its handleEvent method. * * @param app An instance of TestNanoapp. * @param eventType The event to send. */ template void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType) { static_assert(std::is_base_of::value); uint16_t instanceId; if (EventLoopManagerSingleton::get() ->getEventLoop() .findNanoappInstanceIdByAppId(app.id, &instanceId)) { auto event = memoryAlloc(); ASSERT_NE(event, nullptr); event->type = eventType; EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( CHRE_EVENT_TEST_EVENT, static_cast(event), freeTestEventDataCallback, instanceId); } else { LOGE("No instance found for nanoapp id = 0x%016" PRIx64, app.id); } } /** * Sends a message to a nanoapp with data. * * This function is typically used to execute code in the context of the * nanoapp in its handleEvent method. * * The nanoapp handleEvent function will receive a a TestEvent instance * populated with the eventType and a pointer to as copy of the evenData as * a CHRE_EVENT_TEST_EVENT event. * * @param app An instance of TestNanoapp. * @param eventType The event to send. * @param eventData The data to send. */ template void sendEventToNanoapp(const Nanoapp &app, uint16_t eventType, const T &eventData) { static_assert(std::is_base_of::value); static_assert(std::is_trivial::value); uint16_t instanceId; if (EventLoopManagerSingleton::get() ->getEventLoop() .findNanoappInstanceIdByAppId(app.id, &instanceId)) { auto event = memoryAlloc(); ASSERT_NE(event, nullptr); event->type = eventType; auto ptr = memoryAlloc(); ASSERT_NE(ptr, nullptr); *ptr = eventData; event->data = ptr; EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( CHRE_EVENT_TEST_EVENT, static_cast(event), freeTestEventDataCallback, instanceId); } else { LOGE("No instance found for nanoapp id = 0x%016" PRIx64, app.id); } } } // namespace chre #endif // CHRE_SIMULATION_TEST_UTIL_H_