Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2023 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include "ClientController.h"
21 : #include "RialtoClientLogging.h"
22 : #include "SharedMemoryHandle.h"
23 : #include <cstring>
24 : #include <stdexcept>
25 : #include <sys/mman.h>
26 : #include <sys/un.h>
27 : #include <unistd.h>
28 :
29 : namespace
30 : {
31 : // The following error would be reported if a client is deleted
32 : // before unregisterClient() was called. Calling unregisterClient can
33 : // be automated via a proxy class (like the class MediaPipelineProxy)
34 : const std::string kClientPointerNotLocked{"A client could not be locked"};
35 : }; // namespace
36 :
37 : namespace firebolt::rialto::client
38 : {
39 1 : IClientControllerAccessor &IClientControllerAccessor::instance()
40 : {
41 1 : static ClientControllerAccessor factory;
42 1 : return factory;
43 : }
44 :
45 1 : IClientController &ClientControllerAccessor::getClientController() const
46 : {
47 2 : static ClientController ClientController{IControlIpcFactory::createFactory()};
48 0 : return ClientController;
49 : }
50 :
51 20 : ClientController::ClientController(const std::shared_ptr<IControlIpcFactory> &ControlIpcFactory)
52 20 : : m_currentState{ApplicationState::UNKNOWN}, m_registrationRequired{true}
53 : {
54 20 : RIALTO_CLIENT_LOG_DEBUG("entry:");
55 :
56 20 : const char kSrcRev[] = SRCREV;
57 20 : const char kTags[] = TAGS;
58 :
59 : if (std::strlen(kSrcRev) > 0)
60 : {
61 : if (std::strlen(kTags) > 0)
62 : {
63 : RIALTO_CLIENT_LOG_MIL("Release Tag(s): %s (Commit ID: %s)", kTags, kSrcRev);
64 : }
65 : else
66 : {
67 20 : RIALTO_CLIENT_LOG_MIL("Release Tag(s): No Release Tags! (Commit ID: %s)", kSrcRev);
68 : }
69 : }
70 : else
71 : {
72 : RIALTO_CLIENT_LOG_WARN("Failed to get git commit ID!");
73 : }
74 :
75 20 : m_controlIpc = ControlIpcFactory->createControlIpc(this);
76 19 : if (nullptr == m_controlIpc)
77 : {
78 1 : throw std::runtime_error("Failed to create the ControlIpc object");
79 : }
80 28 : }
81 :
82 36 : ClientController::~ClientController()
83 : {
84 18 : RIALTO_CLIENT_LOG_DEBUG("entry:");
85 :
86 18 : termSharedMemory();
87 36 : }
88 :
89 27 : std::shared_ptr<ISharedMemoryHandle> ClientController::getSharedMemoryHandle()
90 : {
91 27 : std::lock_guard<std::mutex> lock{m_mutex};
92 54 : return m_shmHandle;
93 27 : }
94 :
95 13 : bool ClientController::registerClient(std::weak_ptr<IControlClient> client, ApplicationState &appState)
96 : {
97 13 : std::shared_ptr<IControlClient> clientLocked = client.lock();
98 13 : if (!clientLocked)
99 : {
100 1 : RIALTO_CLIENT_LOG_ERROR("Client ptr is null");
101 1 : return false;
102 : }
103 :
104 12 : std::lock_guard<std::mutex> lock{m_mutex};
105 12 : if (m_registrationRequired)
106 : {
107 9 : if (!m_controlIpc->registerClient())
108 : {
109 1 : RIALTO_CLIENT_LOG_ERROR("Failed to register client");
110 1 : return false;
111 : }
112 : }
113 11 : m_registrationRequired = false;
114 :
115 11 : bool alreadyRegistered{std::find_if(m_clients.begin(), m_clients.end(),
116 4 : [&](auto &i)
117 : {
118 4 : std::shared_ptr<IControlClient> iLocked = i.lock();
119 4 : return (iLocked == clientLocked);
120 26 : }) != m_clients.end()};
121 11 : if (!alreadyRegistered)
122 7 : m_clients.push_back(client);
123 11 : appState = m_currentState;
124 :
125 11 : return true;
126 13 : }
127 :
128 1 : bool ClientController::unregisterClient(std::weak_ptr<IControlClient> client)
129 : {
130 1 : std::shared_ptr<IControlClient> clientLocked = client.lock();
131 1 : if (!clientLocked)
132 : {
133 0 : RIALTO_CLIENT_LOG_ERROR("Client ptr is null");
134 0 : return false;
135 : }
136 :
137 1 : std::lock_guard<std::mutex> lock{m_mutex};
138 :
139 1 : bool found{false};
140 1 : for (auto i = m_clients.begin(); i != m_clients.end();)
141 : {
142 1 : std::shared_ptr<IControlClient> iLocked = i->lock();
143 1 : if (!iLocked)
144 : {
145 0 : RIALTO_CLIENT_LOG_ERROR("%s", kClientPointerNotLocked.c_str());
146 0 : i = m_clients.erase(i);
147 : }
148 1 : else if (iLocked == clientLocked)
149 : {
150 1 : i = m_clients.erase(i);
151 1 : found = true;
152 1 : break;
153 : }
154 : else
155 0 : ++i;
156 1 : }
157 :
158 1 : if (!found)
159 : {
160 0 : RIALTO_CLIENT_LOG_ERROR("Client not found");
161 0 : return false;
162 : }
163 :
164 1 : return true;
165 : }
166 :
167 11 : bool ClientController::initSharedMemory()
168 : try
169 : {
170 11 : std::lock_guard<std::mutex> lock{m_mutex};
171 11 : int32_t shmFd{-1};
172 11 : uint32_t shmBufferLen{0U};
173 11 : if (!m_controlIpc->getSharedMemory(shmFd, shmBufferLen))
174 : {
175 1 : RIALTO_CLIENT_LOG_ERROR("Failed to get the shared memory");
176 1 : return false;
177 : }
178 10 : m_shmHandle = std::make_shared<SharedMemoryHandle>(shmFd, shmBufferLen);
179 :
180 8 : RIALTO_CLIENT_LOG_INFO("Shared buffer was successfully initialised");
181 8 : return true;
182 11 : }
183 2 : catch (const std::exception &e)
184 : {
185 2 : RIALTO_CLIENT_LOG_ERROR("Failed to initialise shared memory: %s", e.what());
186 2 : return false;
187 : }
188 :
189 25 : void ClientController::termSharedMemory()
190 : {
191 25 : std::lock_guard<std::mutex> lock{m_mutex};
192 25 : m_shmHandle.reset();
193 : }
194 :
195 19 : void ClientController::notifyApplicationState(ApplicationState state)
196 : {
197 : {
198 19 : std::lock_guard<std::mutex> lock{m_mutex};
199 19 : if (ApplicationState::UNKNOWN == state)
200 : {
201 3 : RIALTO_CLIENT_LOG_DEBUG("Application state changed to unknown. Client will have to register next time");
202 3 : m_registrationRequired = true;
203 : }
204 19 : if (m_currentState == state)
205 : {
206 1 : RIALTO_CLIENT_LOG_WARN("Rialto application state already set, %s", stateToString(m_currentState).c_str());
207 1 : return;
208 : }
209 19 : }
210 :
211 18 : switch (state)
212 : {
213 11 : case ApplicationState::RUNNING:
214 : {
215 11 : if (!initSharedMemory())
216 : {
217 3 : RIALTO_CLIENT_LOG_ERROR("Could not initalise the shared memory");
218 3 : return;
219 : }
220 : // Inform clients after memory initialisation
221 8 : changeStateAndNotifyClients(state);
222 8 : break;
223 : }
224 7 : case ApplicationState::INACTIVE:
225 : case ApplicationState::UNKNOWN:
226 : {
227 : // Inform clients before memory termination
228 7 : changeStateAndNotifyClients(state);
229 7 : termSharedMemory();
230 7 : break;
231 : }
232 : }
233 : }
234 :
235 31 : std::string ClientController::stateToString(ApplicationState state)
236 : {
237 31 : switch (state)
238 : {
239 14 : case ApplicationState::RUNNING:
240 : {
241 14 : return "RUNNING";
242 : }
243 5 : case ApplicationState::INACTIVE:
244 : {
245 5 : return "INACTIVE";
246 : }
247 12 : case ApplicationState::UNKNOWN:
248 : default:
249 : {
250 12 : return "UNKNOWN";
251 : }
252 : }
253 : }
254 :
255 15 : void ClientController::changeStateAndNotifyClients(ApplicationState state)
256 : {
257 15 : std::vector<std::shared_ptr<IControlClient>> currentClients;
258 : {
259 15 : std::lock_guard<std::mutex> lock{m_mutex};
260 15 : RIALTO_CLIENT_LOG_INFO("Rialto application state changed from %s to %s", stateToString(m_currentState).c_str(),
261 : stateToString(state).c_str());
262 15 : m_currentState = state;
263 22 : for (const std::weak_ptr<IControlClient> &client : m_clients)
264 : {
265 7 : std::shared_ptr<IControlClient> clientLocked{client.lock()};
266 7 : if (clientLocked)
267 : {
268 7 : currentClients.push_back(clientLocked);
269 : }
270 : else
271 : {
272 0 : RIALTO_CLIENT_LOG_ERROR("%s", kClientPointerNotLocked.c_str());
273 : }
274 7 : }
275 15 : }
276 22 : for (const auto &client : currentClients)
277 : {
278 7 : client->notifyApplicationState(state);
279 : }
280 15 : }
281 : } // namespace firebolt::rialto::client
|