--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "db_change_observer.hh"
+
+#include <tzplatform_config.h>
+
+#include <utility>
+
+#include "utils/logging.hh"
+
+#include "pkgmgrinfo_debug.h"
+#include "pkgmgr-info.h"
+
+#undef LOG_TAG
+#define LOG_TAG "PKGMGR_INFO"
+
+namespace {
+
+uid_t globaluser_uid = -1;
+
+uid_t GetGlobalUID() {
+ if (globaluser_uid == (uid_t)-1)
+ globaluser_uid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
+
+ return globaluser_uid;
+}
+
+} // namespace
+
+namespace pkgmgr_common {
+
+DbChangeObserver& DbChangeObserver::GetInst() {
+ static DbChangeObserver inst;
+
+ return inst;
+}
+
+gboolean DbChangeObserver::OnReceiveEvent(GIOChannel* channel, GIOCondition cond,
+ gpointer user_data) {
+ LOG(WARNING) << "db changed event occured";
+ char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
+ auto db_change = reinterpret_cast<DbChangeObserver*>(user_data);
+ int fd = g_io_channel_unix_get_fd(channel);
+
+ while(read(fd, buf, sizeof(buf)) > 0);
+
+ std::unique_lock<std::shared_mutex> u(db_change->lock_);
+ if (!db_change->changed_) {
+ db_change->changed_ = true;
+ if (db_change->listener_)
+ db_change->listener_->OnDbChanged();
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+DbChangeObserver::DbChangeObserver() {
+ std::unique_lock<std::shared_mutex> u(lock_);
+ SetGlobalParserDbPath();
+}
+
+DbChangeObserver::~DbChangeObserver() {
+ std::unique_lock<std::shared_mutex> u(lock_);
+ Dispose();
+}
+
+bool DbChangeObserver::Listen() {
+ std::unique_lock<std::shared_mutex> u(lock_);
+
+ if (!disposed_)
+ return true;
+
+ if (global_parser_db_path_.empty()) {
+ if (!SetGlobalParserDbPath()) {
+ LOG(ERROR) << "Fail to Set GlobalParserDbPath";
+ return false;
+ }
+ }
+
+ disposed_ = false;
+
+ fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+ if (fd_ == -1) {
+ LOG(ERROR) << "Failed to inotify_init. errno: " << errno;
+ Dispose();
+ return false;
+ }
+
+ wd_ = inotify_add_watch(fd_, global_parser_db_path_.c_str(), IN_MODIFY);
+ if (wd_ == -1) {
+ LOG(ERROR) << "Failed to inotify_add_watch. errno: " << errno;
+ Dispose();
+ return false;
+ }
+
+ channel_ = g_io_channel_unix_new(fd_);
+ if (channel_ == nullptr) {
+ LOG(ERROR) << "Failed to create GIO channel";
+ Dispose();
+ return false;
+ }
+
+ tag_ = g_io_add_watch(channel_, (GIOCondition)(G_IO_IN), OnReceiveEvent, this);
+ if (tag_ == 0) {
+ LOG(ERROR) << "Failed to add watch";
+ Dispose();
+ return false;
+ }
+
+ changed_ = false;
+ disposed_ = false;
+
+ return true;
+}
+
+void DbChangeObserver::StopListening() {
+ std::unique_lock<std::shared_mutex> u(lock_);
+
+ Dispose();
+}
+
+bool DbChangeObserver::IsChanged() {
+ std::shared_lock<std::shared_mutex> s(lock_);
+ return changed_;
+}
+
+void DbChangeObserver::SetChanged(bool changed) {
+ std::unique_lock<std::shared_mutex>s (lock_);
+ changed_ = changed;
+}
+
+void DbChangeObserver::Dispose() {
+ if (disposed_)
+ return;
+
+ if (tag_) {
+ g_source_remove(tag_);
+ tag_ = 0;
+ }
+
+ if (channel_ != nullptr) {
+ g_io_channel_unref(channel_);
+ channel_ = nullptr;
+ }
+
+ if (wd_ > 0) {
+ inotify_rm_watch(fd_, wd_);
+ wd_ = 0;
+ }
+
+ if (fd_ > 0) {
+ close(fd_);
+ fd_ = 0;
+ }
+
+ disposed_ = true;
+}
+
+bool DbChangeObserver::GetDisposed() {
+ std::shared_lock<std::shared_mutex> s(lock_);
+
+ return disposed_;
+}
+
+bool DbChangeObserver::SetGlobalParserDbPath() {
+ char* tmp_path = getUserPkgParserDBPathUID(GetGlobalUID());
+ if (tmp_path == nullptr) {
+ LOG(ERROR) << "Fail to global parser db";
+ return false;
+ }
+ global_parser_db_path_ = tmp_path;
+ free(tmp_path);
+ return true;
+}
+
+void DbChangeObserver::RegisterEvent(IEvent* listener) {
+ std::unique_lock<std::shared_mutex> s(lock_);
+ listener_ = listener;
+}
+
+void DbChangeObserver::UnRegisterEvent() {
+ std::unique_lock<std::shared_mutex> s(lock_);
+ listener_ = nullptr;
+}
+
+} // namespace pkgmgr_common
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include <gio/gio.h>
+#include <glib.h>
+#include <sys/inotify.h>
+
+#include <string>
+#include <shared_mutex>
+
+#ifndef COMMON_DB_CHANGE_OBSERVER_HH_
+#define COMMON_DB_CHANGE_OBSERVER_HH_
+
+namespace pkgmgr_common {
+
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+class EXPORT_API DbChangeObserver {
+ public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnDbChanged() = 0;
+ };
+ static DbChangeObserver& GetInst();
+ bool Listen();
+ void StopListening();
+ bool IsChanged();
+ void SetChanged(bool changed);
+ void RegisterEvent(IEvent* listener);
+ void UnRegisterEvent();
+ bool GetDisposed();
+
+ private:
+ DbChangeObserver();
+ ~DbChangeObserver();
+
+ int fd_ = 0;
+ int wd_ = 0;
+ GIOChannel* channel_ = nullptr;
+ int tag_ = 0;
+ bool changed_ = false;
+ bool disposed_ = true;
+ std::shared_mutex lock_;
+ std::string global_parser_db_path_;
+ IEvent* listener_ = nullptr;
+
+ void Dispose();
+ bool SetGlobalParserDbPath();
+ static gboolean OnReceiveEvent(GIOChannel* channel, GIOCondition cond,
+ gpointer user_data);
+};
+
+} // namespace pkgmgr_common
+
+#endif // COMMON_DB_CHANGE_OBSERVER_HH_
return convertArray[type];
}
+bool IsDbWriteRequest(ReqType type) {
+ if (type == pkgmgr_common::ReqType::SET_PKG_INFO ||
+ type == pkgmgr_common::ReqType::SET_CERT_INFO ||
+ type == pkgmgr_common::ReqType::WRITE_QUERY)
+ return true;
+
+ return false;
+}
+
} // namespace pkgmgr_common
EXPORT_API const char* ReqTypeToString(ReqType type);
+EXPORT_API bool IsDbWriteRequest(ReqType type);
+
} // namespace pkgmgr_common
#endif // COMMON_REQUEST_TYPE_HH_
sid_ = g_unix_fd_add(server_->GetFd(), condition, OnReceiveRequest, this);
default_uid_ = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
pkgmgr_common::SystemLocale::GetInst().RegisterEvent(this);
+ pkgmgr_common::DbChangeObserver::GetInst().Listen();
+ pkgmgr_common::DbChangeObserver::GetInst().RegisterEvent(this);
thread_pool_->SetLocale(pkgmgr_common::SystemLocale::GetInst().Get());
if (CacheFlag::SetPreparing())
Runner::~Runner() {
g_source_remove(sid_);
+ if (timer_ > 0)
+ g_source_remove(timer_);
CynaraChecker::GetInst().Fini();
pkgmgr_common::SystemLocale::GetInst().UnRegisterEvent();
+ pkgmgr_common::DbChangeObserver::GetInst().UnRegisterEvent();
}
int Runner::OnReceiveRequest(int fd, GIOCondition cond, void* user_data) {
QueueRequest(std::make_shared<RemoveAllCacheRequest>(default_uid_));
}
+void Runner::OnDbChanged() {
+ QueueRequest(std::make_shared<RemoveAllCacheRequest>(default_uid_));
+ SetCreateCacheTimer();
+}
+
bool Runner::QueueRequest(std::shared_ptr<PkgRequest> req) {
thread_pool_->PushQueue(std::move(req));
return true;
void Runner::OnCreateCacheDone(bool success) {
static bool ready = false;
- if (success && !ready) {
+ if (ready)
+ return;
+
+ if (success) {
ready = true;
LOG(WARNING) << "pkginfo-server is ready";
g_idle_add(
return G_SOURCE_REMOVE;
},
nullptr);
+ } else {
+ LOG(WARNING) << "Fail to create cache";
+ SetCreateCacheTimer();
}
}
LOG(ERROR) << "Fail to register cpu inheritance destination ret : " << ret;
}
+void Runner::SetCreateCacheTimer() {
+ if (timer_ > 0)
+ g_source_remove(timer_);
+
+ timer_ = g_timeout_add_seconds_full(G_PRIORITY_LOW, 10,
+ RetryCreateCache, this, NULL);
+}
+
+gboolean Runner::RetryCreateCache(void* data) {
+ LOG(WARNING) << "Retry to create cache";
+ auto* runner = static_cast<Runner*>(data);
+ runner->timer_ = 0;
+
+ pkgmgr_common::DbChangeObserver::GetInst().SetChanged(false);
+ pkgmgr_common::DbChangeObserver::GetInst().Listen();
+
+ if (CacheFlag::SetPreparing()) {
+ runner->QueueRequest(
+ std::make_shared<CreateCacheRequest>(runner->default_uid_, runner));
+ }
+ return G_SOURCE_REMOVE;
+}
+
} // namespace pkgmgr_server
#include <unordered_map>
#include "create_cache_request.hh"
+#include "db_change_observer.hh"
#include "server_socket.hh"
#include "system_locale.hh"
#include "worker_thread.hh"
#endif
class EXPORT_API Runner : public pkgmgr_common::SystemLocale::IEvent,
+ public pkgmgr_common::DbChangeObserver::IEvent,
public CreateCacheRequest::IEvent {
public:
explicit Runner(unsigned int thread_num);
bool QueueRequest(std::shared_ptr<PkgRequest> req);
void OnChanged(const std::string& locale) override;
+ void OnDbChanged() override;
void OnCreateCacheDone(bool success) override;
private:
static int OnReceiveRequest(int fd, GIOCondition cond, void* user_data);
bool QueueRequest(int client_fd);
void SetCPUInheritance();
+ void SetCreateCacheTimer();
+ static gboolean RetryCreateCache(void* data);
private:
int sid_;
uid_t default_uid_;
std::unique_ptr<pkgmgr_common::socket::ServerSocket> server_;
std::unique_ptr<WorkerThread> thread_pool_;
+ guint timer_ = 0;
};
} // namespace pkgmgr_server
#include "abstract_parcelable.hh"
#include "cynara_checker.hh"
+#include "db_change_observer.hh"
#include "request_handler_factory.hh"
#include "server/database/db_handle_provider.hh"
#include "server/database/update_pending_cache_handler.hh"
}
pkgmgr_common::ReqType type = req->GetRequestType();
+ if (pkgmgr_common::IsDbWriteRequest(type))
+ StopDbChangeListening();
std::vector<std::string> privileges = GetPrivileges(type);
if (!CynaraChecker::GetInst().CheckPrivilege(this, req, privileges))
continue;
req->SendData(p);
}
+void WorkerThread::StopDbChangeListening() {
+ auto& db_observer = pkgmgr_common::DbChangeObserver::GetInst();
+
+ if (db_observer.GetDisposed())
+ return;
+
+ LOG(WARNING) << "Try stop listening db change";
+ db_observer.StopListening();
+}
+
} // namespace pkgmgr_server
void Run();
void SendError(const std::shared_ptr<PkgRequest>& req);
void SetMemoryTrimTimer();
+ void StopDbChangeListening();
static gboolean TrimMemory(void* data);
std::shared_ptr<PkgRequest> PopQueue();