void* LoadDispApisLib() {
    void* handle = nullptr;

    for (auto&& lib : kSdmDispLibs) {
        handle = dlopen(lib, RTLD_NOW);
        if (handle != nullptr) {
            LOG(DEBUG) << "Loaded: " << lib;
            break;
        }
        LOG(INFO) << "Can not load " << lib << " (" << dlerror() << ")";
    }

    return handle;
}

template <typename Function>
Function LoadFunction(void* handle, const char* name) {
    void* fn = dlsym(handle, name);
    if (fn == nullptr) {
        LOG(ERROR) << "LoadFunction -- failed to load function " << name;
    }
    return reinterpret_cast<Function>(fn);
}
}  // anonymous namespace

namespace vendor {
namespace lineage {
namespace livedisplay {
namespace V2_0 {
namespace sdm {

SDMController::SDMController()
    : handle_(LoadDispApisLib(), [this](void* p) {
          FOR_EACH_FUNCTION(CLOSE_SDM_FUNCTION)
          if (p != nullptr) {
              int err = dlclose(p);
              p = nullptr;
              if (err != 0) {
                  LOG(ERROR) << "Failed to close disp api lib.";
              }
          }
      }) {
    if (handle_ == nullptr) {
        // Terminate the program on failure
        LOG(FATAL) << "Failed to load SDM display lib, exiting. (" << dlerror() << ")";
    }

    FOR_EACH_FUNCTION(LOAD_SDM_FUNCTION)

    // Initialize SDM backend
    if (init() != android::OK) {
        // Terminate the program on failure
        LOG(FATAL) << "Failed to initialize SDM backend";
    }
}

SDMController::~SDMController() {
    deinit();
}

status