/* * Copyright (C) 2014-present Amlogic, Inc. All rights reserved. * * All information contained herein is Amlogic confidential. * * This software is provided to you pursuant to Software License Agreement * (SLA) with Amlogic Inc ("Amlogic"). This software may be used * only in accordance with the terms of this agreement. * * Redistribution and use in source and binary forms, with or without * modification is strictly prohibited without prior written permission from * Amlogic. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "dbus_defines.h" #define LOG_MODULE_TAG "PQ" #define LOG_CLASS_TAG "PqService" #include "CPQLog.h" #include "PqClient.h" static sd_bus *gs_signal_bus = nullptr; bool pqclient_preset_signal_bus(sd_bus *bus) { if (nullptr == bus) { LOGE("invalid parameter\n"); return false; } if (nullptr != gs_signal_bus) { LOGE("signal bus already set\n"); return false; } gs_signal_bus = bus; return true; } static int gs_method_call_pipe[2]; static std::vector mPqClientObserver; static int SendEvent(CPqClientCb &cb_data) { for (const auto &o : mPqClientObserver) { if (o != nullptr) { o->GetPqCbData(cb_data); LOGD("send event for %p count PqClientObserver!\n", o); } } return 0; } static int signalCallback(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) { const char *memb = sd_bus_message_get_member(msg); if (strcmp(memb, PQ_SERVICE_SIGNAL_HDR_TYPE) == 0) { PqClientCb::HdrTypeCb cb; int r = sd_bus_message_read(msg, "i", &cb.mHdrType); if (r < 0) return r; SendEvent(cb); } else if (strcmp(memb, PQ_SERVICE_SIGNAL_ALLM_GAME_MODE) == 0) { PqClientCb::AllmGameModeCb cb; int r = sd_bus_message_read(msg, "i", &cb.mAllmGameMode); if (r < 0) return r; SendEvent(cb); } else if (strcmp(memb, PQ_SERVICE_SIGNAL_FILM_MAKER_MODE) == 0) { PqClientCb::FilmMakerModeCb cb; int r = sd_bus_message_read(msg, "i", &cb.mFilmMakerMode); if (r < 0) return r; SendEvent(cb); } else if (strcmp(memb, PQ_SERVICE_SIGNAL_REFRESH_RATE) == 0) { PqClientCb::RefreshRateCb cb; int r = sd_bus_message_read(msg, "i", &cb.mRefreshRate); if (r < 0) return r; SendEvent(cb); } else if (strcmp(memb, PQ_SERVICE_SIGNAL_PICTURE_MODE) == 0) { PqClientCb::PqModeChangedCb cb; int r = sd_bus_message_read(msg, "iiii", &cb.pq_mode_info.pq_mode, &cb.pq_mode_info.hdr_type, &cb.pq_mode_info.input_src, &cb.pq_mode_info.low_latency); if (r < 0) return r; SendEvent(cb); } else if (strcmp(memb, PQ_SERVICE_SIGNAL_PICTURE_MODE_MANUAL) == 0) { PqClientCb::PictureModeCb cb; int r = sd_bus_message_read(msg, "i", &cb.mPictureMode); if (r < 0) return r; SendEvent(cb); } else { LOGE("invalid signal received!\n"); } return 0; } static void bus_cleanup(sd_bus *bus, sd_event *event) { if (event) { sd_event_exit(event, 0); sd_event_unref(event); event = nullptr; } if (bus) { sd_bus_unref(bus); bus = nullptr; } } using DeferCallbackHandler = std::function; struct defer_callback_data { sd_bus *bus; sd_event *event; const DeferCallbackHandler *handler; defer_callback_data(sd_bus *b, sd_event *e, const DeferCallbackHandler *h) : bus(b), event(e), handler(h) {} }; static int defer_callback(sd_event_source *, void *userdata) { auto data = static_cast(userdata); (*data->handler)(data->bus, data->event); delete data; return 0; } static void init_run_bus(DeferCallbackHandler callback) { std::thread t([cb = std::move(callback)]() { sd_bus *bus = nullptr; sd_event *event = nullptr; int r = sd_bus_default_system(&bus); if (r < 0) { LOGE("Failed to open system bus: %s\n", strerror(-r)); return; } r = sd_event_default(&event); if (r < 0) { LOGE("Failed to create event: %s\n", strerror(-r)); sd_bus_unref(bus); return; } r = sd_bus_attach_event(bus, event, 0); if (r < 0) { LOGE("Failed to attach event: %s\n", strerror(-r)); sd_event_unref(event); sd_bus_unref(bus); return; } if (cb) { // Add a defer event r = sd_event_add_defer(event, nullptr, defer_callback, new defer_callback_data(bus, event, &cb)); if (r < 0) { LOGE("Failed to add defer event: %s\n", strerror(-r)); sd_event_unref(event); sd_bus_unref(bus); return; } } sd_event_loop(event); bus_cleanup(bus, event); }); t.detach(); } using onCallPrepareHandler = std::function; using onCallDoneHandler = std::function; struct MethodCallRequest { const char *method; onCallPrepareHandler *callPrepare; onCallDoneHandler *onCallDone; MethodCallRequest() : method(nullptr), callPrepare(nullptr), onCallDone(nullptr) {} MethodCallRequest(const char *m, onCallPrepareHandler *cp, onCallDoneHandler *ocd) : method(m), callPrepare(cp), onCallDone(ocd) {} }; static int on_call_done(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { auto handler = static_cast(userdata); const sd_bus_error *err = sd_bus_message_get_error(m); if (err) { LOGE("Failed to call: %s, %s(%s)\n", strerror(-sd_bus_error_get_errno(err)), err->name, err->message); return (*handler)(nullptr); } return (*handler)(m); } static int method_call_handler(sd_event_source *, int fd, uint32_t /*revents*/, void *userdata) { sd_bus *bus = (sd_bus *)userdata; MethodCallRequest req; int len = read(fd, &req, sizeof(req)); if (len != sizeof(req)) { LOGE("%d read, %d bytes expected\n", len, sizeof(req)); } else { if (req.method == nullptr) return 0; sd_bus_message *msg = nullptr; if (sd_bus_message_new_method_call( bus, &msg, PQ_SERVICE_DBUS_SERVICE, PQ_SERVICE_DBUS_OBJECT, PQ_SERVICE_DBUS_INTERFACE, req.method) < 0) return 0; if (req.callPrepare && !(*req.callPrepare)(msg)) { sd_bus_message_unref(msg); msg = nullptr; return 0; } int r; if ((r = sd_bus_call_async(bus, nullptr, msg, on_call_done, req.onCallDone, 0)) < 0) { LOGE("Failed to async call: %s (%s)\n", req.method, strerror(-r)); (*req.onCallDone)(nullptr); } if (msg) { sd_bus_message_unref(msg); msg = nullptr; } } return 0; } static sd_bus_message * call_method(const char *member, std::function packer) { std::promise b; std::future f = b.get_future(); onCallPrepareHandler prepare( [=](sd_bus_message *msg) -> bool { return packer(msg); }); onCallDoneHandler done([&b](sd_bus_message *m) -> int { sd_bus_message_ref(m); b.set_value(m); return 0; }); MethodCallRequest req(member, packer ? &prepare : nullptr, &done); if (write(gs_method_call_pipe[1], &req, sizeof(req)) != sizeof(req)) { LOGE("Failed to write to pipe: %s\n", strerror(errno)); return nullptr; } sd_bus_message *msg = f.get(); return msg; } #include "dbus_client_api_impl.cpp" PqClient::PqClient() { init_pq_logging(); if (gs_signal_bus) { int r = sd_bus_match_signal( gs_signal_bus, nullptr, PQ_SERVICE_DBUS_SERVICE, PQ_SERVICE_DBUS_OBJECT, PQ_SERVICE_DBUS_INTERFACE, nullptr, signalCallback, nullptr); if (r < 0) { LOGE("Failed to match signal: %s\n", strerror(-r)); } } else { init_run_bus([](sd_bus *bus, sd_event *) { int r = sd_bus_match_signal( bus, nullptr, PQ_SERVICE_DBUS_SERVICE, PQ_SERVICE_DBUS_OBJECT, PQ_SERVICE_DBUS_INTERFACE, nullptr, signalCallback, nullptr); if (r < 0) { LOGE("Failed to match signal: %s\n", strerror(-r)); } }); } std::promise b; std::future f = b.get_future(); init_run_bus([&](sd_bus *bus, sd_event *event) { if (pipe(gs_method_call_pipe) < 0) { LOGE("pipe() failed: %s\n", strerror(errno)); return; } sd_event_add_io(event, nullptr, gs_method_call_pipe[0], POLLIN, method_call_handler, bus); try { b.set_value(true); } catch (const std::future_error &e) { LOGE("%s\n", e.what()); } }); f.get(); } PqClient::~PqClient() { LOGD("%s: PqClient has been destructed.\n", __FUNCTION__); } int PqClient::RegisterObserverToPqClient(PqClientIObserver *observer) { if (observer != nullptr) { mPqClientObserver.emplace_back(observer); LOGD("%s: mPqClientObserver[%p] has been register.\n", __FUNCTION__, observer); } else { LOGD("%s: observer is NULL.\n", __FUNCTION__); } return 0; } PqClient *PqClient::GetInstance() { static std::shared_ptr inst_; if (inst_.get() == nullptr) { inst_ = std::shared_ptr(new PqClient(), [](PqClient *ptr) { delete ptr; }); } return inst_.get(); }