Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Processes started after program using sysinfo aren't added to processes list, sometimes #1339

Open
valentinegb opened this issue Aug 17, 2024 · 17 comments

Comments

@valentinegb
Copy link

Describe the bug

It seems that if a program is using sysinfo to check the processes currently running and a new process starts later, it won't be added to the list of processes despite refreshing. Inexplicably, though, while this happens most of the time, there are some times where a newly launched program will be detected.

  • sysinfo version: 0.31.2
  • sysinfo features: system
  • Platform: macOS

To Reproduce

let mut sys = sysinfo::System::new();

loop {
    sys.refresh_processes_specifics(ProcessesToUpdate::All, ProcessRefreshKind::new());

    let discord_is_open = sys.processes_by_name("Discord".as_ref()).next().is_some();
    let apple_music_is_open = sys.processes_by_name("Music".as_ref()).next().is_some();

    // Code reacting to the values of these variables
}
@GuillaumeGomez
Copy link
Owner

Did you give a try to process-viewer and does it have the same issue? Your code looks correct to me. So maybe the issue is the process name you're using to filter?

@valentinegb
Copy link
Author

process-viewer doesn't seem to have the same problem. Oddly, searching for the process name exactly wouldn't show it, but searching for the process name in all lowercase always did when it was open. In my code I changed instances of processes_by_name() to processes_by_exact_name(), since I do have the exact names of the processes I'm looking for, but regardless the issue persists.

@GuillaumeGomez
Copy link
Owner

Weird. And when you list all processes, do you see the ones you're looking for?

@valentinegb
Copy link
Author

valentinegb commented Aug 17, 2024

Nope, not unless they were open before I started checking

(Just did this and then searched in my terminal)

for (_pid, process) in sys.processes() {
    trace!("{}", process.name().to_str().unwrap());
}

@GuillaumeGomez
Copy link
Owner

Your issue is very weird. It is tested in different tests like here: the binary is run then only we refresh processes and it's working on mac as well. I'm really confused about what's going wrong on your side...

@valentinegb
Copy link
Author

valentinegb commented Aug 17, 2024

