*/
#include "worker_thread.hh"
+
#include <sqlite3.h>
+#include <sys/types.h>
#include <malloc.h>
-#include "pkgmgrinfo_debug.h"
-#include "get_appinfo_request_handler.hh"
-#include "get_cert_request_handler.hh"
-#include "get_pkginfo_request_handler.hh"
-#include "get_depinfo_request_handler.hh"
-#include "query_request_handler.hh"
-#include "set_cert_request_handler.hh"
-#include "set_pkginfo_request_handler.hh"
+#include <tzplatform_config.h>
+
#include "abstract_parcelable.hh"
-#include "command_request_handler.hh"
+#include "cynara_checker.hh"
+#include "request_handler_factory.hh"
+#include "server/database/db_handle_provider.hh"
+#include "server/database/remove_cache_db_handler.hh"
+#include "utils/logging.hh"
+
+#include "pkgmgrinfo_debug.h"
#ifdef LOG_TAG
#undef LOG_TAG
#define SQLITE_ENABLE_MEMORY_MANAGEMENT
#endif
+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;
+}
+
+uid_t ConvertUID(uid_t uid) {
+ if (uid < REGULAR_USER)
+ return GetGlobalUID();
+ else
+ return uid;
+}
+
+const char PRIVILEGE_PACKAGE_MANAGER_ADMIN[] =
+ "http://tizen.org/privilege/packagemanager.admin";
+
+std::vector<std::string> GetPrivileges(pkgmgr_common::ReqType type) {
+ std::vector<std::string> ret;
+ if (type == pkgmgr_common::SET_CERT_INFO)
+ ret.emplace_back(PRIVILEGE_PACKAGE_MANAGER_ADMIN);
+ else if (type == pkgmgr_common::SET_PKG_INFO)
+ ret.emplace_back(PRIVILEGE_PACKAGE_MANAGER_ADMIN);
+
+ return ret;
+}
+
+} // namespace
+
namespace pkgmgr_server {
WorkerThread::WorkerThread(unsigned int num) : stop_all_(false) {
for (unsigned int i = 0; i < num; ++i)
threads_.emplace_back([this]() -> void { this->Run(); });
- LOGD("%d Worker threads are created", num);
+ LOG(DEBUG) << num << " Worker threads are created";
}
WorkerThread::~WorkerThread() {
stop_all_ = true;
cv_.notify_all();
- for (auto& t : threads_) t.join();
+ for (auto& t : threads_)
+ t.join();
}
bool WorkerThread::PushQueue(std::shared_ptr<PkgRequest> req) {
return true;
}
+std::shared_ptr<PkgRequest> WorkerThread::PopQueue() {
+ SetMemoryTrimTimer();
+ std::unique_lock<std::mutex> u(lock_);
+ cv_.wait(u, [this] { return !this->queue_.empty() || stop_all_; });
+ if (stop_all_ && queue_.empty())
+ return nullptr;
+
+ auto req = queue_.front();
+ queue_.pop();
+ return req;
+}
+
void WorkerThread::Run() {
- std::unique_ptr<request_handler::AbstractRequestHandler>
- handler[pkgmgr_common::ReqType::MAX];
- handler[pkgmgr_common::ReqType::GET_PKG_INFO].reset(
- new request_handler::GetPkginfoRequestHandler());
- handler[pkgmgr_common::ReqType::GET_APP_INFO].reset(
- new request_handler::GetAppinfoRequestHandler());
- handler[pkgmgr_common::ReqType::SET_PKG_INFO].reset(
- new request_handler::SetPkginfoRequestHandler());
- handler[pkgmgr_common::ReqType::SET_CERT_INFO].reset(
- new request_handler::SetCertRequestHandler());
- handler[pkgmgr_common::ReqType::GET_CERT_INFO].reset(
- new request_handler::GetCertRequestHandler());
- handler[pkgmgr_common::ReqType::GET_PKG_DEP_INFO].reset(
- new request_handler::GetDepinfoRequestHandler());
- handler[pkgmgr_common::ReqType::QUERY].reset(
- new request_handler::QueryRequestHandler());
- handler[pkgmgr_common::ReqType::COMMAND].reset(
- new request_handler::CommandRequestHandler());
-
- LOGD("Initialize request handlers");
+ RequestHandlerFactory factory;
+ LOG(DEBUG) << "Initialize request handlers";
while (true) {
- std::shared_ptr<PkgRequest> req;
- {
- std::unique_lock<std::mutex> u(lock_);
- cv_.wait(u, [this] { return !this->queue_.empty() || stop_all_; });
- if (stop_all_ && queue_.empty()) return;
- req = PopQueue();
+ std::shared_ptr<PkgRequest> req = PopQueue();
+ if (req == nullptr)
+ return;
+
+ if (!req->GetPrivilegeChecked()) {
+ if (!req->ReceiveData()) {
+ LOG(ERROR) << "Fail to receive data";
+ continue;
+ }
+
+ pkgmgr_common::ReqType type = req->GetRequestType();
+ std::vector<std::string> privileges = GetPrivileges(type);
+ if (!CynaraChecker::GetInst().CheckPrivilege(this, req, privileges))
+ continue;
}
- if (req->ReceiveData() == false) {
- LOGE("Failed to ReceiveData");
- continue;
- }
- pkgmgr_common::ReqType type = req->GetRequestType();
- LOGD("Request type(%d), pid(%d)",
- static_cast<int>(type), req->GetSenderPID());
- if (type <= pkgmgr_common::ReqType::REQ_TYPE_NONE
- || type >= pkgmgr_common::ReqType::MAX) {
- LOGE("Request type is invalid (%d)", static_cast<int>(type));
-
- pkgmgr_common::parcel::AbstractParcelable parcelable(
- 0, pkgmgr_common::parcel::ParcelableType::Unknown, PMINFO_R_ERROR);
- tizen_base::Parcel p;
- p.WriteParcelable(parcelable);
- std::vector<uint8_t> raw = p.GetRaw();
- req->SendData(&raw[0], raw.size());
+ auto type = req->GetRequestType();
+ LOG(WARNING) << "Request type: " << pkgmgr_common::ReqTypeToString(type)
+ << " pid: " << req->GetSenderPID() << " tid: " << req->GetSenderTID();
+ auto handler = factory.GetRequestHandler(type);
+ if (handler == nullptr)
continue;
- }
try {
- handler[type]->SetPID(req->GetSenderPID());
- if (!handler[type]->HandleRequest(req->GetData(), req->GetSize(),
- locale_.GetObject()))
- LOGE("Failed to handle request");
+ handler->PreExec();
+ handler->SetUID(ConvertUID(req->GetSenderUID()));
+ handler->SetPID(req->GetSenderPID());
+ if (!handler->HandleRequest(req->DetachData(), req->GetSize(),
+ locale_.GetObject()))
+ LOG(ERROR) << "Failed to handle request";
+
+ if (req->SendData(handler->ExtractResult()) == false)
+ LOG(ERROR) << "Failed to send response pid: " << req->GetSenderPID();
+ else
+ LOG(WARNING) << "Success response pid: " << req->GetSenderPID()
+ << " tid: " << req->GetSenderTID();
} catch (const std::exception& err) {
- LOGE("Exception occurred (%s)", err.what());
- pkgmgr_common::parcel::AbstractParcelable parcelable(
- 0, pkgmgr_common::parcel::ParcelableType::Unknown, PMINFO_R_ERROR);
- tizen_base::Parcel p;
- p.WriteParcelable(parcelable);
- std::vector<uint8_t> raw = p.GetRaw();
- req->SendData(&raw[0], raw.size());
- continue;
+ LOG(ERROR) << "Exception occurred: " << err.what()
+ << ", pid: " << req->GetSenderPID();
+ SendError(req);
} catch (...) {
- LOGE("Exception occurred");
- pkgmgr_common::parcel::AbstractParcelable parcelable(
- 0, pkgmgr_common::parcel::ParcelableType::Unknown, PMINFO_R_ERROR);
- tizen_base::Parcel p;
- p.WriteParcelable(parcelable);
- std::vector<uint8_t> raw = p.GetRaw();
- req->SendData(&raw[0], raw.size());
- continue;
+ LOG(ERROR) << "Exception occurred pid: " << req->GetSenderPID();
+ SendError(req);
}
- std::vector<uint8_t> result_data = handler[type]->ExtractResult();
- req->SendData(result_data.data(), result_data.size());
+ handler->PostExec();
}
}
void WorkerThread::SetMemoryTrimTimer() {
- static guint timer = 0;
- if (timer > 0)
- g_source_remove(timer);
+ std::lock_guard<std::recursive_mutex> lock(mutex_);
+ if (timer_ > 0)
+ g_source_remove(timer_);
- timer = g_timeout_add(3000, TrimMemory, &timer);
+ timer_ = g_timeout_add_seconds_full(G_PRIORITY_LOW, 10,
+ TrimMemory, this, NULL);
}
gboolean WorkerThread::TrimMemory(void* data) {
- LOGD("Trim memory");
- guint* timer = static_cast<guint*>(data);
- sqlite3_release_memory(-1);
- malloc_trim(0);
- *timer = 0;
+ LOG(DEBUG) << "Trim memory";
+ auto* h = static_cast<WorkerThread*>(data);
+ {
+ std::lock_guard<std::recursive_mutex> lock(h->mutex_);
+ h->timer_ = 0;
+ }
- return false;
-}
+ auto crashed_writer_pids =
+ database::DBHandleProvider::CrashedWriteRequestPIDs();
+ if (!crashed_writer_pids.empty()) {
+ database::RemoveCacheDBHandler db(getuid(), std::move(crashed_writer_pids));
+ db.SetLocale(h->locale_.GetObject());
+ db.Execute();
+ }
-std::shared_ptr<PkgRequest> WorkerThread::PopQueue() {
- SetMemoryTrimTimer();
- auto req = queue_.front();
- queue_.pop();
- return req;
+ sqlite3_release_memory(-1);
+ malloc_trim(0);
+ return G_SOURCE_REMOVE;
}
void WorkerThread::SetLocale(std::string locale) {
- LOGD("Change locale (%s) -> (%s)", locale_.GetObject().c_str(),
- locale.c_str());
+ LOG(DEBUG) << "Change locale : " << locale_.GetObject()
+ << " -> " << locale;
locale_.SetObject(std::move(locale));
}
+void WorkerThread::SendError(const std::shared_ptr<PkgRequest>& req) {
+ pkgmgr_common::parcel::AbstractParcelable parcelable(
+ 0, pkgmgr_common::parcel::ParcelableType::Unknown, PMINFO_R_ERROR);
+ tizen_base::Parcel p;
+ p.WriteParcelable(parcelable);
+ req->SendData(p);
+}
+
} // namespace pkgmgr_server