feat: AM loader实现启动freedesktop类型应用

AM loader可以正常启动freedesktop类型应用了

Log: AM loader实现启动freedesktop类型应用
Task: https://pms.uniontech.com/task-view-108539.html
Influence: AM loader
Change-Id: If56835e638ca38ed53bcc7a0dddeca47e05cc8ba
This commit is contained in:
tanfeng 2022-05-25 11:46:28 +08:00
parent 5997b3a2a1
commit 38cf02a51f
8 changed files with 138 additions and 63 deletions

View File

@ -1,6 +1,6 @@
set(SYSTEMD_FILES set(SYSTEMD_FILES
org.deskspec.application.instance@.service org.desktopspec.application.instance@.service
org.deskspec.application.manager.service org.desktopspec.application.manager.service
) )
install(FILES ${SYSTEMD_FILES} DESTINATION lib/systemd/user/) install(FILES ${SYSTEMD_FILES} DESTINATION lib/systemd/user/)

View File

@ -3,6 +3,6 @@ Description=Deepin Application Manager service
[Service] [Service]
Type=DBus Type=DBus
BusName=org.deskspec.ApplicationManager BusName=org.desktopspec.ApplicationManager
ExecStart=/usr/bin/deepin-application-service ExecStart=/usr/bin/deepin-application-manager
Slice=services.slice Slice=services.slice

View File

