Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion AppInfrastructure/Public/Dobby/IDobbyProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,18 @@ class IDobbyProxy : public AICommon::Notifier<IDobbyProxyEvents>
}

public:
// Listener for STOPPED events — no exit code, backward-compatible.
typedef std::function<void(int32_t, const std::string&, IDobbyProxyEvents::ContainerState, const void*)> StateChangeListener;

virtual int registerListener(const StateChangeListener &listener, const void* cbParams) = 0;
// Listener for STOPPED_WITH_STATUS events — includes exit code.
typedef std::function<void(int32_t, const std::string&, IDobbyProxyEvents::ContainerState, int32_t, const void*)> StateChangeWithStatusListener;

virtual int registerListener(const StateChangeListener &listener, const void* cbParams) = 0;
virtual void unregisterListener(int tag) = 0;

virtual int registerListenerWithStatus(const StateChangeWithStatusListener &listener, const void* cbParams) = 0;
virtual void unregisterListenerWithStatus(int tag) = 0;


#if (AI_BUILD_TYPE == AI_DEBUG)

Expand Down
15 changes: 12 additions & 3 deletions client/lib/include/DobbyProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,10 @@ class DobbyProxy : public IDobbyProxy
int getContainerState(int32_t cd) const override;

int registerListener(const StateChangeListener &listener, const void* cbParams) override;
void unregisterListener(int id) override;

void unregisterListener(int tag) override;
int registerListenerWithStatus(const StateChangeWithStatusListener &listener, const void* cbParams) override;
void unregisterListenerWithStatus(int id) override;

std::string getContainerInfo(int32_t descriptor) const override;

Expand Down Expand Up @@ -155,6 +157,7 @@ class DobbyProxy : public IDobbyProxy
private:
void onContainerStartedEvent(const AI_IPC::VariantList& args);
void onContainerStoppedEvent(const AI_IPC::VariantList& args);
void onContainerStoppedWithStatusEvent(const AI_IPC::VariantList& args);
void onContainerHibernatedEvent(const AI_IPC::VariantList& args);
void onContainerAwokenEvent(const AI_IPC::VariantList& args);

Expand All @@ -173,6 +176,7 @@ class DobbyProxy : public IDobbyProxy
private:
std::string mContainerStartedSignal;
std::string mContainerStoppedSignal;
std::string mContainerStoppedWithStatusSignal;

private:
std::thread mStateChangeThread;
Expand All @@ -181,19 +185,20 @@ class DobbyProxy : public IDobbyProxy

struct StateChangeEvent
{
enum Type { Terminate, ContainerStarted, ContainerStopped, ContainerHibernated, ContainerAwoken };
enum Type { Terminate, ContainerStarted, ContainerStopped, ContainerStoppedWithStatus, ContainerHibernated, ContainerAwoken };

explicit StateChangeEvent(Type type_)
: type(type_), descriptor(-1)
{ }

StateChangeEvent(Type type_, int32_t descriptor_, const std::string& name_)
: type(type_), descriptor(descriptor_), name(name_)
: type(type_), descriptor(descriptor_), name(name_), exitCode(-1)
{ }

Type type;
int32_t descriptor;
std::string name;
int32_t exitCode;
};

std::deque<StateChangeEvent> mStateChangeQueue;
Expand All @@ -202,6 +207,10 @@ class DobbyProxy : public IDobbyProxy
AICommon::IDGenerator<8> mListenerIdGen;
std::map<int, std::pair<StateChangeListener, const void*>> mListeners;

std::mutex mStatusListenersLock;
AICommon::IDGenerator<8> mStatusListenerIdGen;
std::map<int, std::pair<StateChangeWithStatusListener, const void*>> mStatusListeners;

};


Expand Down
101 changes: 89 additions & 12 deletions client/lib/source/DobbyProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <Logging.h>

#include <sys/wait.h>
#include <thread>


