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