@ -18,6 +18,10 @@
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <QString>
#include <QProcess>
#include <QDir>
#include "../modules/methods/basic.h" #include "../modules/methods/basic.h"
#include "../modules/methods/instance.hpp" #include "../modules/methods/instance.hpp"
#include "../modules/methods/quit.hpp" #include "../modules/methods/quit.hpp"
@ -40,25 +44,16 @@ struct App {
std::string id; std::string id;
}; };
static App parseApp(const std::string& app) static App parseApp(const QString& app)
{ {
std::vector<std::string> strings; QStringList values = app.split('/', QString::SkipEmptyParts);
std::istringstream stream(app); qInfo() << "app:" << app << ", values size:" << values.size();
std::string s;
while (getline(stream, s, '/')) {
if (s.empty()) {
continue;
}
strings.push_back(s);
}
App result; App result;
if (strings.size() == 3) { if (values.size() == 3) {
result.prefix = strings[0]; result.prefix = values.at(0).toStdString();
result.type = strings[1]; result.type = values.at(1).toStdString();
result.id = strings[2]; result.id = values.at(2).toStdString();
} }
return result; return result;
} }
@ -77,12 +72,51 @@ void sig_handler(int num)
} }
} }
int runLinglong(void* _arg) // TODO: startManager合并流程
int childFreedesktop(Methods::Task* task, std::string path)
{ {
return 0; prctl(PR_SET_PDEATHSIG, SIGKILL);
prctl(PR_SET_PDEATHSIG, SIGTERM);
prctl(PR_SET_PDEATHSIG, SIGHUP);
DesktopDeconstruction dd(path);
dd.beginGroup("Desktop Entry");
std::cout << dd.value<std::string>("Exec") << std::endl;
QStringList envs;
for (auto it = task->environments.begin(); it != task->environments.end(); ++it) {
envs.append(it.key() + "=" + it.value());
}
QStringList exeArgs;
exeArgs << QString::fromStdString(dd.value<std::string>("Exec")).split(" ");
QString exec = exeArgs[0];
exeArgs.removeAt(0);
pid_t pid = fork();
if (pid == -1) {
perror("fork()");
return -1;
}
if (pid == 0) {
// 子进程
QProcess process;
qInfo() << "exec:" << exec;
qInfo() << "exeArgs:" << exeArgs;
process.setWorkingDirectory(QDir::homePath());
process.setEnvironment(envs);
process.start(exec, exeArgs);
process.waitForFinished(-1);
process.close();
qInfo() << "process finish";
exit(0);
}
return pid;
} }
int child(Methods::Task* task, std::string path) int childLinglong(Methods::Task* task, std::string path)
{ {
prctl(PR_SET_PDEATHSIG, SIGKILL); prctl(PR_SET_PDEATHSIG, SIGKILL);
prctl(PR_SET_PDEATHSIG, SIGTERM); prctl(PR_SET_PDEATHSIG, SIGTERM);
@ -179,6 +213,12 @@ int child(Methods::Task* task, std::string path)
return pid; return pid;
} }
int childAndroid(Methods::Task* task, std::string path)
{
// TODO
return 0;
}
#define DAM_TASK_HASH "DAM_TASK_HASH" #define DAM_TASK_HASH "DAM_TASK_HASH"
#define DAM_TASK_TYPE "DAM_TASK_TYPE" #define DAM_TASK_TYPE "DAM_TASK_TYPE"
@ -203,14 +243,14 @@ int main(int argc, char* argv[])
// 初始化应用注册信息 // 初始化应用注册信息
QByteArray registerArray; QByteArray registerArray;
Methods::Registe registe; Methods::Registe registe;
registe.id = dam_task_type; registe.id = dam_task_type;
registe.hash = dam_task_hash; registe.hash = dam_task_hash;
Methods::toJson(registerArray, registe); Methods::toJson(registerArray, registe);
// 向AM注册应用信息进行校验 // 向AM注册应用信息进行校验
Methods::Registe registe_result; Methods::Registe registe_result;
registe_result.state = false; registe_result.state = false;
QByteArray result = client.get(registerArray); QByteArray result = client.get(registerArray);
if (!result.isEmpty()) { if (!result.isEmpty()) {
Methods::fromJson(result, registe_result); Methods::fromJson(result, registe_result);
} }
@ -228,50 +268,66 @@ int main(int argc, char* argv[])
result = client.get(instanceArray); result = client.get(instanceArray);
Methods::Task task; Methods::Task task;
Methods::fromJson(result, task); // fromJson TODO 数据解析异常 Methods::fromJson(result, task); // fromJson TODO 数据解析异常
qWarning() << "[result] " << result; qInfo() << "[Task] " << result;
// 校验task内容 // 校验task内容
App app = parseApp(task.runId.toStdString()); App app = parseApp(task.runId);
qInfo() << "[App] "
<< "prefix:" << QString::fromStdString(app.prefix)
<< "type:" << QString::fromStdString(app.type)
<< "id:" << QString::fromStdString(app.id);
if (task.id.isEmpty() || app.id.empty() || app.type.empty() || app.prefix.empty()) { if (task.id.isEmpty() || app.id.empty() || app.type.empty() || app.prefix.empty()) {
std::cout << "get task error" << std::endl; std::cout << "get task error" << std::endl;
return -4; return -4;
} }
if (app.prefix != "freedesktop"
std::string path{ "/usr/share/applications/" + app.id + ".desktop" }; && app.prefix != "linglong"
if (app.type == "user") { && app.prefix != "android") {
struct passwd* user = getpwuid(getuid()); qWarning() << "error app prefix :" << QString::fromStdString(app.type);
path = std::string(user->pw_dir) + "/.local/share/applications/" + app.id + ".desktop"; return -1;
} }
pthread_attr_t attr; pthread_attr_t attr;
size_t stack_size; size_t stack_size;
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stack_size); pthread_attr_getstacksize(&attr, &stack_size);
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
/* 先将SIGCHLD信号阻塞 保证在子进程结束前设置父进程的捕捉函数 */ /* 先将SIGCHLD信号阻塞 保证在子进程结束前设置父进程的捕捉函数 */
sigset_t nmask, omask; sigset_t nmask, omask;
sigemptyset(&nmask); // sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD); // sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask); // sigprocmask(SIG_BLOCK, &nmask, &omask);
//char* stack = (char*) malloc(stack_size); //char* stack = (char*) malloc(stack_size);
//pid_t pid = clone(child, stack + stack_size, CLONE_NEWPID | SIGCHLD, static_cast<void*>(&task)); //pid_t pid = clone(child, stack + stack_size, CLONE_NEWPID | SIGCHLD, static_cast<void*>(&task));
pid_t pid = child(&task, path); pid_t pid = -1;
if (app.prefix == "freedesktop") {
pid = childFreedesktop(&task, task.filePath.toStdString());
} else if (app.prefix == "linglong") {
pid = childLinglong(&task, task.filePath.toStdString());
} else if (app.prefix == "android") {
pid = childAndroid(&task, task.filePath.toStdString());
} else {
qWarning() << "error app prefix:" << QString::fromStdString(app.prefix);
}
// TODO: 启动线程,创建新的连接去接受服务器的消息 // TODO: 启动线程,创建新的连接去接受服务器的消息
// TODO:信号处理有问题
/* 设置捕捉函数 */ /* 设置捕捉函数 */
struct sigaction sig; // struct sigaction sig;
sig.sa_handler = sig_handler; // sig.sa_handler = sig_handler;
sigemptyset(&sig.sa_mask); // sigemptyset(&sig.sa_mask);
sig.sa_flags = 0; // sig.sa_flags = 0;
sigaction(SIGCHLD, &sig, NULL); // sigaction(SIGCHLD, &sig, NULL);
/* 然后再unblock */ /* 然后再unblock */
sigdelset(&omask, SIGCHLD); // sigdelset(&omask, SIGCHLD);
sigprocmask(SIG_SETMASK, &omask, NULL); // sigprocmask(SIG_SETMASK, &omask, NULL);
int exitCode; int exitCode;
waitpid(pid, &exitCode, 0); waitpid(pid, &exitCode, 0);
qInfo() << "app exitCode:" << exitCode;
Methods::Quit quit; Methods::Quit quit;
quit.code = exitCode; quit.code = exitCode;