I cloned sysinfo and ran all the tests, all passed except test_environ (not sure if that's related)

---- test_environ stdout ----
thread 'test_environ' panicked at tests/process.rs:158:9:
assertion failed: proc_.environ().iter().any(|e| *e == *env)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

It may be worth noting that I'm on macOS 15.1 Beta (24B5024e), though I read through the release notes and didn't see any indication that this is a known issue

@GuillaumeGomez
Copy link
Owner

This one is flaky (on mac). For some reasons, sometimes it cannot retrieve process environment. No clue why. It's part of mac's "magic". ^^'

But if all tests pass, it seems to mean that the problem might not be directly in sysinfo. Maybe there is something slightly different you do which triggers this result? If we can find out what it is, it'd be awesome so that it can be either be fixed directly in sysinfo or at least be mentioned in the docs that this one thing should be done differently.

@valentinegb
Copy link
Author

Here's pretty much all the code that currently is actually used in my program:

// main.rs
use std::{error::Error, process::ExitCode};

use discord_rich_presence::{DiscordIpc, DiscordIpcClient};
use log::{debug, error, trace};
use sysinfo::{ProcessRefreshKind, ProcessesToUpdate};

const CLIENT_ID: &str = "1273805325954187386";

fn try_main() -> Result<(), Box<dyn Error>> {
    env_logger::init();
    debug!("Initialized logging");

    if !sysinfo::IS_SUPPORTED_SYSTEM {
        return Err("This system is not supported by sysinfo, a crucial dependency".into());
    }

    let mut sys = sysinfo::System::new();
    let mut discord_client = None;

    loop {
        sys.refresh_processes_specifics(ProcessesToUpdate::All, ProcessRefreshKind::new());

        let discord_is_open = sys
            .processes_by_exact_name("Discord".as_ref())
            .next()
            .is_some();
        let apple_music_is_open = sys
            .processes_by_exact_name("Music".as_ref())
            .next()
            .is_some();

        if discord_is_open && apple_music_is_open {
            trace!("Time to work!");

            if discord_client.is_none() {
                discord_client = Some(DiscordIpcClient::new(CLIENT_ID)?);

                discord_client.as_mut().unwrap().connect()?;
                debug!("Connected Discord client");
            }

            // TODO
        } else {
            trace!("Idling...");
        }
    }
}

fn main() -> ExitCode {
    if let Err(err) = try_main() {
        error!("{err}");

        return ExitCode::FAILURE;
    }

    ExitCode::SUCCESS // Impossible to reach?
}
# Cargo.toml
[package]
name = "apple-music-rich-presence"
version = "0.1.0"
edition = "2021"

[dependencies]
discord-rich-presence = { git = "https://github.com/vionya/discord-rich-presence.git", rev = "5620e8901566290a583f9354205686b18628ba1b", version = "0.2.4" }
env_logger = "0.11.5"
log = "0.4.22"
sysinfo = { version = "0.31.2", default-features = false, features = ["system"] }

Some stuff was omitted since it's old and not actually used

Sorry for the massive comment! You would think most of this couldn't be causing this issue but, who knows

@GuillaumeGomez
Copy link
Owner

Your code looks good. Then let's try taking a different approach: if you ask for the PIDs when you start the program and then see what information sysinfo has for both processes maybe? I'm curious to see if an information in particular is badly retrieved.

@valentinegb
Copy link
Author

valentinegb commented Aug 17, 2024

I switched out refresh_processes_specifics() for refresh_processes() and added this to the loop:

for (pid, process) in sys.processes() {
    trace!("{pid}: {process:?}");
}

Launched Discord and Apple Music then the program. Found those two in the logs:

[2024-08-17T19:58:24Z TRACE apple_music_rich_presence] 11848: Process { pid: Pid(11848), parent: Some(Pid(1)), name: "Discord", environ: [], command: [], executable path: Some("/Applications/Discord.app/Contents/MacOS/Discord"), current working directory: None, memory usage: 48381952, virtual memory usage: 1635724623872, CPU usage: 0.0, status: Run, root: None, disk_usage: DiskUsage { total_written_bytes: 13795328, written_bytes: 0, total_read_bytes: 245784576, read_bytes: 0 }, user_id: Some(Uid(501)), effective_user_id: Some(Uid(501)) }
[2024-08-17T19:58:24Z TRACE apple_music_rich_presence] 15340: Process { pid: Pid(15340), parent: Some(Pid(1)), name: "Music", environ: [], command: [], executable path: Some("/System/Applications/Music.app/Contents/MacOS/Music"), current working directory: None, memory usage: 141099008, virtual memory usage: 426729963520, CPU usage: 0.0, status: Run, root: None, disk_usage: DiskUsage { total_written_bytes: 630784, written_bytes: 0, total_read_bytes: 93708288, read_bytes: 0 }, user_id: Some(Uid(501)), effective_user_id: Some(Uid(501)) }

Another very strange thing I noticed is that programs (such as "VisualizerService") which are launched alongside Apple Music, are detected by sysinfo when Apple Music is launched afterwards, even though Apple Music itself is not. Here's the logging of VisualizerService, too:

[2024-08-17T19:58:24Z TRACE apple_music_rich_presence] 15341: Process { pid: Pid(15341), parent: Some(Pid(1)), name: "VisualizerService", environ: [], command: [], executable path: Some("/System/Applications/Music.app/Contents/XPCServices/VisualizerService.xpc/Contents/MacOS/VisualizerService"), current working directory: None, memory usage: 15843328, virtual memory usage: 420849057792, CPU usage: 0.0, status: Run, root: None, disk_usage: DiskUsage { total_written_bytes: 0, written_bytes: 0, total_read_bytes: 348160, read_bytes: 0 }, user_id: Some(Uid(501)), effective_user_id: Some(Uid(501)) }

@GuillaumeGomez
Copy link
Owner

Definitely strange. refresh_processes calls refresh_processes_specifics as you can see here. So there is definitely something wrong in sysinfo. Since I can't replicate the bug locally, do you mind trying to find out what's wrong in the source code please? ^^'

Don't hesitate to ask if you have any question. But I'm glad that a new bug was found. :D

@valentinegb
Copy link
Author

A revelation! This code fixed the issue:

sleep(Duration::from_secs(5));

... So the problem is that the loop is too fast when not limited?

@GuillaumeGomez
Copy link
Owner

Wait really? If true then it's really not great. T_T

sysinfo uses proc_listallpids to retrieve all PIDs and then iterate through them. It'd be super weird for this API to take multiple seconds to realize a process got added...

@valentinegb
Copy link
Author

valentinegb commented Aug 17, 2024

Did a little bit of testing, I was able to get as low as 1 second to consistently detect processes correctly, and as low as 100 milliseconds to inconsistently detect processes correctly

@GuillaumeGomez
Copy link
Owner

But no process with the given PID you're looking for is there right? If so, I suppose the proc_listallpids function is not working correctly...

@valentinegb
Copy link
Author

But no process with the given PID you're looking for is there right?

If there's some time between refreshes, the processes I'm looking for do appear.

@GuillaumeGomez
Copy link
Owner

So it seems like the system API is not refreshing very quickly. How strange.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants