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