Skip to content

Commit

Permalink
Merge pull request #358 from stsdc/new-process-app-matching
Browse files Browse the repository at this point in the history
- Better process to app matching
- Flatpak apps detection
  • Loading branch information
stsdc authored Jul 9, 2023
2 parents 4a555e3 + 2af28de commit f7e2036
Show file tree
Hide file tree
Showing 8 changed files with 718 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
apt update
apt install -y libgala-dev libgee-0.8-dev libglib2.0-dev libgranite-dev libgtk-3-dev libhandy-1-dev
apt install -y libdbus-glib-1-dev libwnck-3-dev libgtop2-dev libwingpanel-3.0-dev libudisks2-dev
apt install -y libxnvctrl0 libxnvctrl-dev libcurl4-gnutls-dev
apt install -y libxnvctrl0 libxnvctrl-dev libcurl4-gnutls-dev libflatpak-dev
apt install -y meson valac sassc git
- name: Build
env:
Expand Down
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Build-Depends: meson,
libxnvctrl-dev,
libcurl4-gnutls-dev,
libjson-glib-dev,
libflatpak-dev,
sassc
Standards-Version: 4.1.1

Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ app_dependencies = [
dependency('x11'),
dependency('udisks2'),
dependency('json-glib-1.0'),
dependency('flatpak'),

livechart_proj.get_variable('livechart_dep'),

Expand Down
25 changes: 20 additions & 5 deletions src/Managers/Process.vala
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class Monitor.Process : GLib.Object {

public Gee.HashSet<string> open_files_paths;

public Gee.HashSet<int> children = new Gee.HashSet<int> ();

/**
* CPU usage of this process from the last time that it was updated, measured in percent
*
Expand Down Expand Up @@ -91,9 +93,8 @@ public class Monitor.Process : GLib.Object {
username = passwd.pw_name;
}



exists = parse_stat () && read_cmdline ();
get_children_pids ();
get_usage (0, 1);
}

Expand All @@ -112,7 +113,6 @@ public class Monitor.Process : GLib.Object {
}

// Kills the process
// Returns if kill was successful
public bool kill () {
// Sends a kill signal that cannot be ignored
if (Posix.kill (stat.pid, Posix.Signal.KILL) == 0) {
Expand All @@ -122,7 +122,6 @@ public class Monitor.Process : GLib.Object {
}

// Ends the process
// Returns if end was successful
public bool end () {
// Sends a terminate signal
if (Posix.kill (stat.pid, Posix.Signal.TERM) == 0) {
Expand All @@ -131,6 +130,19 @@ public class Monitor.Process : GLib.Object {
return false;
}

private bool get_children_pids () {
string ? children_content = ProcessUtils.read_file ("/proc/%d/task/%d/children".printf (stat.pid, stat.pid));
if (children_content == "" || children_content == null) {
return false;
}

var splitted_children_pids = children_content.split (" ");
foreach (var child in splitted_children_pids) {
this.children.add (int.parse (child));
}
return true;
}

private bool parse_io () {
var io_file = File.new_for_path ("/proc/%d/io".printf (stat.pid));

Expand Down Expand Up @@ -273,7 +285,10 @@ public class Monitor.Process : GLib.Object {
}

if (cmdline.length <= 0) {
// was empty, not an error
// if cmdline has 0 length we look into stat file
// useful for kworker processes
command = stat.comm;

return true;
}

Expand Down
158 changes: 102 additions & 56 deletions src/Managers/ProcessManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace Monitor {
private Gee.TreeMap<int, Process> process_list;
private Gee.HashSet<int> kernel_process_blacklist;
private Gee.HashMap<string, AppInfo> apps_info_list;
private Gee.HashSet<Flatpak.Instance> flatpak_apps = new Gee.HashSet<Flatpak.Instance> ();



public signal void process_added (Process process);
Expand All @@ -29,6 +31,9 @@ namespace Monitor {
apps_info_list = new Gee.HashMap<string, AppInfo> ();

populate_apps_info ();
Flatpak.Instance.get_all ().foreach ((fp) => {
flatpak_apps.add (fp);
});

update_processes.begin ();
}
Expand All @@ -38,59 +43,20 @@ namespace Monitor {

foreach (AppInfo app_info in _apps_info) {
string commandline = (app_info.get_commandline ());
// debug ("%s\n", commandline);

// GLib.DesktopAppInfo? dai = info as GLib.DesktopAppInfo;

// if (dai != null) {
// string id = dai.get_string ("X-Flatpak");
// if (id != null)
// appid_map.insert (id, info);
// }


if (commandline == null)
continue;

// sanitize_cmd (ref cmd);
apps_info_list.set (commandline, app_info);
}
}

// private static void sanitize_cmd(ref string? commandline) {
// if (commandline == null)
// return;

//// flatpak: parse the command line of the containerized program
// if (commandline.contains("flatpak run")) {
// var index = commandline.index_of ("--command=") + 10;
// commandline = commandline.substring (index);
// }

//// TODO: unify this with the logic in get_full_process_cmd
//// commandline = Process.first_component (commandline);
//// commandline = Path.get_basename (commandline);
//// commandline = Process.sanitize_name (commandline);

//// Workaround for google-chrome
// if (commandline.contains ("google-chrome-stable"))
// commandline = "chrome";
// }

// public static AppInfo? app_info_for_process (Process p) {
// AppInfo? info = null;

// if (p.command != null)
// info = apps_info[p.command];

// if (info == null && p.app_id != null)
// info = appid_map[p.app_id];

// return info;
// }




/**
* Gets a process by its pid, making sure that it's updated.
Expand Down Expand Up @@ -174,7 +140,7 @@ namespace Monitor {

var uid = Posix.getuid ();
GTop.ProcList proclist;
// var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_UID, uid);
// var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_UID, uid);
var pids = GTop.get_proclist (out proclist, GTop.GLIBTOP_KERN_PROC_ALL, uid);

for (int i = 0; i < proclist.number; i++) {
Expand All @@ -190,38 +156,111 @@ namespace Monitor {
cpu_last_useds = useds;
cpu_last_totals = cpu_data.xcpu_total;


Flatpak.Instance.get_all ().foreach ((fp) => {
flatpak_apps.add (fp);
});

/* emit the updated signal so that subscribers can update */
updated ();

}

/**
* Parses a pid and adds a Process to our process_list or to the kernel_blacklist
*
* returns the created process
*/
private Process ? add_process (int pid, bool lazy_signal = false) {
// create the process
var process = new Process (pid);
/** Sets name and icon for a process that is a Flatpak app and its children. */
private void set_flatpak_name_icon (Process process, GLib.Icon icon, string name) {
process.application_name = name;
process.icon = icon;
foreach (int pid in process.children) {
var _process = this.get_process (pid);
if (_process != null) {
set_flatpak_name_icon (_process, icon, name);
}
}
}

private bool match_process_app (Process process) {
var command_sanitized = ProcessUtils.sanitize_commandline (process.command);
var command_sanitized_basename = Path.get_basename (command_sanitized);

// placeholding shortened commandline
process.application_name = ProcessUtils.sanitize_commandline (process.command);
process.application_name = command_sanitized_basename;

foreach (var flatpak_app in flatpak_apps) {
if (flatpak_app.get_pid () == process.stat.pid || flatpak_app.get_child_pid () == process.stat.pid) {
debug ("Found Flatpak app: %s ", flatpak_app.get_app ());
foreach (var key in apps_info_list.keys) {
if (apps_info_list.get (key).get_id ().replace (".desktop", "") == flatpak_app.get_app ()) {
set_flatpak_name_icon (process, apps_info_list.get (key).get_icon (), apps_info_list.get (key).get_name ());
}
}
}
}

// checking maybe it's an application
foreach (var key in apps_info_list.keys) {
if (key.contains (process.application_name)) {
if (apps_info_list.get (key).get_executable () == command_sanitized) {
process.application_name = apps_info_list.get (key).get_name ();
process.icon = apps_info_list.get (key).get_icon ();
} else if (apps_info_list.get (key).get_executable () == process.command.split (" ")[1]) {
process.application_name = apps_info_list.get (key).get_name ();
// debug (apps_info_list.get (key).get_icon ().to_string ());
process.icon = apps_info_list.get (key).get_icon ();
} else if (key.split (" ")[1] != null) {
if (key.split (" ")[1].contains ("%") || key.split (" ")[1].contains ("--")) {
if (apps_info_list.get (key).get_executable () == command_sanitized_basename) {
process.application_name = apps_info_list.get (key).get_name ();
process.icon = apps_info_list.get (key).get_icon ();
return true;
}
}
// Steam case
// Must match a proper executable and not game executable e.g. steam steam://rungameid/210770
if ((Path.get_basename (key.split (" ")[0]) == command_sanitized_basename) && !key.split (" ")[1].contains ("steam")) {
process.application_name = apps_info_list.get (key).get_name ();
process.icon = apps_info_list.get (key).get_icon ();
return true;
}

// workaround for some flatpak apps
if (process.command.contains (apps_info_list.get (key).get_id ().replace (".desktop", ""))) {
process.application_name = apps_info_list.get (key).get_name ();
process.icon = apps_info_list.get (key).get_icon ();
return true;
}
} else if (apps_info_list.get (key).get_commandline () == process.command) {
process.application_name = apps_info_list.get (key).get_name ();
process.icon = apps_info_list.get (key).get_icon ();
return true;
}
}

if (process.application_name == "bash") {
debug ("app name is [bash] " + process.application_name);
if (ProcessUtils.is_shell (command_sanitized_basename)) {
process.icon = ProcessUtils.get_bash_icon ();
debug ("app name is " + process.application_name);
}
if (process.application_name == "docker" || process.application_name == "dockerd") {
if (command_sanitized_basename == "docker" || command_sanitized_basename == "dockerd" || command_sanitized_basename == "docker-proxy") {
process.icon = ProcessUtils.get_docker_icon ();
process.application_name = command_sanitized_basename;
debug ("app name is " + process.application_name);
}

// process.application_name = process.command;

return true;
}

/**
* Parses a pid and adds a Process to our `process_list` or to the `kernel_blacklist`
*
* returns the created process
*/
private Process ? add_process (int pid, bool lazy_signal = false) {
// create the process
var process = new Process (pid);

if (!process.exists) {
return null;
}

this.match_process_app (process);

if (process.exists) {
if (process.stat.pgrp != 0) {
// regular process, add it to our cache
Expand Down Expand Up @@ -250,6 +289,13 @@ namespace Monitor {
private void remove_process (int pid) {
if (process_list.has_key (pid)) {
process_list.unset (pid);
// flatpak_apps.remove (pid);
foreach (var fp in flatpak_apps) {
if (fp.get_pid () == pid) {
flatpak_apps.remove (fp);
break;
}
}
process_removed (pid);
} else if (kernel_process_blacklist.contains (pid)) {
kernel_process_blacklist.remove (pid);
Expand Down
14 changes: 9 additions & 5 deletions src/Managers/ProcessUtils.vala
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
public class Monitor.ProcessUtils {
// checks if it is run by shell
private static bool is_shell (string chunk) {
public static bool is_shell (string chunk) {
return "sh" == chunk || "bash" == chunk || "zsh" == chunk;
}

private static bool is_python (string chunk) {
public static bool is_python (string chunk) {
return chunk.contains ("python");
}

public static string sanitize_commandline (string ? commandline) {
if (commandline == null) return Path.get_basename ("");
if (commandline == null) return "";

// splitting command; might include many options
var splitted_commandline = commandline.split (" ");

// check if started by any shell
if (is_shell (splitted_commandline[0]) || is_python (splitted_commandline[0]) ) {
return Path.get_basename (splitted_commandline[1]);
return commandline;
}

return Path.get_basename (splitted_commandline[0]);
// if (!splitted_commandline[0].contains ("/")) {
// return commandline;
// }

return splitted_commandline[0];
}

public static string ? read_file (string path) {
Expand Down
Loading

0 comments on commit f7e2036

Please sign in to comment.