1 /*
2     SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
3 
4     SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 #include "extended_process_list.h"
7 #include "kcoreaddons_version.h"
8 
9 #include <KLocalizedString>
10 #include <KPluginFactory>
11 #include <KPluginLoader>
12 #include <KPluginMetaData>
13 #include <KUser>
14 
15 #include "process.h"
16 #include "process_attribute.h"
17 #include "process_data_provider.h"
18 #include "processcore_debug.h"
19 
20 using namespace KSysGuard;
21 
22 class Q_DECL_HIDDEN ExtendedProcesses::Private
23 {
24 public:
25     Private(ExtendedProcesses *q);
26     void loadPlugins();
27 
28     ExtendedProcesses *q;
29     QVector<ProcessAttribute *> m_coreAttributes;
30     QVector<ProcessDataProvider *> m_providers;
31     QHash<K_UID, KUser> m_userCache;
32 };
33 
34 enum GroupPolicy { Accumulate, Average, ForwardFirstEntry };
35 
36 template<class T>
37 class ProcessSensor : public KSysGuard::ProcessAttribute
38 {
39 public:
ProcessSensor(ExtendedProcesses * parent,const QString & id,const QString & name,std::function<T (KSysGuard::Process *)> extractFunc,KSysGuard::Process::Change changeFlag=KSysGuard::Process::Nothing,GroupPolicy groupPolicy=Accumulate)40     ProcessSensor(ExtendedProcesses *parent,
41                   const QString &id,
42                   const QString &name,
43                   std::function<T(KSysGuard::Process *)> extractFunc,
44                   KSysGuard::Process::Change changeFlag = KSysGuard::Process::Nothing,
45                   GroupPolicy groupPolicy = Accumulate)
46         : KSysGuard::ProcessAttribute(id, name, parent)
47         , m_extractFunc(extractFunc)
48         , m_changeFlag(changeFlag)
49         , m_groupPolicy(groupPolicy)
50     {
51         if (m_changeFlag != 0) {
52             connect(parent, &ExtendedProcesses::processChanged, this, [this](KSysGuard::Process *process) {
53                 if (!process->changes().testFlag(m_changeFlag)) {
54                     return;
55                 }
56                 emit dataChanged(process);
57             });
58         }
59     }
60 
data(KSysGuard::Process * process) const61     QVariant data(KSysGuard::Process *process) const override
62     {
63         return QVariant::fromValue(m_extractFunc(process));
64     }
65 
66 private:
67     std::function<T(KSysGuard::Process *)> m_extractFunc;
68     KSysGuard::Process::Change m_changeFlag;
69     GroupPolicy m_groupPolicy = Accumulate;
70 };
71 
Private(ExtendedProcesses * _q)72 ExtendedProcesses::Private::Private(ExtendedProcesses *_q)
73     : q(_q)
74 {
75 }
76 
ExtendedProcesses(QObject * parent)77 ExtendedProcesses::ExtendedProcesses(QObject *parent)
78     : Processes(QString(), parent)
79     , d(new Private(this))
80 {
81     d->loadPlugins();
82 
83     auto pidSensor =
84         new ProcessSensor<qlonglong>(this, QStringLiteral("pid"), i18n("PID"), &KSysGuard::Process::pid, KSysGuard::Process::Status, ForwardFirstEntry);
85     pidSensor->setDescription(i18n("The unique Process ID that identifies this process."));
86     d->m_coreAttributes << pidSensor;
87 
88     auto parentPidSensor = new ProcessSensor<qlonglong>(this,
89                                                         QStringLiteral("parentPid"),
90                                                         i18n("Parent PID"),
91                                                         &KSysGuard::Process::parentPid,
92                                                         Process::Nothing,
93                                                         ForwardFirstEntry);
94     d->m_coreAttributes << parentPidSensor;
95 
96     auto loginSensor =
97         new ProcessSensor<QString>(this, QStringLiteral("login"), i18n("Login"), &KSysGuard::Process::login, KSysGuard::Process::Login, ForwardFirstEntry);
98     loginSensor->setDescription(i18n("The user who owns this process."));
99     d->m_coreAttributes << loginSensor;
100 
101     auto uidSensor =
102         new ProcessSensor<qlonglong>(this, QStringLiteral("uid"), i18n("UID"), &KSysGuard::Process::uid, KSysGuard::Process::Uids, ForwardFirstEntry);
103     d->m_coreAttributes << uidSensor;
104 
105     auto userNameSensor = new ProcessSensor<QString>(
106         this,
107         QStringLiteral("username"),
108         i18n("Username"),
109         [this](KSysGuard::Process *p) {
110             const K_UID uid = p->uid();
111             auto userIt = d->m_userCache.find(uid);
112             if (userIt == d->m_userCache.end()) {
113                 userIt = d->m_userCache.insert(uid, KUser(uid));
114             }
115             return userIt->loginName();
116         },
117         KSysGuard::Process::Uids,
118         ForwardFirstEntry);
119     d->m_coreAttributes << userNameSensor;
120 
121     auto canUserLoginSensor = new ProcessSensor<bool>(
122         this,
123         QStringLiteral("canUserLogin"),
124         i18n("Can Login"),
125         [this](KSysGuard::Process *p) {
126             const K_UID uid = p->uid();
127             if (uid == 65534) { // special value meaning nobody
128                 return false;
129             }
130             auto userIt = d->m_userCache.find(uid);
131             if (userIt == d->m_userCache.end()) {
132                 userIt = d->m_userCache.insert(uid, KUser(uid));
133             }
134 
135             if (!userIt->isValid()) {
136                 // For some reason the user isn't recognised.  This might happen under certain security situations.
137                 // Just return true to be safe
138                 return true;
139             }
140             const QString shell = userIt->shell();
141             if (shell == QLatin1String("/bin/false")) { // FIXME - add in any other shells it could be for false
142                 return false;
143             }
144             return true;
145         },
146         KSysGuard::Process::Uids,
147         ForwardFirstEntry);
148     d->m_coreAttributes << canUserLoginSensor;
149 
150     auto euidSensor =
151         new ProcessSensor<qlonglong>(this, QStringLiteral("euid"), i18n("EUID"), &KSysGuard::Process::euid, KSysGuard::Process::Uids, ForwardFirstEntry);
152     d->m_coreAttributes << euidSensor;
153 
154     auto suidSensor =
155         new ProcessSensor<qlonglong>(this, QStringLiteral("suid"), i18n("suid"), &KSysGuard::Process::suid, KSysGuard::Process::Uids, ForwardFirstEntry);
156     d->m_coreAttributes << suidSensor;
157 
158     auto fsuidSensor =
159         new ProcessSensor<qlonglong>(this, QStringLiteral("fsuid"), i18n("fsuid"), &KSysGuard::Process::fsuid, KSysGuard::Process::Uids, ForwardFirstEntry);
160     d->m_coreAttributes << fsuidSensor;
161 
162     auto gidSensor =
163         new ProcessSensor<qlonglong>(this, QStringLiteral("gid"), i18n("gid"), &KSysGuard::Process::gid, KSysGuard::Process::Gids, ForwardFirstEntry);
164     d->m_coreAttributes << gidSensor;
165 
166     auto egidSensor =
167         new ProcessSensor<qlonglong>(this, QStringLiteral("egid"), i18n("egid"), &KSysGuard::Process::egid, KSysGuard::Process::Gids, ForwardFirstEntry);
168     d->m_coreAttributes << egidSensor;
169 
170     auto sgidSensor =
171         new ProcessSensor<qlonglong>(this, QStringLiteral("sgid"), i18n("sgid"), &KSysGuard::Process::sgid, KSysGuard::Process::Gids, ForwardFirstEntry);
172     d->m_coreAttributes << sgidSensor;
173 
174     auto fsgidSensor =
175         new ProcessSensor<qlonglong>(this, QStringLiteral("fsgid"), i18n("fsgid"), &KSysGuard::Process::fsgid, KSysGuard::Process::Gids, ForwardFirstEntry);
176     d->m_coreAttributes << fsgidSensor;
177 
178     auto tracerpidSensor = new ProcessSensor<qlonglong>(this,
179                                                         QStringLiteral("tracerpid"),
180                                                         i18n("Tracer Pid"),
181                                                         &KSysGuard::Process::tracerpid,
182                                                         Process::Nothing,
183                                                         ForwardFirstEntry);
184     d->m_coreAttributes << tracerpidSensor;
185 
186     auto ttySensor =
187         new ProcessSensor<QByteArray>(this, QStringLiteral("tty"), i18n("tty"), &KSysGuard::Process::tty, KSysGuard::Process::Tty, ForwardFirstEntry);
188     ttySensor->setDescription(i18n("The controlling terminal on which this process is running."));
189     d->m_coreAttributes << ttySensor;
190 
191     auto userTimeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("userTime"), i18n("User Time"), &KSysGuard::Process::userTime);
192     d->m_coreAttributes << userTimeSensor;
193 
194     auto sysTimeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("sysTime"), i18n("System Time"), &KSysGuard::Process::sysTime);
195     sysTimeSensor->setUnit(KSysGuard::UnitSecond);
196     d->m_coreAttributes << sysTimeSensor;
197 
198     auto timeSensor = new ProcessSensor<qlonglong>(
199         this,
200         QStringLiteral("totalUsage"),
201         i18n("Total Time"),
202         [](KSysGuard::Process *p) {
203             return p->userTime() + p->sysTime();
204         },
205         KSysGuard::Process::Usage);
206     timeSensor->setShortName(i18n("Time"));
207     timeSensor->setUnit(KSysGuard::UnitSecond);
208     timeSensor->setDescription(i18n("The total user and system time that this process has been running for"));
209     d->m_coreAttributes << timeSensor;
210 
211     auto startTimeSensor = new ProcessSensor<qlonglong>(this,
212                                                         QStringLiteral("startTime"),
213                                                         i18n("Start Time"),
214                                                         &KSysGuard::Process::startTime,
215                                                         Process::Nothing,
216                                                         ForwardFirstEntry); // Is this correct for apps?
217     startTimeSensor->setDescription(i18n("The elapsed time since the process was started."));
218     startTimeSensor->setUnit(KSysGuard::UnitTime);
219     d->m_coreAttributes << startTimeSensor;
220 
221     const int maximumCpuPercent = 100 * numberProcessorCores();
222 
223     auto userUsageSensor =
224         new ProcessSensor<int>(this, QStringLiteral("userUsage"), i18n("User CPU Usage"), &KSysGuard::Process::userUsage, KSysGuard::Process::Usage);
225     userUsageSensor->setShortName(i18n("User CPU"));
226     userUsageSensor->setMin(0);
227     userUsageSensor->setMax(maximumCpuPercent);
228     userUsageSensor->setUnit(KSysGuard::UnitPercent);
229     d->m_coreAttributes << userUsageSensor;
230 
231     auto sysUsageSensor =
232         new ProcessSensor<int>(this, QStringLiteral("sysUsage"), i18n("System CPU Usage"), &KSysGuard::Process::sysUsage, KSysGuard::Process::Usage);
233     sysUsageSensor->setShortName(i18n("System CPU"));
234     sysUsageSensor->setMin(0);
235     sysUsageSensor->setMax(maximumCpuPercent);
236     sysUsageSensor->setUnit(KSysGuard::UnitPercent);
237     d->m_coreAttributes << sysUsageSensor;
238 
239     auto usageSensor = new ProcessSensor<int>(
240         this,
241         QStringLiteral("usage"),
242         i18n("Total CPU Usage"),
243         [](KSysGuard::Process *p) {
244             return p->userUsage() + p->sysUsage();
245         },
246         KSysGuard::Process::Usage,
247         Accumulate);
248     usageSensor->setShortName(i18n("CPU"));
249     usageSensor->setMin(0);
250     usageSensor->setMax(maximumCpuPercent);
251     usageSensor->setUnit(KSysGuard::UnitPercent);
252     usageSensor->setDescription(i18n("The current total CPU usage of the process."));
253     d->m_coreAttributes << usageSensor;
254 
255     auto totalUserUsageSensor = new ProcessSensor<int>(this,
256                                                        QStringLiteral("totalUserUsage"),
257                                                        i18n("Group User CPU Usage"),
258                                                        &KSysGuard::Process::totalUserUsage,
259                                                        KSysGuard::Process::TotalUsage,
260                                                        Average);
261     totalUserUsageSensor->setDescription(i18n("The amount of userspace CPU used by this process and all its children."));
262     totalUserUsageSensor->setMin(0);
263     totalUserUsageSensor->setMax(maximumCpuPercent);
264     totalUserUsageSensor->setUnit(KSysGuard::UnitPercent);
265     d->m_coreAttributes << totalUserUsageSensor;
266 
267     auto totalSysUsageSensor = new ProcessSensor<int>(this,
268                                                       QStringLiteral("totalSysUsage"),
269                                                       i18n("Group System CPU Usage"),
270                                                       &KSysGuard::Process::totalSysUsage,
271                                                       KSysGuard::Process::TotalUsage,
272                                                       Average);
273     totalUserUsageSensor->setDescription(i18n("The amount of system CPU used by this process and all its children."));
274     totalSysUsageSensor->setMin(0);
275     totalSysUsageSensor->setMax(maximumCpuPercent);
276     totalSysUsageSensor->setUnit(KSysGuard::UnitPercent);
277     d->m_coreAttributes << totalSysUsageSensor;
278 
279     auto totalUsageSensor = new ProcessSensor<int>(
280         this,
281         QStringLiteral("totalUsage"),
282         i18n("Group Total CPU Usage"),
283         [](KSysGuard::Process *p) {
284             return p->totalUserUsage() + p->totalSysUsage();
285         },
286         KSysGuard::Process::TotalUsage,
287         Average);
288     totalUsageSensor->setShortName(i18n("Group CPU"));
289     totalUserUsageSensor->setDescription(i18n("The total amount of CPU used by this process and all its children."));
290     totalUsageSensor->setMin(0);
291     totalUsageSensor->setMax(maximumCpuPercent);
292     totalUsageSensor->setUnit(KSysGuard::UnitPercent);
293     d->m_coreAttributes << totalUsageSensor;
294 
295     auto niceLevelSensor =
296         new ProcessSensor<int>(this, QStringLiteral("niceLevel"), i18n("Nice Level"), &KSysGuard::Process::niceLevel, KSysGuard::Process::NiceLevels);
297     niceLevelSensor->setDescription(i18n(
298         "The priority with which this process is being run. For the normal scheduler, this ranges from 19 (very nice, least priority) to -19 (top priority)."));
299     d->m_coreAttributes << niceLevelSensor;
300 
301     auto schedulerSensor =
302         new ProcessSensor<uint>(this, QStringLiteral("scheduler"), i18n("Scheduler"), &KSysGuard::Process::scheduler, KSysGuard::Process::NiceLevels);
303     d->m_coreAttributes << schedulerSensor;
304 
305     auto ioPriorityClassSensor = new ProcessSensor<uint>(this,
306                                                          QStringLiteral("ioPriorityClass"),
307                                                          i18n("IO Priority Class"),
308                                                          &KSysGuard::Process::ioPriorityClass,
309                                                          KSysGuard::Process::NiceLevels);
310     d->m_coreAttributes << ioPriorityClassSensor;
311 
312     auto ioniceLevelSensor =
313         new ProcessSensor<int>(this, QStringLiteral("ioniceLevel"), i18n("IO Nice Level"), &KSysGuard::Process::ioniceLevel, KSysGuard::Process::NiceLevels);
314     ioniceLevelSensor->setUnit(KSysGuard::UnitNone);
315     d->m_coreAttributes << ioniceLevelSensor;
316 
317     auto vmSizeSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("vmSize"), i18n("VM Size"), &KSysGuard::Process::vmSize, KSysGuard::Process::VmSize);
318     vmSizeSensor->setUnit(KSysGuard::UnitKiloByte);
319     vmSizeSensor->setMin(0);
320     vmSizeSensor->setMax(totalPhysicalMemory());
321     vmSizeSensor->setDescription(
322         i18n("This is the amount of virtual memory space that the process is using, included shared libraries, graphics memory, files on disk, and so on. This "
323              "number is almost meaningless."));
324     d->m_coreAttributes << vmSizeSensor;
325 
326     auto vmRSSSensor =
327         new ProcessSensor<qlonglong>(this, QStringLiteral("vmRSS"), i18n("RSS Memory Usage"), &KSysGuard::Process::vmRSS, KSysGuard::Process::VmRSS);
328     vmRSSSensor->setUnit(KSysGuard::UnitKiloByte);
329     vmRSSSensor->setMin(0);
330     vmRSSSensor->setMax(totalPhysicalMemory());
331     vmRSSSensor->setDescription(
332         i18n("This is the amount of physical memory that this process is using and includes the amount of memory used by shared libraries."));
333 
334     auto vmURSSSensor =
335         new ProcessSensor<qlonglong>(this, QStringLiteral("vmURSS"), i18n("Private Memory Usage"), &KSysGuard::Process::vmURSS, KSysGuard::Process::VmURSS);
336     vmURSSSensor->setUnit(KSysGuard::UnitKiloByte);
337     vmURSSSensor->setShortName(i18n("Private"));
338     vmURSSSensor->setMin(0);
339     vmURSSSensor->setMax(totalPhysicalMemory());
340     vmURSSSensor->setDescription(
341         i18n("This is the amount of physical memory that this process is using by itself, and approximates the Private memory usage of the process.<br>It does "
342              "not include any swapped out memory, nor the code size of its shared libraries."));
343     d->m_coreAttributes << vmURSSSensor;
344 
345     auto sharedMemorySensor = new ProcessSensor<qlonglong>(
346         this,
347         QStringLiteral("vmShared"),
348         i18n("Shared Memory Usage"),
349         [](KSysGuard::Process *p) -> qlonglong {
350             if (p->vmRSS() - p->vmURSS() < 0 || p->vmURSS() == -1) {
351                 return 0;
352             }
353             return (qlonglong)(p->vmRSS() - p->vmURSS());
354         },
355         KSysGuard::Process::VmRSS);
356     d->m_coreAttributes << sharedMemorySensor;
357     sharedMemorySensor->setShortName(i18n("Shared"));
358     sharedMemorySensor->setDescription(
359         i18n("This is approximately the amount of real physical memory that this process's shared libraries are using.<br>This memory is shared among all "
360              "processes that use this library."));
361     sharedMemorySensor->setUnit(KSysGuard::UnitKiloByte);
362     sharedMemorySensor->setMin(0);
363     sharedMemorySensor->setMax(totalPhysicalMemory());
364 
365     auto vmPSSSensor = new ProcessSensor<qlonglong>(this, QStringLiteral("vmPSS"), i18n("Memory Usage"), &KSysGuard::Process::vmPSS, KSysGuard::Process::VmPSS);
366     vmPSSSensor->setShortName(i18n("Memory"));
367     vmPSSSensor->setUnit(KSysGuard::UnitKiloByte);
368     vmPSSSensor->setMin(0);
369     vmPSSSensor->setMax(totalPhysicalMemory());
370     vmPSSSensor->setRequiredUpdateFlags(Processes::Smaps);
371     vmPSSSensor->setDescription(
372         i18n("This is an approximation of the real amount of physical memory that this process is using. It is calculated by dividing the process' shared "
373              "memory usage by the amount of processes sharing that memory, then adding the process' private memory."));
374     d->m_coreAttributes << vmPSSSensor;
375 
376     auto nameSensor =
377         new ProcessSensor<QString>(this, QStringLiteral("name"), i18n("Name"), &KSysGuard::Process::name, KSysGuard::Process::Name, ForwardFirstEntry);
378     nameSensor->setDescription(i18n("The process name."));
379     d->m_coreAttributes << nameSensor;
380 
381     auto commandSensor = new ProcessSensor<QString>(this,
382                                                     QStringLiteral("command"),
383                                                     i18n("Command"),
384                                                     &KSysGuard::Process::command,
385                                                     KSysGuard::Process::Command,
386                                                     ForwardFirstEntry);
387     commandSensor->setDescription(i18n("The command with which this process was launched."));
388     d->m_coreAttributes << commandSensor;
389 
390     auto statusSensor =
391         new ProcessSensor<QString>(this, QStringLiteral("status"), i18n("Status"), &KSysGuard::Process::translatedStatus, KSysGuard::Process::Status);
392     d->m_coreAttributes << statusSensor;
393 
394     auto ioCharactersReadSensor = new ProcessSensor<qlonglong>(this,
395                                                                QStringLiteral("ioCharactersRead"),
396                                                                i18n("IO Characters Read"),
397                                                                &KSysGuard::Process::ioCharactersRead,
398                                                                KSysGuard::Process::IO);
399     ioCharactersReadSensor->setUnit(KSysGuard::UnitByte);
400     ioCharactersReadSensor->setRequiredUpdateFlags(Processes::IOStatistics);
401     d->m_coreAttributes << ioCharactersReadSensor;
402 
403     auto ioCharactersWrittenSensor = new ProcessSensor<qlonglong>(this,
404                                                                   QStringLiteral("ioCharactersWritten"),
405                                                                   i18n("IO Characters Written"),
406                                                                   &KSysGuard::Process::ioCharactersWritten,
407                                                                   KSysGuard::Process::IO);
408     ioCharactersWrittenSensor->setUnit(KSysGuard::UnitByte);
409     ioCharactersWrittenSensor->setRequiredUpdateFlags(Processes::IOStatistics);
410     d->m_coreAttributes << ioCharactersWrittenSensor;
411 
412     auto ioReadSyscallsSensor = new ProcessSensor<qlonglong>(this,
413                                                              QStringLiteral("ioReadSyscalls"),
414                                                              i18n("IO Read Syscalls"),
415                                                              &KSysGuard::Process::ioReadSyscalls,
416                                                              KSysGuard::Process::IO);
417     ioReadSyscallsSensor->setUnit(KSysGuard::UnitRate);
418     ioReadSyscallsSensor->setRequiredUpdateFlags(Processes::IOStatistics);
419     d->m_coreAttributes << ioReadSyscallsSensor;
420 
421     auto ioReadSyscallsRateSensor = new ProcessSensor<qlonglong>(this,
422                                                                  QStringLiteral("ioReadSyscallsRate"),
423                                                                  i18n("IO Read Syscalls Rate"),
424                                                                  &KSysGuard::Process::ioReadSyscallsRate,
425                                                                  KSysGuard::Process::IO);
426     ioReadSyscallsRateSensor->setUnit(KSysGuard::UnitRate);
427     ioReadSyscallsRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
428     d->m_coreAttributes << ioReadSyscallsSensor;
429 
430     auto ioWriteSyscallsSensor = new ProcessSensor<qlonglong>(this,
431                                                               QStringLiteral("ioWriteSyscalls"),
432                                                               i18n("IO Write Syscalls"),
433                                                               &KSysGuard::Process::ioWriteSyscalls,
434                                                               KSysGuard::Process::IO);
435     ioWriteSyscallsSensor->setUnit(KSysGuard::UnitRate);
436     ioWriteSyscallsSensor->setRequiredUpdateFlags(Processes::IOStatistics);
437     d->m_coreAttributes << ioWriteSyscallsSensor;
438 
439     auto ioWriteSyscallsRateSensor = new ProcessSensor<qlonglong>(this,
440                                                                   QStringLiteral("ioReadSyscallsRate"),
441                                                                   i18n("IO Write Syscalls Rate"),
442                                                                   &KSysGuard::Process::ioWriteSyscallsRate,
443                                                                   KSysGuard::Process::IO);
444     ioWriteSyscallsRateSensor->setUnit(KSysGuard::UnitRate);
445     ioWriteSyscallsRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
446     d->m_coreAttributes << ioWriteSyscallsRateSensor;
447 
448     auto ioCharactersActuallyReadSensor = new ProcessSensor<qlonglong>(this,
449                                                                        QStringLiteral("ioCharactersActuallyRead"),
450                                                                        i18n("IO Characters Actually Read"),
451                                                                        &KSysGuard::Process::ioCharactersActuallyRead,
452                                                                        KSysGuard::Process::IO);
453     ioCharactersActuallyReadSensor->setUnit(KSysGuard::UnitByte);
454     ioCharactersActuallyReadSensor->setRequiredUpdateFlags(Processes::IOStatistics);
455     d->m_coreAttributes << ioCharactersActuallyReadSensor;
456 
457     auto ioCharactersReadRateSensor = new ProcessSensor<qlonglong>(this,
458                                                                    QStringLiteral("ioCharactersReadRate"),
459                                                                    i18n("IO Characters Read Rate"),
460                                                                    &KSysGuard::Process::ioCharactersReadRate,
461                                                                    KSysGuard::Process::IO);
462     ioCharactersReadRateSensor->setDescription(i18n("The read rate for all of a process' IO, including disk cache and other nonphysical IO."));
463     ioCharactersReadRateSensor->setUnit(KSysGuard::UnitByteRate);
464     ioCharactersReadRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
465     d->m_coreAttributes << ioCharactersReadRateSensor;
466 
467     auto ioCharactersWrittenRateSensor = new ProcessSensor<qlonglong>(this,
468                                                                       QStringLiteral("ioCharactersWrittenRate"),
469                                                                       i18n("IO Characters Written Rate"),
470                                                                       &KSysGuard::Process::ioCharactersWrittenRate,
471                                                                       KSysGuard::Process::IO);
472     ioCharactersWrittenRateSensor->setDescription(i18n("The write rate for all of a process' IO, including disk cache and other nonphysical IO."));
473     ioCharactersWrittenRateSensor->setUnit(KSysGuard::UnitByteRate);
474     ioCharactersWrittenRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
475     d->m_coreAttributes << ioCharactersWrittenRateSensor;
476 
477     auto ioCharactersActuallyReadRateSensor = new ProcessSensor<qlonglong>(this,
478                                                                            QStringLiteral("ioCharactersActuallyReadRate"),
479                                                                            i18n("Disk Read Rate"),
480                                                                            &KSysGuard::Process::ioCharactersActuallyReadRate,
481                                                                            KSysGuard::Process::IO);
482     ioCharactersActuallyReadRateSensor->setUnit(KSysGuard::UnitByteRate);
483     ioCharactersActuallyReadRateSensor->setShortName(i18n("Read"));
484     ioCharactersActuallyReadRateSensor->setDescription(i18n("The rate of data being read from disk."));
485     ioCharactersActuallyReadRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
486     d->m_coreAttributes << ioCharactersActuallyReadRateSensor;
487 
488     auto ioCharactersActuallyWrittenRateSensor = new ProcessSensor<qlonglong>(this,
489                                                                               QStringLiteral("ioCharactersActuallyWrittenRate"),
490                                                                               i18n("Disk Write Rate"),
491                                                                               &KSysGuard::Process::ioCharactersActuallyWrittenRate,
492                                                                               KSysGuard::Process::IO);
493     ioCharactersActuallyWrittenRateSensor->setUnit(KSysGuard::UnitByteRate);
494     ioCharactersActuallyWrittenRateSensor->setShortName(i18n("Write"));
495     ioCharactersActuallyWrittenRateSensor->setDescription(i18n("The rate of data being written to the disk."));
496     ioCharactersActuallyWrittenRateSensor->setRequiredUpdateFlags(Processes::IOStatistics);
497     d->m_coreAttributes << ioCharactersActuallyWrittenRateSensor;
498 
499     auto numThreadsSensor = new ProcessSensor<int>(this,
500                                                    QStringLiteral("numThreads"),
501                                                    i18n("Threads"),
502                                                    &KSysGuard::Process::numThreads,
503                                                    KSysGuard::Process::NumThreads,
504                                                    ForwardFirstEntry);
505     d->m_coreAttributes << numThreadsSensor;
506 
507     connect(this, &KSysGuard::Processes::beginRemoveProcess, this, [this](KSysGuard::Process *process) {
508         const auto attrs = attributes();
509         for (auto a : attrs) {
510             a->clearData(process);
511         }
512     });
513 
514     connect(this, &KSysGuard::Processes::updated, this, [this]() {
515         for (auto p : qAsConst(d->m_providers)) {
516             if (p->enabled()) {
517                 p->update();
518             }
519         }
520     });
521 }
522 
~ExtendedProcesses()523 ExtendedProcesses::~ExtendedProcesses()
524 {
525 }
526 
attributes() const527 QVector<ProcessAttribute *> ExtendedProcesses::attributes() const
528 {
529     return d->m_coreAttributes + extendedAttributes();
530 }
531 
extendedAttributes() const532 QVector<ProcessAttribute *> ExtendedProcesses::extendedAttributes() const
533 {
534     QVector<ProcessAttribute *> rc;
535     for (auto p : qAsConst(d->m_providers)) {
536         rc << p->attributes();
537     }
538     return rc;
539 }
540 
loadPlugins()541 void ExtendedProcesses::Private::loadPlugins()
542 {
543 #if KCOREADDONS_VERSION < QT_VERSION_CHECK(5, 86, 0)
544     const QVector<KPluginMetaData> listMetaData = KPluginLoader::findPlugins(QStringLiteral("ksysguard/process"));
545 #else
546     const QVector<KPluginMetaData> listMetaData = KPluginMetaData::findPlugins(QStringLiteral("ksysguard/process"));
547 #endif
548     // instantiate all plugins
549     for (const auto &pluginMetaData : listMetaData) {
550         qCDebug(LIBKSYSGUARD_PROCESSCORE) << "loading plugin" << pluginMetaData.name();
551         auto factory = qobject_cast<KPluginFactory *>(pluginMetaData.instantiate());
552         if (!factory) {
553             qCCritical(LIBKSYSGUARD_PROCESSCORE) << "failed to load plugin factory" << pluginMetaData.name();
554             continue;
555         }
556         ProcessDataProvider *provider = factory->create<ProcessDataProvider>(q);
557         if (!provider) {
558             qCCritical(LIBKSYSGUARD_PROCESSCORE) << "failed to instantiate ProcessDataProvider" << pluginMetaData.name();
559             continue;
560         }
561         m_providers << provider;
562     }
563 }
564 
instance()565 QSharedPointer<ExtendedProcesses> ExtendedProcesses::instance()
566 {
567     static QWeakPointer<ExtendedProcesses> instance;
568     auto processes = instance.lock();
569     if (!processes) {
570         processes = QSharedPointer<ExtendedProcesses>(new ExtendedProcesses, [](ExtendedProcesses *p) {
571             delete p;
572         });
573         instance = processes;
574     }
575     return processes;
576 }
577