Expand Down Expand Up @@ -89,10 +90,16 @@
const AI_IPC::SignalHandler startedHandler(std::bind(&DobbyProxy::onContainerStartedEvent, this, std::placeholders::_1));
mContainerStartedSignal = mIpcService->registerSignalHandler(startedSignal, startedHandler);

// Subscribe to plain STOPPED to serve StateChangeListener clients (no exit code).
const AI_IPC::Signal stoppedSignal(objectName, DOBBY_CTRL_INTERFACE, DOBBY_CTRL_EVENT_STOPPED);
const AI_IPC::SignalHandler stoppedHandler(std::bind(&DobbyProxy::onContainerStoppedEvent, this, std::placeholders::_1));
mContainerStoppedSignal = mIpcService->registerSignalHandler(stoppedSignal, stoppedHandler);

// Subscribe to STOPPED_WITH_STATUS to serve StateChangeWithStatusListener clients (with exit code).
const AI_IPC::Signal stoppedWithStatusSignal(objectName, DOBBY_CTRL_INTERFACE, DOBBY_CTRL_EVENT_STOPPED_WITH_STATUS);
const AI_IPC::SignalHandler stoppedWithStatusHandler(std::bind(&DobbyProxy::onContainerStoppedWithStatusEvent, this, std::placeholders::_1));
mContainerStoppedWithStatusSignal = mIpcService->registerSignalHandler(stoppedWithStatusSignal, stoppedWithStatusHandler);

const AI_IPC::Signal hibernatedSignal(objectName, DOBBY_CTRL_INTERFACE, DOBBY_CTRL_EVENT_HIBERNATED);
const AI_IPC::SignalHandler hibernatedHandler(std::bind(&DobbyProxy::onContainerHibernatedEvent, this, std::placeholders::_1));
mContainerStartedSignal = mIpcService->registerSignalHandler(hibernatedSignal, hibernatedHandler);
Expand All @@ -101,7 +108,7 @@
const AI_IPC::SignalHandler awokenHandler(std::bind(&DobbyProxy::onContainerAwokenEvent, this, std::placeholders::_1));
mContainerStartedSignal = mIpcService->registerSignalHandler(awokenSignal, awokenHandler);

if (mContainerStartedSignal.empty() || mContainerStoppedSignal.empty())
if (mContainerStartedSignal.empty() || mContainerStoppedSignal.empty() || mContainerStoppedWithStatusSignal.empty())
{
AI_LOG_ERROR("failed to register dbus signal listeners");
}
Expand All @@ -127,6 +134,9 @@
if (!mContainerStoppedSignal.empty())
mIpcService->unregisterHandler(mContainerStoppedSignal);

if (!mContainerStoppedWithStatusSignal.empty())
mIpcService->unregisterHandler(mContainerStoppedWithStatusSignal);

// flush the ipc service to guarantee the signal handlers aren't going to
// be called after we're done
mIpcService->flush();
Expand Down Expand Up @@ -196,6 +206,36 @@
mListenerIdGen.put(id);
}

int DobbyProxy::registerListenerWithStatus(const StateChangeWithStatusListener &listener, const void* cbParams)
{
std::lock_guard<std::mutex> locker(mStatusListenersLock);

int id = mStatusListenerIdGen.get();
if (id < 0)
{
AI_LOG_ERROR("too many status listeners installed");
return -1;
}

mStatusListeners.emplace(id, std::make_pair(listener, cbParams));
return id;
}

void DobbyProxy::unregisterListenerWithStatus(int id)
{
std::lock_guard<std::mutex> locker(mStatusListenersLock);

auto it = mStatusListeners.find(id);
if (it == mStatusListeners.end())
{
AI_LOG_ERROR("no status listener installed with id %d", id);
return;
}

mStatusListeners.erase(it);
mStatusListenerIdGen.put(id);
}

