+++ /dev/null
-/*
- * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __SERVICE_MANAGER_H__
-#define __SERVICE_MANAGER_H__
-
-#include <service.h>
-#include <service_types.h>
-#include <tizen.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief The handle for the service manager event handler.
- * @since_tizen 10.0
- */
-typedef void *service_manager_event_h;
-
-/**
- * @brief Called when the service state changes.
- * @since_tizen 10.0
- * @param[in] service The service handle
- * @param[in] state The state of the service
- * @param[in] user_data The user data passed from the add event handler function
- * @see service_manager_add_event_handler()
- * @remarks The @a service should not be freed. The @a service can be used only in the callback.
- */
-typedef void (*service_state_changed_cb)(service_h service,
- service_state_e state,
- void *user_data);
-
-/**
- * @brief Adds a service state change event handler.
- * @since_tizen 10.0
- * @param[in] callback The callback function to invoke
- * @param[in] user_data The user data to be passed to the callback function
- * @param[out] event_handler The event handler
- * @return @c 0 on success,
- * otherwise a negative error value
- * @retval #SERVICE_ERROR_NONE Successful
- * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #SERVICE_ERROR_OUT_OF_MEMORY Out of memory
- * @see service_manager_remove_event_handler()
- * @see service_state_changed_cb()
- * @remarks The @a event_handler should be released using service_manager_remove_event_handler().
- *
- * @code
-#include <service_manager.h>
-#include <dlog.h>
-
-#undef LOG_TAG
-#define LOG_TAG "ALARM_SERVICE"
-
-static service_manager_event_h __event_handler;
-
-static void ServiceStateChangedCb(service_h service, service_state_e state,
- void* user_data) {
- char* name = nullptr;
- service_get_name(service, &name);
- LOGD("name=%s, state=%d", name, state);
- free(name);
-}
-
-int AddEventHandler(void) {
- service_manager_event_h event_handler = nullptr;
- int ret = service_manager_add_event_handler(ServiceStateChangedCb, nullptr,
- &event_handler);
- if (ret != SERVICE_MANAGER_ERROR_NONE) {
- LOGE("Failed to add event handler. error=%d", ret);
- return ret;
- }
-
- return 0;
-}
- * @endcode
- */
-int service_manager_add_event_handler(service_state_changed_cb callback,
- void *user_data,
- service_manager_event_h *event_handler);
-
-/**
- * @brief Removes a service state change event handler.
- * @since_tizen 10.0
- * @param[in] event_handler The event handler
- * @return @c 0 on success,
- * otherwise a negative error value
- * @retval #SERVICE_ERROR_NONE Successful
- * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
- * @see service_manager_add_event_handler()
- *
- * @code
-#include <service_manager.h>
-#include <dlog.h>
-
-#undef LOG_TAG
-#define LOG_TAG "ALARM_SERVICE"
-
-static service_manager_event_h __event_handler;
-
-// ...
-
-void RemoveEventHandler(void) {
- service_manager_remove_event_handler(__event_handler);
-}
- * @endcode
- */
-int service_manager_remove_event_handler(service_manager_event_h event_handler);
-
-/**
- * @brief Gets the service handle by the name.
- * @since_tizen 10.0
- * @param[in] name The name of the service
- * @param[out] service The service handle
- * @return @c 0 on success,
- * otherwise a negative error value
- * @retval #SERVICE_ERROR_NONE Successful
- * @retval #SERVICE_ERROR_INVALID_PARAMETER Invalid parameter
- * @remarks The @a service should not be released using service_destroy().
- *
- * @code
-#include <service_manager.h>
-#include <dlog.h>
-
-#undef LOG_TAG
-#define LOG_TAG "ALARM_SERVICE"
-
-service_h GetServiceFromName(const char* name) {
- service_h service = nullptr;
- int ret = service_manager_get_service(name, &service);
- if (ret != SERVICE_MANAGER_ERROR_NONE) {
- LOGE("Failed to get service. error=%d", ret);
- return nullptr;
- }
-
- return service;
-}
- * @endcode
- */
-int service_manager_get_service(const char *name, service_h *service);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SERVICE_MANAGER_H__ */
#include "service.hh"
+#include <glib.h>
#include <tizen_core.h>
#include <stdexcept>
#include "service_manager.hh"
namespace tizen_base {
+namespace {
+
+class ServiceStateChangedEventArgs {
+ public:
+ ServiceStateChangedEventArgs(Service* service, Service::State state)
+ : service_(service), state_(state) {}
+
+ const Service* GetService() const { return service_; }
+
+ Service::State GetState() const { return state_; }
+
+ private:
+ Service* service_;
+ Service::State state_;
+};
+
+} // namespace
Service::Service(std::shared_ptr<ServiceInfo> info,
std::shared_ptr<IEvent> listener)
THROW(SERVICE_ERROR_INVALID_CONTEXT);
}
- ServiceManager::GetInst().NotifyServiceStateChanged(this);
+ NotifyStateChanged();
}
Service::~Service() {
core_, [](void* user_data) -> bool {
auto* service = static_cast<Service*>(user_data);
service->tid_ = gettid();
- service->OnCreate();
+ service->OnBaseCreate();
service->state_ = Service::State::Running;
- ServiceManager::GetInst().NotifyServiceStateChanged(service);
+ service->NotifyStateChanged();
return false;
}, this, &source);
core_,
[](void* user_data) -> bool {
auto* service = static_cast<Service*>(user_data);
- std::unique_lock<std::mutex> idle_lock(service->mutex_);
- service->OnDestroy();
- service->cond_var_.notify_one();
+ auto service_ptr = service->shared_from_this();
+ service->OnBaseDestroy();
return false;
},
this, &source);
tizen_core_task_quit(task_);
- if (gettid() != tid_)
- cond_var_.wait(lock, [this]() { return state_ == State::Destroyed; });
-
running_ = false;
}
}
}
-void Service::OnCreate() {
+void Service::OnBaseCreate() {
state_ = State::Created;
if (listener_.use_count() > 1) listener_->OnCreate(this);
- ServiceManager::GetInst().NotifyServiceStateChanged(this);
+ NotifyStateChanged();
}
-void Service::OnDestroy() {
+void Service::OnBaseDestroy() {
state_ = State::Destroyed;
if (listener_.use_count() > 1) listener_->OnDestroy(this);
- ServiceManager::GetInst().NotifyServiceStateChanged(this);
+ NotifyStateChanged();
}
-void Service::OnMessageReceived(const std::string& sender,
- const tizen_base::Bundle& envelope) {
+void Service::OnBaseMessageReceived(const std::string& sender,
+ const tizen_base::Bundle& envelope) {
if (listener_.use_count() > 1)
listener_->OnMessageReceived(this, sender, envelope);
}
const char* task_name = nullptr;
tizen_core_channel_object_get_sender_task_name(object, &task_name);
auto* service = static_cast<Service*>(user_data);
- service->OnMessageReceived(task_name != nullptr ? task_name : "",
- tizen_base::Bundle(data, false, true));
+ service->OnBaseMessageReceived(task_name != nullptr ? task_name : "",
+ tizen_base::Bundle(data, false, true));
+}
+
+void Service::SetStateChangedCb(StateChangedCb cb) {
+ state_changed_cb_ = std::move(cb);
+}
+
+void Service::NotifyStateChanged() {
+ auto* args = new ServiceStateChangedEventArgs(this, state_);
+ g_idle_add(
+ [](gpointer user_data) {
+ auto* args = static_cast<ServiceStateChangedEventArgs*>(user_data);
+ auto& cb = args->GetService()->state_changed_cb_;
+ if (cb != nullptr) cb(args->GetService(), args->GetState());
+ delete args;
+ return G_SOURCE_REMOVE;
+ },
+ args);
}
} // namespace tizen_base
#include <atomic>
#include <condition_variable>
+#include <functional>
#include <memory>
#include <mutex>
#include <string>
const Bundle& envelope) = 0;
};
+ using StateChangedCb =
+ std::function<void(const Service*, Service::State)>;
+
Service(std::shared_ptr<ServiceInfo> info, std::shared_ptr<IEvent> listener);
virtual ~Service();
tizen_core_h GetCore() const;
tizen_core_channel_sender_h GetChannelSender() const;
void SendMessage(const tizen_base::Bundle& envelope);
-
- void OnCreate();
- void OnDestroy();
- void OnMessageReceived(const std::string& sender,
- const tizen_base::Bundle& envelope);
+ void SetStateChangedCb(StateChangedCb cb);
private:
+ void OnBaseCreate();
+ void OnBaseDestroy();
+ void OnBaseMessageReceived(const std::string& sender,
+ const tizen_base::Bundle& envelope);
+ void NotifyStateChanged();
+
bool Init();
void Shutdown();
static void ChannelReceiveCb(tizen_core_channel_object_h object,
std::mutex mutex_;
std::condition_variable cond_var_;
pid_t tid_ = -1;
+ StateChangedCb state_changed_cb_ = nullptr;
};
} // namespace tizen_base
THROW(SERVICE_ERROR_NO_SUCH_SERVICE);
}
- auto listener = ServiceManager::GetInst().GetServiceEventListener(name);
+ auto listener = ServiceManager::GetInst().Get(name);
if (listener == nullptr) {
_E("No such event listener. name=%s", name.c_str());
THROW(SERVICE_ERROR_INVALID_CONTEXT);
THROW(SERVICE_ERROR_OUT_OF_MEMORY);
}
+ service->SetStateChangedCb(std::bind(&ServiceLoader::ServiceStateChangedCb,
+ this, std::placeholders::_1,
+ std::placeholders::_2));
+ services_[name] = service;
service->Run();
}
void ServiceLoader::OnMessageReceived(const std::string& sender,
const tizen_base::Bundle& envelope) {}
+void ServiceLoader::OnServiceStateChanged(const Service* service,
+ Service::State state) {}
+
void ServiceLoader::ChannelReceiveCb(tizen_core_channel_object_h object,
void* user_data) {
bundle* data = nullptr;
return found->second;
}
+void ServiceLoader::ServiceStateChangedCb(const Service* service,
+ Service::State state) {
+ OnServiceStateChanged(service, state);
+ if (state == Service::State::Destroyed) {
+ services_.erase(service->GetName());
+ }
+}
+
} // namespace tizen_base
virtual void OnDestroy();
virtual void OnMessageReceived(const std::string& sender,
const tizen_base::Bundle& envelope);
+ virtual void OnServiceStateChanged(const Service* service,
+ Service::State state);
private:
std::shared_ptr<Service> GetService(const std::string& name);
std::shared_ptr<ServiceInfo> GetServiceInfo(const std::string& name);
+ void ServiceStateChangedCb(const Service* service, Service::State state);
bool Init();
void Shutdown();
return inst;
}
-bool ServiceManager::Insert(std::string name,
- std::shared_ptr<Service> service) {
- if (services_.find(name) != services_.end()) {
- _E("Service(%s) already exists", name.c_str());
- return false;
- }
-
- services_[name] = std::move(service);
- return true;
-}
-
-std::shared_ptr<Service> ServiceManager::Get(const std::string& name) const {
- if (services_.find(name) == services_.end()) {
- _W("Service(%s) does not exist", name.c_str());
- return nullptr;
- }
-
- return services_.at(name);
-}
-
-bool ServiceManager::Contains(const std::string& name) const {
- return services_.find(name) != services_.end();
-}
-
-void ServiceManager::Remove(const std::string& name) {
- auto it = services_.find(name);
- if (it == services_.end())
- return;
-
- auto service = it->second;
- listeners_.erase(service);
- services_.erase(it);
-}
-
-void ServiceManager::AddEventListener(const std::shared_ptr<Service>& service,
- IEvent* listener) {
- listeners_[service].push_back(listener);
-}
-
-void ServiceManager::RemoveEventListener(
- const std::shared_ptr<Service>& service,
- IEvent* listener) {
- auto found = listeners_.find(service);
- if (found == listeners_.end())
- return;
-
- auto& core_listeners = found->second;
- auto it = std::find(core_listeners.begin(), core_listeners.end(), listener);
- if (it != core_listeners.end())
- core_listeners.erase(it);
-}
-
-void ServiceManager::NotifyServiceStateChanged(Service* service) {
- for (auto [svc, listeners] : listeners_) {
- for (auto listener : listeners) {
- auto* cb_info = new std::tuple<IEvent*, Service*, Service::State>(
- listener, service, service->GetState());
- tizen_core_source_h source = nullptr;
- tizen_core_add_idle_job(
- svc->GetCore(),
- [](void* user_data) -> bool {
- auto* cb_info =
- static_cast<std::tuple<IEvent*, Service*, Service::State>*>(
- user_data);
- auto [listener, service, state] = *cb_info;
- delete cb_info;
- listener->OnServiceStateChanged(service, state);
- return false;
- },
- cb_info, &source);
- if (source == nullptr) {
- _E("Failed to create idle job");
- delete cb_info;
- }
- }
- }
-}
-
-void ServiceManager::RegisterServiceEventListener(
- std::string name, std::shared_ptr<Service::IEvent> listener) {
- if (!Contains(name)) {
- _E("Invalid parameter");
+void ServiceManager::Register(std::string name,
+ std::shared_ptr<Service::IEvent> listener) {
+ auto found = listeners_.find(name);
+ if (found != listeners_.end()) {
+ _E("Already registered");
return;
}
- service_listeners_[std::move(name)] = std::move(listener);
+ listeners_[std::move(name)] = std::move(listener);
}
-void ServiceManager::UnregisterServiceEventListener(const std::string& name) {
- auto found = service_listeners_.find(name);
- if (found == service_listeners_.end()) return;
+void ServiceManager::Unregister(const std::string& name) {
+ auto found = listeners_.find(name);
+ if (found == listeners_.end()) return;
- service_listeners_.erase(found);
+ listeners_.erase(found);
}
-std::shared_ptr<Service::IEvent> ServiceManager::GetServiceEventListener(
- const std::string& name) {
- auto found = service_listeners_.find(name);
- if (found == service_listeners_.end()) return nullptr;
+std::shared_ptr<Service::IEvent> ServiceManager::Get(const std::string& name) {
+ auto found = listeners_.find(name);
+ if (found == listeners_.end()) return nullptr;
return found->second;
}
-std::shared_ptr<Service> ServiceManager::FindFromThisThread() {
- tizen_core_h core = nullptr;
- tizen_core_find_from_this_thread(&core);
- if (core == nullptr)
- return nullptr;
-
- auto it = std::find_if(
- services_.begin(), services_.end(),
- [&](const std::pair<std::string, std::shared_ptr<Service>>& element)
- -> bool {
- auto& [name, service] = element;
- return service->GetCore() == core;
- });
-
- if (it == services_.end())
- return nullptr;
-
- return it->second;
-}
-
ServiceManager::ServiceManager() {}
ServiceManager::~ServiceManager() {}
class ServiceManager {
public:
- class IEvent {
- public:
- virtual ~IEvent() = default;
- virtual void OnServiceStateChanged(Service* service,
- Service::State state) = 0;
- };
-
static ServiceManager& GetInst();
- bool Insert(std::string name, std::shared_ptr<Service> service);
- std::shared_ptr<Service> Get(const std::string& name) const;
- bool Contains(const std::string& name) const;
- void Remove(const std::string& name);
- void AddEventListener(const std::shared_ptr<Service>& service,
- IEvent* listener);
- void RemoveEventListener(const std::shared_ptr<Service>& service,
- IEvent* listener);
- void NotifyServiceStateChanged(Service* service);
- void RegisterServiceEventListener(std::string name,
- std::shared_ptr<Service::IEvent> listener);
- void UnregisterServiceEventListener(const std::string& name);
- std::shared_ptr<Service::IEvent> GetServiceEventListener(
- const std::string& name);
-
- std::shared_ptr<Service> FindFromThisThread();
+ void Register(std::string name, std::shared_ptr<Service::IEvent> listener);
+ void Unregister(const std::string& name);
+ std::shared_ptr<Service::IEvent> Get(const std::string& name);
private:
ServiceManager();
~ServiceManager();
private:
- std::unordered_map<std::string, std::shared_ptr<Service::IEvent>>
- service_listeners_;
- std::unordered_map<std::string, std::shared_ptr<Service>> services_;
- std::unordered_map<std::shared_ptr<Service>, std::vector<IEvent*>> listeners_;
+ std::unordered_map<std::string, std::shared_ptr<Service::IEvent>> listeners_;
};
} // namespace tizen_base
*/
#include "service.h"
-#include "service_manager.h"
#include <algorithm>
#include <new>
void* user_data_ = nullptr;
};
-class EventHandler : public tizen_base::ServiceManager::IEvent {
- public:
- EventHandler(service_state_changed_cb callback, void* user_data)
- : callback_(callback), user_data_(user_data) {}
-
- virtual ~EventHandler() {}
-
- void OnServiceStateChanged(tizen_base::Service* service,
- tizen_base::Service::State state) override {
- if (callback_) {
- callback_(reinterpret_cast<service_h>(
- const_cast<tizen_base::Service*>(service)),
- static_cast<service_state_e>(state), user_data_);
- }
- }
-
- private:
- service_state_changed_cb callback_ = nullptr;
- void* user_data_ = nullptr;
-};
-
} // namespace
API int service_register(const char* name,
}
auto& inst = tizen_base::ServiceManager::GetInst();
- auto listener = inst.GetServiceEventListener(name);
+ auto listener = inst.Get(name);
if (listener != nullptr) return SERVICE_ERROR_ALREADY_EXIST;
try {
auto handle = std::make_shared<ServiceEvent>(callback, user_data);
- inst.RegisterServiceEventListener(name, std::move(handle));
+ inst.Register(name, std::move(handle));
} catch (const std::bad_alloc&) {
_E("Out of memory");
return SERVICE_ERROR_OUT_OF_MEMORY;
return SERVICE_ERROR_INVALID_PARAMETER;
}
- tizen_base::ServiceManager::GetInst().UnregisterServiceEventListener(name);
+ tizen_base::ServiceManager::GetInst().Unregister(name);
return SERVICE_ERROR_NONE;
}
*sender = handle->GetChannelSender();
return SERVICE_ERROR_NONE;
}
-
-API int service_manager_add_event_handler(service_state_changed_cb callback,
- void *user_data,
- service_manager_event_h *event_handler) {
- if (!callback || !event_handler) {
- _E("Invalid parameter");
- return SERVICE_ERROR_INVALID_PARAMETER;
- }
-
- auto* handle = new (std::nothrow) EventHandler(callback, user_data);
- if (!handle) {
- _E("Out of memory");
- return SERVICE_ERROR_OUT_OF_MEMORY;
- }
-
- auto& inst = tizen_base::ServiceManager::GetInst();
- auto service = inst.FindFromThisThread();
- if (service == nullptr) {
- _E("Failed to find service from this thread");
- return SERVICE_ERROR_INVALID_CONTEXT;
- }
-
- tizen_base::ServiceManager::GetInst().AddEventListener(service, handle);
- *event_handler = reinterpret_cast<service_manager_event_h>(handle);
- return SERVICE_ERROR_NONE;
-}
-
-API int service_manager_remove_event_handler(
- service_manager_event_h event_handler) {
- if (!event_handler) {
- _E("Invalid parameter");
- return SERVICE_ERROR_INVALID_PARAMETER;
- }
-
- auto* handle = reinterpret_cast<EventHandler*>(event_handler);
- auto& inst = tizen_base::ServiceManager::GetInst();
-
- auto service = inst.FindFromThisThread();
- if (service == nullptr) {
- _E("Failed to find service from this thread");
- return SERVICE_ERROR_INVALID_CONTEXT;
- }
-
- inst.RemoveEventListener(service, handle);
- delete handle;
- return SERVICE_ERROR_NONE;
-}
-
-API int service_manager_get_service(const char* name, service_h* service) {
- if (!name || !service) {
- _E("Invalid parameter");
- return SERVICE_ERROR_INVALID_PARAMETER;
- }
-
- auto& inst = tizen_base::ServiceManager::GetInst();
- if (!inst.Contains(name)) return SERVICE_ERROR_INVALID_PARAMETER;
-
- *service = reinterpret_cast<service_h>(inst.Get(name).get());
- return SERVICE_ERROR_NONE;
-}
callback_.message(sender.c_str(), envelope.GetHandle(), user_data_);
}
+ void OnServiceStateChanged(const tizen_base::Service* service,
+ tizen_base::Service::State state) {}
+
private:
service_loader_lifecycle_callback_s callback_;
void* user_data_;