4949#include < cstdlib>
5050#include < cstring>
5151#include < ctime>
52-
52+ #include < fcntl.h>
53+ #include < sys/mman.h>
54+ #include < sys/stat.h>
5355#include < sys/param.h>
5456
5557#if HAVE_SYS_TYPES_H
6567#include < sys/vmmeter.h>
6668#endif
6769
68- #include < sys/stat.h>
69-
7070#if HAVE_SYS_SWAP_H
7171#include < sys/swap.h>
7272#endif
106106#include " error_numbers.h"
107107#include " common_defs.h"
108108#include " filesys.h"
109+ #include " shmem.h"
109110#include " str_util.h"
110111#include " str_replace.h"
111112#include " util.h"
@@ -541,12 +542,11 @@ static void parse_cpuinfo_linux(HOST_INFO& host) {
541542
542543#if defined(__aarch64__) || defined(__arm__)
543544 if (
544- // Hardware is specifying the board this CPU is on, store it in product_name while we parse /proc/cpuinfo
545+ // Hardware is specifying the board this CPU is on,
546+ // store it in product_name while we parse /proc/cpuinfo
545547 strstr (buf, " Hardware\t : " )
546548 ) {
547- // this makes sure we only ever copy as much bytes as we can still store in host.product_name
548- int t = sizeof (host.product_name ) - strlen (host.product_name ) - 2 ;
549- strlcpy (buf2, strchr (buf, ' :' ) + 2 , ((t<sizeof (buf2))?t:sizeof (buf2)));
549+ strlcpy (buf2, strchr (buf, ' :' ) + 2 , sizeof (buf2));
550550 strip_whitespace (buf2);
551551 if (strlen (host.product_name )) {
552552 safe_strcat (host.product_name , " " );
@@ -2291,9 +2291,92 @@ long xss_idle() {
22912291
22922292#endif // LINUX_LIKE_SYSTEM
22932293
2294+ #ifndef ANDROID // Android doesn't have shm_open()
2295+ // idle time detection.
2296+ // old approach: do it ourselves by looking at devices
2297+ // and trying to get info from X11
2298+ // (big mess, permissions problems, doesn't generally work)
2299+ // new approach: get last-input time from a separate daemon process,
2300+ // communicated via shmem
2301+
2302+ bool get_idle_time_from_daemon (long &idle_time) {
2303+ static int64_t * seg_ptr = NULL ;
2304+ if (!seg_ptr) {
2305+ int fd = shm_open (" /idle_detect_shmem" , O_RDONLY, 0 );
2306+ if (fd < 0 ) {
2307+ return false ;
2308+ }
2309+
2310+ struct stat st;
2311+ if (fstat (fd, &st)) {
2312+ close (fd);
2313+ return false ;
2314+ }
2315+ if (st.st_size < 2 *sizeof (int64_t )) {
2316+ close (fd);
2317+ return false ;
2318+ }
2319+
2320+ int64_t * mapped_ptr = (int64_t *)mmap (
2321+ NULL , 2 *sizeof (int64_t ), PROT_READ, MAP_SHARED, fd, 0
2322+ );
2323+ close (fd);
2324+ if (mapped_ptr == MAP_FAILED) {
2325+ return false ;
2326+ }
2327+
2328+ seg_ptr = mapped_ptr;
2329+ }
2330+ if (!seg_ptr) return false ;
2331+
2332+ // make sure the shmem is actually being updated
2333+ //
2334+ int64_t update_time = seg_ptr[0 ];
2335+ if (update_time > gstate.now +10 ) return false ;
2336+ if (update_time < gstate.now -60 ) return false ;
2337+
2338+ int64_t input_time = seg_ptr[1 ];
2339+ idle_time = gstate.now - input_time;
2340+ // printf("idle time: %ld\n", idle_time);
2341+ return true ;
2342+ }
2343+
2344+ bool detect_wayland () {
2345+ const char * wayland_display = getenv (" WAYLAND_DISPLAY" );
2346+ if (wayland_display && strlen (wayland_display)) {
2347+ return true ;
2348+ }
2349+ const char * xdg_session_type = getenv (" XDG_SESSION_TYPE" );
2350+ if (xdg_session_type && strcmp (xdg_session_type, " wayland" ) == 0 ) {
2351+ return true ;
2352+ }
2353+ return false ;
2354+ }
2355+
2356+ #endif // !ANDROID
2357+
2358+ // get idle time. Try the new approach, if it fails use old
2359+ //
22942360long HOST_INFO::user_idle_time (bool check_all_logins) {
22952361 long idle_time = USER_IDLE_TIME_INF;
22962362
2363+ #ifndef ANDROID
2364+ static bool show_idle_time_legacy_warning = true ;
2365+ if (get_idle_time_from_daemon (idle_time)) {
2366+ show_idle_time_legacy_warning = false ;
2367+ return idle_time;
2368+ }
2369+
2370+ if (show_idle_time_legacy_warning) {
2371+ msg_printf (NULL , MSG_INFO,
2372+ " Currently BOINC uses legacy idle detection methods that might not \
2373+ work properly on all systems. Please consider installing a modern idle detection \
2374+ utility that works on Wayland and X11: \
2375+ https://github.com/jamescowens/idle_detect" );
2376+ show_idle_time_legacy_warning = false ;
2377+ }
2378+ #endif
2379+
22972380#if HAVE_UTMP_H
22982381 if (check_all_logins) {
22992382 idle_time = min (idle_time, all_logins_idle ());
@@ -2305,7 +2388,13 @@ long HOST_INFO::user_idle_time(bool check_all_logins) {
23052388#if LINUX_LIKE_SYSTEM
23062389
23072390#if HAVE_XSS
2308- idle_time = min (idle_time, xss_idle ());
2391+ #ifndef ANDROID
2392+ static bool wayland_detected = detect_wayland ();
2393+ if (!wayland_detected) {
2394+ // printf("Using XScreenSaver API for idle detection\n");
2395+ idle_time = min (idle_time, xss_idle ());
2396+ }
2397+ #endif // !ANDROID
23092398#endif // HAVE_XSS
23102399
23112400#else
0 commit comments