18f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/* 28f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * Copyright (C) 2017 The Android Open Source Project 38f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * 48f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * Licensed under the Apache License, Version 2.0 (the "License"); 58f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * you may not use this file except in compliance with the License. 68f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * You may obtain a copy of the License at 78f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * 88f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * http://www.apache.org/licenses/LICENSE-2.0 98f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * 108f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * Unless required by applicable law or agreed to in writing, software 118f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * distributed under the License is distributed on an "AS IS" BASIS, 128f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * See the License for the specific language governing permissions and 148f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * limitations under the License. 158f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard */ 168f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 178f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#define LOG_TAG "EffectsFactoryConfigLoader" 188f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard//#define LOG_NDEBUG 0 198f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 208f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include <dlfcn.h> 218f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include <set> 228f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include <stdlib.h> 238f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include <string> 248f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 258f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include <log/log.h> 268f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 278f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include <media/EffectsConfig.h> 288f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 298f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include "EffectsConfigLoader.h" 308f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include "EffectsFactoryState.h" 318f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#include "EffectsXmlConfigLoader.h" 328f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 338f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardnamespace android { 348f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 358f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardusing namespace effectsConfig; 368f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 378f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard///////////////////////////////////////////////// 388f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard// Local functions 398f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard///////////////////////////////////////////////// 408f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 418f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardnamespace { 428f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 438f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** Similarly to dlopen, looks for the provided path in LD_EFFECT_LIBRARY_PATH. 448f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * @return true if the library is found and set resolvedPath to its absolute path. 458f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * false if not found 468f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard */ 478f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardbool resolveLibrary(const std::string& path, std::string* resolvedPath) { 488f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard for (auto* libraryDirectory : LD_EFFECT_LIBRARY_PATH) { 498f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard std::string candidatePath = std::string(libraryDirectory) + '/' + path; 508f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (access(candidatePath.c_str(), R_OK) == 0) { 518f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard *resolvedPath = std::move(candidatePath); 528f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return true; 538f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 548f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 558f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return false; 568f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 578f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 588f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** Loads a library given its relative path and stores the result in libEntry. 598f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * @return true on success with libEntry's path, handle and desc filled 608f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * false on success with libEntry's path filled with the path of the failed lib 618f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * The caller MUST free the resources path (free) and handle (dlclose) if filled. 628f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard */ 638f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardbool loadLibrary(const char* relativePath, lib_entry_t* libEntry) noexcept { 648f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 658f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard std::string absolutePath; 668f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (!resolveLibrary(relativePath, &absolutePath)) { 678f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Could not find library in effect directories: %s", relativePath); 688f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard libEntry->path = strdup(relativePath); 698f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return false; 708f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 718f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard const char* path = absolutePath.c_str(); 728f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard libEntry->path = strdup(path); 738f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 748f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Make sure the lib is closed on early return 758f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard std::unique_ptr<void, decltype(dlclose)*> libHandle(dlopen(path, RTLD_NOW), 768f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard dlclose); 778f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (libHandle == nullptr) { 788f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Could not dlopen library %s: %s", path, dlerror()); 798f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return false; 808f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 818f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 828f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto* description = static_cast<audio_effect_library_t*>( 838f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard dlsym(libHandle.get(), AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR)); 848f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (description == nullptr) { 858f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Invalid effect library, failed not find symbol '%s' in %s: %s", 868f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR, path, dlerror()); 878f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return false; 888f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 898f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 908f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (description->tag != AUDIO_EFFECT_LIBRARY_TAG) { 918f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Bad tag %#08x in description structure, expected %#08x for library %s", 928f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard description->tag, AUDIO_EFFECT_LIBRARY_TAG, path); 938f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return false; 948f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 958f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 968f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard uint32_t majorVersion = EFFECT_API_VERSION_MAJOR(description->version); 978f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION); 988f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (majorVersion != expectedMajorVersion) { 998f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Unsupported major version %#08x, expected %#08x for library %s", 1008f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard majorVersion, expectedMajorVersion, path); 1018f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return false; 1028f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1038f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1048f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard libEntry->handle = libHandle.release(); 1058f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard libEntry->desc = description; 1068f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return true; 1078f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 1088f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1098f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** Because the structures will be destroyed by c code, using new to allocate shared structure 1108f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * is not possible. Provide a equivalent of unique_ptr for malloc/freed structure to make sure 1118f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * they are not leaked in the c++ code. 1128f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard @{ */ 1138f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardstruct FreeDeleter { 1148f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard void operator()(void* p) { 1158f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard free(p); 1168f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1178f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard}; 1188f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** unique_ptr for object created with malloc. */ 1198f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardtemplate <class T> 1208f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardusing UniqueCPtr = std::unique_ptr<T, FreeDeleter>; 1218f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1228f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** c version of std::make_unique. Uses malloc and free. */ 1238f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardtemplate <class T> 1248f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin RocardUniqueCPtr<T> makeUniqueC() { 1258f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard T* ptr = new (malloc(sizeof(T))) T{}; // Use placement new to initialize the structure 1268f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return UniqueCPtr<T>{ptr}; 1278f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 1288f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1298f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** @} */ 1308f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1318f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** Push an not owned element in a list_elem link list with an optional lock. */ 1328f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardtemplate <class T, class ListElem> 1338f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardvoid listPush(T* object, ListElem** list, pthread_mutex_t* mutex = nullptr) noexcept { 1348f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto listElem = makeUniqueC<ListElem>(); 1358f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listElem->object = object; 1368f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (mutex != nullptr) { 1378f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard pthread_mutex_lock(mutex); 1388f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1398f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listElem->next = *list; 1408f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard *list = listElem.release(); 1418f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (mutex != nullptr) { 1428f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard pthread_mutex_unlock(mutex); 1438f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1448f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 1458f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1468f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** Push an owned element in a list_elem link list with an optional lock. */ 1478f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardtemplate <class T, class ListElem> 1488f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardvoid listPush(UniqueCPtr<T>&& object, ListElem** list, pthread_mutex_t* mutex = nullptr) noexcept { 1498f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(object.release(), list, mutex); 1508f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 1518f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1528f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardsize_t loadLibraries(const effectsConfig::Libraries& libs, 1538f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard list_elem_t** libList, pthread_mutex_t* libListLock, 1548f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard list_elem_t** libFailedList) 1558f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard{ 1568f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard size_t nbSkippedElement = 0; 1578f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard for (auto& library : libs) { 1588f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1598f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Construct a lib entry 1608f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto libEntry = makeUniqueC<lib_entry_t>(); 1618f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard libEntry->name = strdup(library.name.c_str()); 1628f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard libEntry->effects = nullptr; 1638f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard pthread_mutex_init(&libEntry->lock, nullptr); 1648f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1658f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (!loadLibrary(library.path.c_str(), libEntry.get())) { 1668f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Register library load failure 1678f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(std::move(libEntry), libFailedList); 1688f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ++nbSkippedElement; 1698f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard continue; 1708f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1718f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(std::move(libEntry), libList, libListLock); 1728f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1738f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return nbSkippedElement; 1748f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 1758f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1768f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** Find a library with the given name in the given list. */ 1778f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardlib_entry_t* findLibrary(const char* name, list_elem_t* list) { 1788f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1798f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard while (list != nullptr) { 1808f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto* object = static_cast<lib_entry_t*>(list->object); 1818f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (strcmp(object->name, name) == 0) { 1828f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return object; 1838f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1848f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard list = list->next; 1858f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 1868f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return nullptr; 1878f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 1888f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1898f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardstruct UuidStr { 1908f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard /** Length of an uuid represented as string. @TODO: use a constant instead of 40. */ 1918f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard char buff[40]; 1928f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard}; 1938f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 1948f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard/** @return a string representing the provided uuid. 1958f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * By not providing an output buffer, it is implicitly created in the caller context. 1968f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard * In such case the return pointer has the same lifetime as the expression containing uuidToString() 1978f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard */ 1988f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardchar* uuidToString(const effect_uuid_t& uuid, UuidStr&& str = {}) { 1998f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard uuidToString(&uuid, str.buff, sizeof(str.buff)); 2008f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return str.buff; 2018f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 2028f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2038f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardstruct LoadEffectResult { 2048f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard /** true if the effect is usable (aka, existing lib, desc, right version, unique uuid) */ 2058f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard bool success = false; 2068f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard /** Set if the effect lib was found*/ 2078f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard lib_entry_t* lib = nullptr; 2088f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard //* Set if the description was successfuly retrieved from the lib */ 2098f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard UniqueCPtr<effect_descriptor_t> effectDesc; 2108f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard}; 2118f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2128f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin RocardLoadEffectResult loadEffect(const EffectImpl& effect, const std::string& name, 2138f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard list_elem_t* libList) { 2148f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard LoadEffectResult result; 2158f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2168f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Find the effect library 2178f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard result.lib = findLibrary(effect.library->name.c_str(), libList); 2188f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (result.lib == nullptr) { 2198f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Could not find library %s to load effect %s", 2208f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard effect.library->name.c_str(), name.c_str()); 2218f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return result; 2228f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 2238f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2248f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard result.effectDesc = makeUniqueC<effect_descriptor_t>(); 2258f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2268f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Get the effect descriptor 2278f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (result.lib->desc->get_descriptor(&effect.uuid, result.effectDesc.get()) != 0) { 2288f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Error querying effect %s on lib %s", 2298f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard uuidToString(effect.uuid), result.lib->name); 2308f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard result.effectDesc.reset(); 2318f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return result; 2328f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 2338f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2348f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Dump effect for debug 2358f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#if (LOG_NDEBUG==0) 2368f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard char s[512]; 2378f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard dumpEffectDescriptor(result.effectDesc.get(), s, sizeof(s), 0 /* indent */); 2388f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGV("loadEffect() read descriptor %p:%s", result.effectDesc.get(), s); 2398f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard#endif 2408f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2418f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Check effect is supported 2428f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION); 2438f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (EFFECT_API_VERSION_MAJOR(result.effectDesc->apiVersion) != expectedMajorVersion) { 2448f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Bad API version %#08x for effect %s in lib %s, expected major %#08x", 2458f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard result.effectDesc->apiVersion, name.c_str(), result.lib->name, expectedMajorVersion); 2468f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return result; 2478f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 2488f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2498f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard lib_entry_t *_; 2508f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (findEffect(nullptr, &effect.uuid, &_, nullptr) == 0) { 2518f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Effect %s uuid %s already exist", uuidToString(effect.uuid), name.c_str()); 2528f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return result; 2538f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 2548f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2558f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard result.success = true; 2568f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return result; 2578f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 2588f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2598f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocardsize_t loadEffects(const Effects& effects, list_elem_t* libList, list_elem_t** skippedEffects, 2608f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard list_sub_elem_t** subEffectList) { 2618f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard size_t nbSkippedElement = 0; 2628f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2638f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard for (auto& effect : effects) { 2648f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2658f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto effectLoadResult = loadEffect(effect, effect.name, libList); 2668f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (!effectLoadResult.success) { 2678f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (effectLoadResult.effectDesc != nullptr) { 2688f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(std::move(effectLoadResult.effectDesc), skippedEffects); 2698f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 2708f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ++nbSkippedElement; 2718f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard continue; 2728f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 2738f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2748f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (effect.isProxy) { 2758f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto swEffectLoadResult = loadEffect(effect.libSw, effect.name + " libsw", libList); 2768f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto hwEffectLoadResult = loadEffect(effect.libHw, effect.name + " libhw", libList); 2778f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (!swEffectLoadResult.success || !hwEffectLoadResult.success) { 2788f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Push the main effect in the skipped list even if only a subeffect is invalid 2798f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // as the main effect is not usable without its subeffects. 2808f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(std::move(effectLoadResult.effectDesc), skippedEffects); 2818f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ++nbSkippedElement; 2828f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard continue; 2838f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 28460c1b59023a84a5f854246c89974519b94642bf5Mikhail Naganov listPush(effectLoadResult.effectDesc.get(), subEffectList); 2858f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2868f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // Since we return a dummy descriptor for the proxy during 2878f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // get_descriptor call, we replace it with the corresponding 2888f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // sw effect descriptor, but keep the Proxy UUID 2898f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard *effectLoadResult.effectDesc = *swEffectLoadResult.effectDesc; 2908f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard effectLoadResult.effectDesc->uuid = effect.uuid; 2918f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2928f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard effectLoadResult.effectDesc->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED; 2938f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 2948f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto registerSubEffect = [subEffectList](auto&& result) { 2958f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto entry = makeUniqueC<sub_effect_entry_t>(); 2968f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard entry->object = result.effectDesc.release(); 2978f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard // lib_entry_t is stored since the sub effects are not linked to the library 2988f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard entry->lib = result.lib; 2998f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(std::move(entry), &(*subEffectList)->sub_elem); 3008f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard }; 3018f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard registerSubEffect(std::move(swEffectLoadResult)); 3028f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard registerSubEffect(std::move(hwEffectLoadResult)); 3038f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 3048f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 3058f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard listPush(std::move(effectLoadResult.effectDesc), &effectLoadResult.lib->effects); 3068f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 3078f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return nbSkippedElement; 3088f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 3098f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 3108f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} // namespace 3118f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 3128f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard///////////////////////////////////////////////// 3138f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard// Interface function 3148f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard///////////////////////////////////////////////// 3158f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 31641af42b44e5d47bc3a1ca90d170f8da7205cacb8Kevin Rocardextern "C" ssize_t EffectLoadXmlEffectConfig(const char* path) 3178f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard{ 3188f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard using effectsConfig::parse; 3198f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard auto result = path ? parse(path) : parse(); 3208f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard if (result.parsedConfig == nullptr) { 3218f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE("Failed to parse XML configuration file"); 3228f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return -1; 3238f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard } 3248f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard result.nbSkippedElement += loadLibraries(result.parsedConfig->libraries, 3258f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard &gLibraryList, &gLibLock, &gLibraryFailedList) + 3268f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard loadEffects(result.parsedConfig->effects, gLibraryList, 3278f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard &gSkippedEffects, &gSubEffectList); 3288f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 3298f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard ALOGE_IF(result.nbSkippedElement != 0, "%zu errors during loading of configuration: %s", 3308cb2eab728fb263e21e18f33d608df69845a1cc3Kevin Rocard result.nbSkippedElement, result.configPath ?: "No config file found"); 3318f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 3328f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard return result.nbSkippedElement; 3338f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} 3348f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard 3358f5520a7378e7af0fcc6a8b693f29a6ddffbbbcdKevin Rocard} // namespace android 336