View File

@ -18,6 +18,7 @@ namespace Methods
QString runId; QString runId;
QString type{"task"}; QString type{"task"};
QString date; QString date;
QString filePath;
QList<QString> arguments; QList<QString> arguments;
QMap<QString, QString> environments; QMap<QString, QString> environments;
}; };
@ -36,7 +37,8 @@ namespace Methods
QJsonObject obj = { QJsonObject obj = {
{"type", task.type}, {"type", task.type},
{"id", task.id}, {"id", task.id},
{"run_id", task.runId}, {"runId", task.runId},
{"filePath", task.filePath},
{"date", task.date}, {"date", task.date},
{"arguments", argArray}, {"arguments", argArray},
{"environments", QJsonObject::fromVariantMap(envsMap)} {"environments", QJsonObject::fromVariantMap(envsMap)}
@ -51,24 +53,30 @@ namespace Methods
qWarning() << "fromJson task failed"; qWarning() << "fromJson task failed";
return; return;
} }
QJsonObject obj = doc.object(); QJsonObject obj = doc.object();
if (!obj.contains("id") || !obj.contains("runId") || !obj.contains("date") \ if (obj.contains("id")) {
|| !obj.contains("arguments") || !obj.contains("environments")) { task.id = obj.value("id").toString();
qWarning() << "id runId date arguments environments not exist in task array"; }
return; if (obj.contains("runId")) {
task.runId = obj.value("runId").toString();
}
if (obj.contains("filePath")) {
task.filePath = obj.value("filePath").toString();
}
if (obj.contains("date")) {
task.date = obj.value("date").toString();
} }
task.id = obj.value("id").toString(); if (obj.contains("arguments")) {
task.runId = obj.value("runId").toString(); for (auto arg : obj.value("arguments").toArray()) {
task.date = obj.value("date").toString(); task.arguments.append(arg.toString());
for (auto arg : obj.value("arguments").toArray()) { }
task.arguments.append(arg.toString());
} }
if (obj.contains("environments")) {
QVariantMap envsMap = obj.value("environments").toObject().toVariantMap(); QVariantMap envsMap = obj.value("environments").toObject().toVariantMap();
for (auto it = envsMap.constBegin(); it != envsMap.constEnd(); ++it) { for (auto it = envsMap.constBegin(); it != envsMap.constEnd(); ++it) {
task.environments.insert(it.key(), it.value().toString()); task.environments.insert(it.key(), it.value().toString());
}
} }
} }
} // namespace Methods } // namespace Methods

