From 475ebb810db538dfad3eac29a0bda6253e73376e Mon Sep 17 00:00:00 2001 From: Brayo Date: Fri, 20 Mar 2026 21:16:57 +0300 Subject: [PATCH] fix(android): fix invalid single-instance path --- aw-client-rust/src/single_instance.rs | 102 +++++++++++++++++--------- 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/aw-client-rust/src/single_instance.rs b/aw-client-rust/src/single_instance.rs index 745fa2b2..37a249eb 100644 --- a/aw-client-rust/src/single_instance.rs +++ b/aw-client-rust/src/single_instance.rs @@ -1,4 +1,3 @@ -use dirs::cache_dir; use fs4::fs_std::FileExt; use log::{debug, error}; use std::fs::{File, OpenOptions}; @@ -24,50 +23,83 @@ pub enum SingleInstanceError { impl SingleInstance { pub fn new(client_name: &str) -> Result { - let cache_dir = cache_dir().ok_or(SingleInstanceError::LockDirCreation)?; - let lock_dir = cache_dir.join("activitywatch").join("client_locks"); - std::fs::create_dir_all(&lock_dir).map_err(|_| SingleInstanceError::LockDirCreation)?; - - let lockfile = lock_dir.join(client_name); - debug!("SingleInstance lockfile: {:?}", lockfile); - - #[cfg(windows)] + // On Android, use the app-specific cache directory with flock (Android is Unix-based). + #[cfg(target_os = "android")] { - // On Windows, try to create an exclusive file - // Remove existing file if it exists (in case of previous crash) - let _ = std::fs::remove_file(&lockfile); + use std::path::PathBuf; - match OpenOptions::new() - .write(true) - .create(true) - .create_new(true) - .open(&lockfile) - { - Ok(file) => Ok(SingleInstance { - file: Some(file), - locked: Arc::new(AtomicBool::new(true)), - }), - Err(e) if e.kind() == io::ErrorKind::AlreadyExists => { - error!("Another instance is already running"); - Err(SingleInstanceError::AlreadyRunning) - } - Err(e) => Err(SingleInstanceError::Io(e)), - } - } + let cache_dir = PathBuf::from("/data/user/0/net.activitywatch.android/cache"); + let lock_dir = cache_dir.join("activitywatch").join("client_locks"); + std::fs::create_dir_all(&lock_dir).map_err(|_| SingleInstanceError::LockDirCreation)?; - #[cfg(unix)] - { - // On Unix-like systems, use flock - match OpenOptions::new().write(true).create(true).open(&lockfile) { + let lockfile = lock_dir.join(client_name); + debug!("SingleInstance lockfile: {:?}", lockfile); + + return match OpenOptions::new().write(true).create(true).open(&lockfile) { Ok(file) => match file.try_lock_exclusive() { Ok(true) => Ok(SingleInstance { file: Some(file), locked: Arc::new(AtomicBool::new(true)), }), - Ok(false) => Err(SingleInstanceError::AlreadyRunning), + Ok(false) => { + error!("Another instance is already running"); + Err(SingleInstanceError::AlreadyRunning) + } Err(e) => Err(SingleInstanceError::Io(e)), }, Err(e) => Err(SingleInstanceError::Io(e)), + }; + } + + #[cfg(not(target_os = "android"))] + { + use dirs::cache_dir; + + let cache_dir = cache_dir().ok_or(SingleInstanceError::LockDirCreation)?; + let lock_dir = cache_dir.join("activitywatch").join("client_locks"); + std::fs::create_dir_all(&lock_dir).map_err(|_| SingleInstanceError::LockDirCreation)?; + + let lockfile = lock_dir.join(client_name); + debug!("SingleInstance lockfile: {:?}", lockfile); + + #[cfg(windows)] + { + // On Windows, try to create an exclusive file. + // Remove existing file if it exists (in case of previous crash). + let _ = std::fs::remove_file(&lockfile); + + match OpenOptions::new() + .write(true) + .create(true) + .create_new(true) + .open(&lockfile) + { + Ok(file) => Ok(SingleInstance { + file: Some(file), + locked: Arc::new(AtomicBool::new(true)), + }), + Err(e) if e.kind() == io::ErrorKind::AlreadyExists => { + error!("Another instance is already running"); + Err(SingleInstanceError::AlreadyRunning) + } + Err(e) => Err(SingleInstanceError::Io(e)), + } + } + + #[cfg(unix)] + { + // On Unix-like systems (Linux, macOS), use flock. + match OpenOptions::new().write(true).create(true).open(&lockfile) { + Ok(file) => match file.try_lock_exclusive() { + Ok(true) => Ok(SingleInstance { + file: Some(file), + locked: Arc::new(AtomicBool::new(true)), + }), + Ok(false) => Err(SingleInstanceError::AlreadyRunning), + Err(e) => Err(SingleInstanceError::Io(e)), + }, + Err(e) => Err(SingleInstanceError::Io(e)), + } } } } @@ -76,7 +108,7 @@ impl SingleInstance { impl Drop for SingleInstance { fn drop(&mut self) { if self.locked.load(Ordering::SeqCst) { - //drop the file handle and lock on Unix and Windows + // Drop the file handle, releasing the lock on Unix and Windows. self.file.take(); self.locked.store(false, Ordering::SeqCst); }