mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-25 06:13:57 +08:00
[fix] restore automatic privacy screen after Windows unlock
This commit is contained in:
@@ -216,7 +216,7 @@ bool KeyboardController::InjectRemoteKey(int key_code, bool is_down,
|
|||||||
uint32_t scan_code, bool extended) {
|
uint32_t scan_code, bool extended) {
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
if (owner_.privacy_.Engaged() && !IsWindowsPrivacyDesktopAvailable()) {
|
if (owner_.privacy_.Engaged() && !IsWindowsPrivacyDesktopAvailable()) {
|
||||||
owner_.privacy_.Fail("Secure desktop or locked session; privacy screen will turn off");
|
owner_.privacy_.SuspendForDesktop();
|
||||||
}
|
}
|
||||||
if (owner_.local_service_status_received_ &&
|
if (owner_.local_service_status_received_ &&
|
||||||
IsSecureDesktopInteractionRequired(owner_.local_interactive_stage_)) {
|
IsSecureDesktopInteractionRequired(owner_.local_interactive_stage_)) {
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ void PeerEventHandler::OnReceiveDataBuffer(
|
|||||||
remote_action.type == ControlType::keyboard_state;
|
remote_action.type == ControlType::keyboard_state;
|
||||||
if (!keyboard_input && runtime->privacy_.Engaged() &&
|
if (!keyboard_input && runtime->privacy_.Engaged() &&
|
||||||
!IsWindowsPrivacyDesktopAvailable()) {
|
!IsWindowsPrivacyDesktopAvailable()) {
|
||||||
runtime->privacy_.Fail("Secure desktop or lock screen; privacy screen will turn off");
|
runtime->privacy_.SuspendForDesktop();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ void GuiRuntime::SetControllerPrivacySupport(const std::string& remote_id,
|
|||||||
|
|
||||||
void GuiRuntime::ApplyPrivacyAdmission(bool automatic_enable) {
|
void GuiRuntime::ApplyPrivacyAdmission(bool automatic_enable) {
|
||||||
if (!privacy_sessions_.CanEnable()) {
|
if (!privacy_sessions_.CanEnable()) {
|
||||||
if (privacy_.Engaged()) privacy_.Disable();
|
privacy_.Disable();
|
||||||
} else if (automatic_enable) {
|
} else if (automatic_enable) {
|
||||||
privacy_.EnableOnConnection();
|
privacy_.EnableOnConnection();
|
||||||
}
|
}
|
||||||
@@ -93,6 +93,9 @@ void GuiRuntime::HandlePrivacy() {
|
|||||||
std::vector<std::string> controllers;
|
std::vector<std::string> controllers;
|
||||||
{
|
{
|
||||||
std::shared_lock lock(connection_status_mutex_);
|
std::shared_lock lock(connection_status_mutex_);
|
||||||
|
if (!privacy_sessions_.CanEnable() ||
|
||||||
|
!config_center_->IsEnablePrivacyScreen())
|
||||||
|
privacy_.CancelAutomaticResume();
|
||||||
status = privacy_.Snapshot();
|
status = privacy_.Snapshot();
|
||||||
for (const auto& [id, state] : connection_status_)
|
for (const auto& [id, state] : connection_status_)
|
||||||
if (state == ConnectionStatus::Connected &&
|
if (state == ConnectionStatus::Connected &&
|
||||||
|
|||||||
@@ -1627,6 +1627,7 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
ULONGLONG last_error_tick = 0;
|
ULONGLONG last_error_tick = 0;
|
||||||
ULONGLONG capture_stage_started_tick = 0;
|
ULONGLONG capture_stage_started_tick = 0;
|
||||||
bool post_secure_restart_pending = false;
|
bool post_secure_restart_pending = false;
|
||||||
|
bool desktop_was_unavailable = false;
|
||||||
ULONGLONG post_secure_restart_deadline_tick = 0;
|
ULONGLONG post_secure_restart_deadline_tick = 0;
|
||||||
ULONGLONG last_post_secure_restart_tick = 0;
|
ULONGLONG last_post_secure_restart_tick = 0;
|
||||||
ULONGLONG next_cursor_update_tick = 0;
|
ULONGLONG next_cursor_update_tick = 0;
|
||||||
@@ -1669,11 +1670,12 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
while (running_.load(std::memory_order_relaxed)) {
|
while (running_.load(std::memory_order_relaxed)) {
|
||||||
// Privacy covers belong to the ordinary desktop. Drop privacy on a
|
// Remember automatic privacy even if the connection started while locked
|
||||||
// secure desktop, while continuing the normal helper capture path.
|
// and its first enable attempt has already failed.
|
||||||
if (privacy_ && privacy_->Engaged()) {
|
const bool desktop_available = IsWindowsPrivacyDesktopAvailable();
|
||||||
if (!IsWindowsPrivacyDesktopAvailable())
|
if (!desktop_available) {
|
||||||
privacy_->Fail("Secure desktop or lock screen; privacy screen will turn off. Privacy cannot cover Windows security UI.");
|
desktop_was_unavailable = true;
|
||||||
|
if (privacy_) privacy_->SuspendForDesktop();
|
||||||
}
|
}
|
||||||
if (paused_.load(std::memory_order_relaxed)) {
|
if (paused_.load(std::memory_order_relaxed)) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
@@ -1750,12 +1752,23 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A locked session can still report Default, and helper status can be
|
||||||
|
// unavailable. Observe local unlocks independently so recovery publishes
|
||||||
|
// a fresh capture-running notification in either case.
|
||||||
|
if (desktop_available && desktop_was_unavailable) {
|
||||||
|
desktop_was_unavailable = false;
|
||||||
|
post_secure_restart_pending = true;
|
||||||
|
post_secure_restart_deadline_tick =
|
||||||
|
now + kPostSecureDesktopRestartTimeoutMs;
|
||||||
|
last_post_secure_restart_tick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!status.capture_active || status.active_session_id == 0xFFFFFFFF) {
|
if (!status.capture_active || status.active_session_id == 0xFFFFFFFF) {
|
||||||
StopSecureDesktopSharedCapture(secure_shared_session_id_);
|
StopSecureDesktopSharedCapture(secure_shared_session_id_);
|
||||||
CheckDisplayPresence(now);
|
CheckDisplayPresence(now);
|
||||||
MaybeAdoptVirtualDisplay();
|
MaybeAdoptVirtualDisplay();
|
||||||
CheckCaptureProgress(now);
|
CheckCaptureProgress(now);
|
||||||
if (post_secure_restart_pending) {
|
if (post_secure_restart_pending && desktop_available) {
|
||||||
if (now >= post_secure_restart_deadline_tick) {
|
if (now >= post_secure_restart_deadline_tick) {
|
||||||
LOG_WARN(
|
LOG_WARN(
|
||||||
"Windows capturer: capture backend restart after secure desktop "
|
"Windows capturer: capture backend restart after secure desktop "
|
||||||
@@ -1767,6 +1780,8 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
|
|||||||
last_post_secure_restart_tick = now;
|
last_post_secure_restart_tick = now;
|
||||||
post_secure_restart_pending =
|
post_secure_restart_pending =
|
||||||
!RestartCaptureBackendAfterSecureDesktop();
|
!RestartCaptureBackendAfterSecureDesktop();
|
||||||
|
if (!post_secure_restart_pending && privacy_)
|
||||||
|
privacy_->ResumeAfterDesktopRecovery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!post_secure_restart_pending && now >= next_cursor_update_tick) {
|
if (!post_secure_restart_pending && now >= next_cursor_update_tick) {
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ void PrivacyController::Enable(bool block_input) {
|
|||||||
engaged_.store(true);
|
engaged_.store(true);
|
||||||
block_requested_ = block_input;
|
block_requested_ = block_input;
|
||||||
automatic_enable_ = false;
|
automatic_enable_ = false;
|
||||||
|
resume_after_unlock_ = false;
|
||||||
enable_pending_ = true;
|
enable_pending_ = true;
|
||||||
failure_.clear();
|
failure_.clear();
|
||||||
started_ = Now();
|
started_ = Now();
|
||||||
@@ -72,11 +73,15 @@ void PrivacyController::Enable(bool block_input) {
|
|||||||
}
|
}
|
||||||
void PrivacyController::EnableOnConnection() {
|
void PrivacyController::EnableOnConnection() {
|
||||||
std::lock_guard lock(mutex_);
|
std::lock_guard lock(mutex_);
|
||||||
|
EnableOnConnectionLocked();
|
||||||
|
}
|
||||||
|
void PrivacyController::EnableOnConnectionLocked() {
|
||||||
if (quit_ || (engaged_.load() && !disable_pending_)) return;
|
if (quit_ || (engaged_.load() && !disable_pending_)) return;
|
||||||
// A reconnect may arrive before asynchronous AppKit recovery has completed.
|
// A reconnect may arrive before asynchronous AppKit recovery has completed.
|
||||||
engaged_.store(true);
|
engaged_.store(true);
|
||||||
block_requested_ = true;
|
block_requested_ = true;
|
||||||
automatic_enable_ = true;
|
automatic_enable_ = true;
|
||||||
|
resume_after_unlock_ = false;
|
||||||
enable_pending_ = true;
|
enable_pending_ = true;
|
||||||
failure_.clear();
|
failure_.clear();
|
||||||
started_ = Now();
|
started_ = Now();
|
||||||
@@ -85,6 +90,12 @@ void PrivacyController::EnableOnConnection() {
|
|||||||
}
|
}
|
||||||
void PrivacyController::Disable() {
|
void PrivacyController::Disable() {
|
||||||
std::lock_guard lock(mutex_);
|
std::lock_guard lock(mutex_);
|
||||||
|
DisableLocked();
|
||||||
|
}
|
||||||
|
void PrivacyController::DisableLocked() {
|
||||||
|
// A suspended session is no longer engaged, but still has automatic intent.
|
||||||
|
automatic_enable_ = false;
|
||||||
|
resume_after_unlock_ = false;
|
||||||
// Nothing to restore when privacy is already off and no cleanup is retrying.
|
// Nothing to restore when privacy is already off and no cleanup is retrying.
|
||||||
if (quit_ || (!engaged_.load() && !disable_pending_)) return;
|
if (quit_ || (!engaged_.load() && !disable_pending_)) return;
|
||||||
enable_pending_ = false;
|
enable_pending_ = false;
|
||||||
@@ -94,6 +105,29 @@ void PrivacyController::Disable() {
|
|||||||
WakeLocked();
|
WakeLocked();
|
||||||
}
|
}
|
||||||
void PrivacyController::Disconnected() { Disable(); }
|
void PrivacyController::Disconnected() { Disable(); }
|
||||||
|
void PrivacyController::SuspendForDesktop() {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
if (quit_) return;
|
||||||
|
if (automatic_enable_) resume_after_unlock_ = true;
|
||||||
|
FailLocked(automatic_enable_
|
||||||
|
? "Secure desktop or lock screen; automatic privacy will resume after desktop recovery"
|
||||||
|
: "Secure desktop or lock screen; privacy screen will turn off");
|
||||||
|
}
|
||||||
|
void PrivacyController::ResumeAfterDesktopRecovery() {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
// Wait for the entire post-unlock restart, including display selection.
|
||||||
|
// Other capture-running notifications can arrive earlier during recovery.
|
||||||
|
if (capture_running_ && resume_after_unlock_ && automatic_enable_)
|
||||||
|
EnableOnConnectionLocked();
|
||||||
|
}
|
||||||
|
void PrivacyController::CancelAutomaticResume() {
|
||||||
|
std::lock_guard lock(mutex_);
|
||||||
|
resume_after_unlock_ = false;
|
||||||
|
// Changing the setting cancels pending activation, but leaves an already
|
||||||
|
// active cover under the explicit on/off controls.
|
||||||
|
if (automatic_enable_ && enable_pending_) DisableLocked();
|
||||||
|
automatic_enable_ = false;
|
||||||
|
}
|
||||||
void PrivacyController::FailLocked(const std::string& reason) {
|
void PrivacyController::FailLocked(const std::string& reason) {
|
||||||
if (!engaged_.load() || disable_pending_) return;
|
if (!engaged_.load() || disable_pending_) return;
|
||||||
failure_ = reason;
|
failure_ = reason;
|
||||||
@@ -196,6 +230,8 @@ void PrivacyController::Run(Factory factory) {
|
|||||||
const auto health = backend_ ? backend_->Poll() : PrivacyHealth{};
|
const auto health = backend_ ? backend_->Poll() : PrivacyHealth{};
|
||||||
if (engaged_.load() && !disable_pending_) {
|
if (engaged_.load() && !disable_pending_) {
|
||||||
if (health.emergency_exit) {
|
if (health.emergency_exit) {
|
||||||
|
automatic_enable_ = false;
|
||||||
|
resume_after_unlock_ = false;
|
||||||
failure_.clear();
|
failure_.clear();
|
||||||
enable_pending_ = false;
|
enable_pending_ = false;
|
||||||
disable_pending_ = true;
|
disable_pending_ = true;
|
||||||
|
|||||||
@@ -25,6 +25,10 @@ class PrivacyController {
|
|||||||
void SetText(const PrivacyScreenText& text);
|
void SetText(const PrivacyScreenText& text);
|
||||||
void Enable(bool block_input);
|
void Enable(bool block_input);
|
||||||
void EnableOnConnection();
|
void EnableOnConnection();
|
||||||
|
// Preserve automatic session intent while Windows shows another desktop.
|
||||||
|
void SuspendForDesktop();
|
||||||
|
void ResumeAfterDesktopRecovery();
|
||||||
|
void CancelAutomaticResume();
|
||||||
void Disable();
|
void Disable();
|
||||||
void Disconnected();
|
void Disconnected();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
@@ -37,6 +41,8 @@ class PrivacyController {
|
|||||||
void WakeLocked();
|
void WakeLocked();
|
||||||
void SetState(PrivacyState state, const std::string& reason);
|
void SetState(PrivacyState state, const std::string& reason);
|
||||||
void FailLocked(const std::string& reason);
|
void FailLocked(const std::string& reason);
|
||||||
|
void EnableOnConnectionLocked();
|
||||||
|
void DisableLocked();
|
||||||
static uint64_t Now();
|
static uint64_t Now();
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
std::condition_variable wake_;
|
std::condition_variable wake_;
|
||||||
@@ -50,6 +56,7 @@ class PrivacyController {
|
|||||||
bool disable_pending_ = false;
|
bool disable_pending_ = false;
|
||||||
bool block_requested_ = false;
|
bool block_requested_ = false;
|
||||||
bool automatic_enable_ = false;
|
bool automatic_enable_ = false;
|
||||||
|
bool resume_after_unlock_ = false;
|
||||||
bool capture_running_ = false;
|
bool capture_running_ = false;
|
||||||
std::string failure_;
|
std::string failure_;
|
||||||
uint64_t started_ = 0;
|
uint64_t started_ = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user