// -----------------------------------------------------------------------------
/**
* @brief Called when a org.rdk.dobby.ctrl1.Started event is received from
Expand Down Expand Up @@ -244,7 +284,7 @@
{
AI_LOG_FN_ENTRY();

// the event should container two args; container descriptor and id
// STOPPED carries two args: container descriptor and id (no exit code).
int32_t descriptor;
std::string id;

Expand All @@ -255,7 +295,6 @@
}
else
{
// ping off an event
std::lock_guard<std::mutex> locker(mStateChangeLock);
mStateChangeQueue.emplace_back(StateChangeEvent::ContainerStopped, descriptor, id);
mStateChangeCond.notify_all();
Expand All @@ -264,6 +303,33 @@
AI_LOG_FN_EXIT();
}

void DobbyProxy::onContainerStoppedWithStatusEvent(const AI_IPC::VariantList& args)
{
AI_LOG_FN_ENTRY();

// STOPPED_WITH_STATUS carries three args: descriptor, id, raw waitpid status.
int32_t descriptor;
std::string id;
int32_t rawStatus;

if (!AI_IPC::parseVariantList<int32_t, std::string, int32_t>(args, &descriptor, &id, &rawStatus))
{
AI_LOG_ERROR("failed to read all args from %s.%s signal",
DOBBY_CTRL_INTERFACE, DOBBY_CTRL_EVENT_STOPPED_WITH_STATUS);
}
else
{
StateChangeEvent ev(StateChangeEvent::ContainerStoppedWithStatus, descriptor, id);
ev.exitCode = WIFEXITED(rawStatus) ? WEXITSTATUS(rawStatus) : -1;

std::lock_guard<std::mutex> locker(mStateChangeLock);
mStateChangeQueue.push_back(ev);

Check notice

Code scanning / Coverity

Variable copied when it could be moved Note

COPY_INSTEAD_OF_MOVE: "ev" is copied and then passed-by-reference as parameter to STL insertion function "std::deque<DobbyProxy::StateChangeEvent, std::allocatorDobbyProxy::StateChangeEvent >::push_back(std::deque<DobbyProxy::StateChangeEvent, std::allocatorDobbyProxy::StateChangeEvent >::value_type const &)", when it could be moved instead.
Remediation Advice: Use "std::move(""ev"")" instead of "ev".
Comment thread
madanagopalt marked this conversation as resolved.
Dismissed
mStateChangeCond.notify_all();
}

AI_LOG_FN_EXIT();
}

// -----------------------------------------------------------------------------
/**
* @brief Called when a org.rdk.dobby.ctrl1.Hibernated event is received from
Expand Down Expand Up @@ -1498,16 +1564,27 @@
notify(&IDobbyProxyEvents::containerStateChanged,
event.descriptor, event.name, state);

// need to hold the lock before searching
std::lock_guard<std::mutex> listenerLocker(mListenersLock);

// check if we have any listener interested in this service
for (const std::pair<const int, std::pair<StateChangeListener, const void*>>& handler : mListeners)
if (event.type == StateChangeEvent::ContainerStoppedWithStatus)
{
// Notify status listeners (include exit code)
std::lock_guard<std::mutex> listenerLocker(mStatusListenersLock);
for (const auto& handler : mStatusListeners)
{
const StateChangeWithStatusListener& cb = handler.second.first;
if (cb)
cb(event.descriptor, event.name, state, event.exitCode, handler.second.second);
}
}
else
{
const StateChangeListener& callback = handler.second.first;
const void* cbParams = handler.second.second;
if (callback)
callback(event.descriptor, event.name, state, cbParams);
// Notify standard listeners (no exit code)
std::lock_guard<std::mutex> listenerLocker(mListenersLock);
for (const auto& handler : mListeners)
{
const StateChangeListener& cb = handler.second.first;
if (cb)
cb(event.descriptor, event.name, state, handler.second.second);
}
}
}

Expand Down
Loading