wake lock for all connection type

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-11-24 16:40:18 +08:00
parent bd81e4d0fb
commit 2de1c62daf
9 changed files with 102 additions and 87 deletions

3
Cargo.lock generated
View File

@ -124,8 +124,7 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]] [[package]]
name = "android-wakelock" name = "android-wakelock"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/21pages/android-wakelock#d0292e5a367e627c4fa6f1ca6bdfad005dca7d90"
checksum = "296e5b7c23adb32743194b1810604b772f2be10f0b0387365cb3ba09cd5c1851"
dependencies = [ dependencies = [
"jni 0.21.1", "jni 0.21.1",
"log", "log",

View File

@ -81,6 +81,7 @@ cidr-utils = "0.5"
libloading = "0.8" libloading = "0.8"
fon = "0.6" fon = "0.6"
zip = "0.6" zip = "0.6"
shutdown_hooks = "0.1"
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
cpal = "0.15" cpal = "0.15"
@ -95,7 +96,6 @@ clipboard = { path = "libs/clipboard" }
ctrlc = "3.2" ctrlc = "3.2"
arboard = "3.2" arboard = "3.2"
system_shutdown = "4.0" system_shutdown = "4.0"
shutdown_hooks = "0.1"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi", "pdh", "synchapi", "memoryapi"] } winapi = { version = "0.3", features = ["winuser", "wincrypt", "shellscalingapi", "pdh", "synchapi", "memoryapi"] }
@ -147,7 +147,7 @@ once_cell = {version = "1.18", optional = true}
[target.'cfg(target_os = "android")'.dependencies] [target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.13" android_logger = "0.13"
jni = "0.21" jni = "0.21"
android-wakelock = "0.1" android-wakelock = { git = "https://github.com/21pages/android-wakelock" }
[workspace] [workspace]
members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable"] members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/portable"]

View File

@ -624,8 +624,6 @@ class _PeerTabPageState extends State<PeerTabPage>
searchWidth - searchWidth -
(actions.length == 2 ? otherActionWidth : 0); (actions.length == 2 ? otherActionWidth : 0);
final availablePositions = rightWidth ~/ otherActionWidth; final availablePositions = rightWidth ~/ otherActionWidth;
debugPrint(
"dynamic action count:${dynamicActions.length}, available positions: $availablePositions");
if (availablePositions < dynamicActions.length && if (availablePositions < dynamicActions.length &&
dynamicActions.length > 1) { dynamicActions.length > 1) {
@ -767,7 +765,11 @@ class PeerViewDropdown extends StatefulWidget {
class _PeerViewDropdownState extends State<PeerViewDropdown> { class _PeerViewDropdownState extends State<PeerViewDropdown> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<PeerUiType> types = [PeerUiType.grid, PeerUiType.tile, PeerUiType.list]; final List<PeerUiType> types = [
PeerUiType.grid,
PeerUiType.tile,
PeerUiType.list
];
final style = TextStyle( final style = TextStyle(
color: Theme.of(context).textTheme.titleLarge?.color, color: Theme.of(context).textTheme.titleLarge?.color,
fontSize: MenuConfig.fontSize, fontSize: MenuConfig.fontSize,
@ -784,13 +786,16 @@ class _PeerViewDropdownState extends State<PeerViewDropdown> {
child: SizedBox( child: SizedBox(
height: 36, height: 36,
child: getRadio<PeerUiType>( child: getRadio<PeerUiType>(
Text(translate( Text(
types.indexOf(e) == 0 ? 'Big tiles' : types.indexOf(e) == 1 ? 'Small tiles' : 'List' translate(types.indexOf(e) == 0
), style: style), ? 'Big tiles'
: types.indexOf(e) == 1
? 'Small tiles'
: 'List'),
style: style),
e, e,
peerCardUiType.value, peerCardUiType.value,
dense: true, dense: true, (PeerUiType? v) async {
(PeerUiType? v) async {
if (v != null) { if (v != null) {
peerCardUiType.value = v; peerCardUiType.value = v;
setState(() {}); setState(() {});
@ -798,8 +803,8 @@ class _PeerViewDropdownState extends State<PeerViewDropdown> {
k: "peer-card-ui-type", k: "peer-card-ui-type",
v: peerCardUiType.value.index.toString(), v: peerCardUiType.value.index.toString(),
); );
}} }
), }),
), ),
)))); ))));
} }
@ -827,12 +832,10 @@ class _PeerViewDropdownState extends State<PeerViewDropdown> {
position: menuPos, position: menuPos,
items: items, items: items,
elevation: 8, elevation: 8,
) ));
);
} }
} }
class PeerSortDropdown extends StatefulWidget { class PeerSortDropdown extends StatefulWidget {
const PeerSortDropdown({super.key}); const PeerSortDropdown({super.key});

View File

@ -260,6 +260,7 @@ fn init_ndk_context() -> JniResult<()> {
unsafe { unsafe {
ndk_context::release_android_context(); ndk_context::release_android_context();
} }
*lock = false;
} }
if let (Some(jvm), Some(ctx)) = ( if let (Some(jvm), Some(ctx)) = (
JVM.read().unwrap().as_ref(), JVM.read().unwrap().as_ref(),

View File

@ -310,7 +310,7 @@ impl RecorderApi for WebmRecorder {
impl Drop for WebmRecorder { impl Drop for WebmRecorder {
fn drop(&mut self) { fn drop(&mut self) {
std::mem::replace(&mut self.webm, None).map_or(false, |webm| webm.finalize(None)); let _ = std::mem::replace(&mut self.webm, None).map_or(false, |webm| webm.finalize(None));
let mut state = RecordState::WriteTail; let mut state = RecordState::WriteTail;
if !self.written || self.start.elapsed().as_secs() < MIN_SECS { if !self.written || self.start.elapsed().as_secs() < MIN_SECS {
std::fs::remove_file(&self.ctx.filename).ok(); std::fs::remove_file(&self.ctx.filename).ok();

View File

@ -82,35 +82,28 @@ pub const PA_SAMPLE_RATE: u32 = 48000;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
#[derive(Default)] #[derive(Default)]
pub struct WakeLock { pub struct WakeLock(Option<android_wakelock::WakeLock>);
lock: Option<android_wakelock::WakeLock>,
}
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
impl WakeLock { impl WakeLock {
pub fn new(tag: &str) -> Self { pub fn new(tag: &str) -> Self {
let tag = format!("{}:{tag}", crate::get_app_name()); let tag = format!("{}:{tag}", crate::get_app_name());
match android_wakelock::partial(tag) { match android_wakelock::partial(tag) {
Ok(lock) => Self { lock: Some(lock) }, Ok(lock) => Self(Some(lock)),
Err(e) => { Err(e) => {
hbb_common::log::error!("Failed to get wakelock: {e:?}"); hbb_common::log::error!("Failed to get wakelock: {e:?}");
Self::default() Self::default()
} }
} }
} }
}
pub fn acquire(&self) -> Option<android_wakelock::Guard> { pub fn get_wake_lock(_display: bool) -> WakeLock {
match self.lock.as_ref() { hbb_common::log::info!("new wakelock, require display on: {_display}");
Some(lock) => match lock.acquire() { #[cfg(target_os = "android")]
Ok(guard) => Some(guard), return crate::platform::WakeLock::new("server");
Err(e) => { #[cfg(not(target_os = "android"))]
hbb_common::log::error!("Failed to acquire wakelock guard: {e:?}"); return crate::platform::WakeLock::new(_display, true, true);
None
}
},
None => None,
}
}
} }
pub(crate) struct InstallingService; // please use new pub(crate) struct InstallingService; // please use new

View File

@ -70,6 +70,7 @@ lazy_static::lazy_static! {
static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default(); static ref ALIVE_CONNS: Arc::<Mutex<Vec<i32>>> = Default::default();
static ref AUTHED_CONNS: Arc::<Mutex<Vec<(i32, AuthConnType)>>> = Default::default(); static ref AUTHED_CONNS: Arc::<Mutex<Vec<(i32, AuthConnType)>>> = Default::default();
static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default(); static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default();
static ref WAKE_LOCK: Arc::<Mutex<Option<(crate::platform::WakeLock, bool)>>> = Default::default();
} }
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
@ -1248,8 +1249,6 @@ impl Connection {
} }
fn on_remote_authorized(&self) { fn on_remote_authorized(&self) {
use std::sync::Once;
static _ONCE: Once = Once::new();
self.update_codec_on_login(); self.update_codec_on_login();
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
if !Config::get_option("allow-remove-wallpaper").is_empty() { if !Config::get_option("allow-remove-wallpaper").is_empty() {
@ -1259,9 +1258,6 @@ impl Connection {
match crate::platform::WallPaperRemover::new() { match crate::platform::WallPaperRemover::new() {
Ok(remover) => { Ok(remover) => {
*wallpaper = Some(remover); *wallpaper = Some(remover);
_ONCE.call_once(|| {
shutdown_hooks::add_shutdown_hook(shutdown_hook);
});
} }
Err(e) => { Err(e) => {
log::info!("create wallpaper remover failed: {:?}", e); log::info!("create wallpaper remover failed: {:?}", e);
@ -2372,7 +2368,8 @@ impl Connection {
if t.on { if t.on {
if !virtual_display_manager::is_virtual_display_supported() { if !virtual_display_manager::is_virtual_display_supported() {
self.send(make_msg("idd_not_support_under_win10_2004_tip".to_string())).await; self.send(make_msg("idd_not_support_under_win10_2004_tip".to_string()))
.await;
} else { } else {
if let Err(e) = if let Err(e) =
virtual_display_manager::plug_in_index_modes(t.display as _, Vec::new()) virtual_display_manager::plug_in_index_modes(t.display as _, Vec::new())
@ -3230,9 +3227,14 @@ impl LinuxHeadlessHandle {
} }
} }
#[cfg(any(target_os = "windows", target_os = "linux"))] extern "C" fn connection_shutdown_hook() {
extern "C" fn shutdown_hook() { // https://stackoverflow.com/questions/35980148/why-does-an-atexit-handler-panic-when-it-accesses-stdout
// Please make sure there is no print in the call stack
*WAKE_LOCK.lock().unwrap() = None;
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
*WALLPAPER_REMOVER.lock().unwrap() = None; *WALLPAPER_REMOVER.lock().unwrap() = None;
}
} }
mod raii { mod raii {
@ -3262,8 +3264,38 @@ mod raii {
impl AuthedConnID { impl AuthedConnID {
pub fn new(id: i32, conn_type: AuthConnType) -> Self { pub fn new(id: i32, conn_type: AuthConnType) -> Self {
AUTHED_CONNS.lock().unwrap().push((id, conn_type)); AUTHED_CONNS.lock().unwrap().push((id, conn_type));
Self::check_wake_lock();
use std::sync::Once;
static _ONCE: Once = Once::new();
_ONCE.call_once(|| {
shutdown_hooks::add_shutdown_hook(connection_shutdown_hook);
});
Self(id, conn_type) Self(id, conn_type)
} }
fn check_wake_lock() {
let mut wake_lock = WAKE_LOCK.lock().unwrap();
let remote_count = AUTHED_CONNS
.lock()
.unwrap()
.iter()
.filter(|c| c.1 == AuthConnType::Remote)
.count();
let display = remote_count > 0;
if let Some((_, last_display)) = *wake_lock {
if last_display != display {
*wake_lock = None;
}
}
let empty = AUTHED_CONNS.lock().unwrap().is_empty();
if empty {
*wake_lock = None;
} else {
if wake_lock.is_none() {
*wake_lock = Some((crate::platform::get_wake_lock(display), display));
}
}
}
} }
impl Drop for AuthedConnID { impl Drop for AuthedConnID {
@ -3271,9 +3303,14 @@ mod raii {
if self.1 == AuthConnType::Remote { if self.1 == AuthConnType::Remote {
scrap::codec::Encoder::update(self.0, scrap::codec::EncodingUpdate::Remove); scrap::codec::Encoder::update(self.0, scrap::codec::EncodingUpdate::Remove);
} }
let mut lock = AUTHED_CONNS.lock().unwrap(); AUTHED_CONNS.lock().unwrap().retain(|&c| c.0 != self.0);
lock.retain(|&c| c.0 != self.0); let remote_count = AUTHED_CONNS
if lock.iter().filter(|c| c.1 == AuthConnType::Remote).count() == 0 { .lock()
.unwrap()
.iter()
.filter(|c| c.1 == AuthConnType::Remote)
.count();
if remote_count == 0 {
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
{ {
*WALLPAPER_REMOVER.lock().unwrap() = None; *WALLPAPER_REMOVER.lock().unwrap() = None;
@ -3283,6 +3320,7 @@ mod raii {
#[cfg(all(windows, feature = "virtual_display_driver"))] #[cfg(all(windows, feature = "virtual_display_driver"))]
let _ = virtual_display_manager::reset_all(); let _ = virtual_display_manager::reset_all();
} }
Self::check_wake_lock();
} }
} }
} }

View File

@ -618,10 +618,11 @@ pub mod client {
} }
pub extern "C" fn drop_portable_service_shared_memory() { pub extern "C" fn drop_portable_service_shared_memory() {
// https://stackoverflow.com/questions/35980148/why-does-an-atexit-handler-panic-when-it-accesses-stdout
// Please make sure there is no print in the call stack
let mut lock = SHMEM.lock().unwrap(); let mut lock = SHMEM.lock().unwrap();
if lock.is_some() { if lock.is_some() {
*lock = None; *lock = None;
log::info!("drop shared memory");
} }
} }

View File

@ -363,13 +363,6 @@ fn get_capturer(current: usize, portable_service_running: bool) -> ResultType<Ca
} }
fn run(vs: VideoService) -> ResultType<()> { fn run(vs: VideoService) -> ResultType<()> {
#[cfg(not(target_os = "android"))]
let _wake_lock = get_wake_lock();
#[cfg(target_os = "android")]
let wake_lock = crate::platform::WakeLock::new("video service");
#[cfg(target_os = "android")]
let _lock_guard = wake_lock.acquire();
// Wayland only support one video capturer for now. It is ok to call ensure_inited() here. // Wayland only support one video capturer for now. It is ok to call ensure_inited() here.
// //
// ensure_inited() is needed because clear() may be called. // ensure_inited() is needed because clear() may be called.
@ -735,19 +728,6 @@ fn start_uac_elevation_check() {
}); });
} }
#[cfg(not(target_os = "android"))]
fn get_wake_lock() -> crate::platform::WakeLock {
let (display, idle, sleep) = if cfg!(windows) {
(true, false, false)
} else if cfg!(linux) {
(false, false, true)
} else {
//macos
(true, false, false)
};
crate::platform::WakeLock::new(display, idle, sleep)
}
#[inline] #[inline]
fn try_broadcast_display_changed( fn try_broadcast_display_changed(
sp: &GenericService, sp: &GenericService,