View File

@ -68,8 +68,9 @@ public:
emit q_ptr->taskFinished(p->exitCode()); emit q_ptr->taskFinished(p->exitCode());
} }
#else #else
qInfo() << "app manager load service:" << QString("org.desktopspec.application.instance@%1.service").arg(m_id);
QDBusInterface systemd("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager"); QDBusInterface systemd("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager");
QDBusReply<void> reply = systemd.call("StartUnit", QString("org.deskspec.application.instance@%1.service").arg(m_id), "replace-irreversibly"); QDBusReply<void> reply = systemd.call("StartUnit", QString("org.desktopspec.application.instance@%1.service").arg(m_id), "replace-irreversibly");
if (!reply.isValid()) { if (!reply.isValid()) {
qInfo() << reply.error(); qInfo() << reply.error();
q_ptr->deleteLater(); q_ptr->deleteLater();
@ -82,7 +83,7 @@ public:
#ifdef LOADER_PATH #ifdef LOADER_PATH
#else #else
QDBusInterface systemd("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager"); QDBusInterface systemd("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager");
qInfo() << systemd.call("StopUnit", QString("org.deskspec.application.instance@%1.service").arg(m_id), "replace-irreversibly"); qInfo() << systemd.call("StopUnit", QString("org.desktopspec.application.instance@%1.service").arg(m_id), "replace-irreversibly");
#endif #endif
} }
@ -146,6 +147,7 @@ Methods::Task ApplicationInstance::taskInfo() const
Methods::Task task; Methods::Task task;
task.id = d->m_id; task.id = d->m_id;
task.runId = d->application->id(); task.runId = d->application->id();
task.filePath = d->application->filePath();
task.date = QString::number(startuptime()); task.date = QString::number(startuptime());
task.arguments = m_files; task.arguments = m_files;

View File

@ -90,8 +90,11 @@ void ApplicationManagerPrivate::recvClientData(int socket, const std::vector<cha
result.state = false; result.state = false;
// std::lock_guard<std::mutex> lock(task_mutex); // std::lock_guard<std::mutex> lock(task_mutex);
for (auto it = tasks.begin(); it != tasks.end(); ++it) { for (auto it = tasks.begin(); it != tasks.end(); ++it) {
result.state = true; if (registe.hash == QString::fromStdString(it->first)) {
result.hash = QString::fromStdString(it->first); result.state = true;
result.hash = registe.hash;
break;
}
} }
Methods::toJson(tmpArray, result); Methods::toJson(tmpArray, result);
write(socket, tmpArray.toStdString()); write(socket, tmpArray.toStdString());
@ -199,6 +202,7 @@ QList<QDBusObjectPath> ApplicationManager::GetInstances(const QString &id)
*/ */
QDBusObjectPath ApplicationManager::Launch(const QString &id, QStringList files) QDBusObjectPath ApplicationManager::Launch(const QString &id, QStringList files)
{ {
qInfo() << "Launch " << id;
Q_D(ApplicationManager); Q_D(ApplicationManager);
if (!d->checkDMsgUid()) if (!d->checkDMsgUid())
return {}; return {};

View File

@ -90,6 +90,11 @@ int main(int argc, char *argv[])
QDBusConnection::sessionBus().registerObject(app->path().path(), "org.desktopspec.Application", app.get()); QDBusConnection::sessionBus().registerObject(app->path().path(), "org.desktopspec.Application", app.get());
} }
for (const QSharedPointer<Application> &app : apps) {
qInfo() << "appId - " << app->id();
qInfo() << "appFilePath - " << app->filePath();
}
ApplicationManager::instance()->addApplication(apps); ApplicationManager::instance()->addApplication(apps);
ApplicationManager::instance()->launchAutostartApps(); ApplicationManager::instance()->launchAutostartApps();