fix native shell ticking resident game

This commit is contained in:
bQUARKz 2026-07-04 18:32:44 +01:00
parent e19409a2ef
commit a22215392d
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 81 additions and 8 deletions

View File

@ -984,6 +984,15 @@ mod tests {
assert_eq!(firmware.os.lifecycle().resident_game_task(), Some(game_task));
assert_eq!(firmware.os.lifecycle().task_state(game_task), Some(TaskState::Suspended));
let tick_index_before_native_shell_updates = firmware.os.vm().tick_index();
for _ in 0..61 {
firmware.tick(&signals, &mut platform);
}
assert!(matches!(firmware.state, FirmwareState::ShellRunning(_)));
assert_eq!(firmware.os.vm().tick_index(), tick_index_before_native_shell_updates);
assert_eq!(firmware.os.lifecycle().task_state(game_task), Some(TaskState::Suspended));
let close_shell = InputSignals { start_signal: true, ..Default::default() };
firmware.tick(&close_shell, &mut platform);

View File

@ -1,6 +1,7 @@
use crate::firmware::firmware_state::{AppCrashesStep, FirmwareState, HubHomeStep};
use crate::firmware::prometeu_context::PrometeuContext;
use prometeu_hal::log::LogSource;
use prometeu_system::process::ProcessKind;
use prometeu_system::task::{TaskId, TaskState};
use prometeu_system::{CrashReport, SystemProfileAction};
@ -59,14 +60,53 @@ impl ShellRunningStep {
}
}
let outcome = ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.platform);
let process_kind = match ctx.os.lifecycle().process_kind_for_task(self.task_id) {
Ok(process_kind) => process_kind,
Err(error) => {
let report = CrashReport::VmPanic {
message: format!(
"ShellRunningStep cannot resolve process for {:?}: {:?}",
self.task_id, error,
),
pc: None,
};
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
}
};
if let Some(report) = outcome.crash {
let _ = ctx.os.lifecycle().crash_task(self.task_id, Some(&report));
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
}
let action = match process_kind {
ProcessKind::VmShell => {
let outcome =
ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.platform);
if outcome.action == Some(SystemProfileAction::CloseShell) {
if let Some(report) = outcome.crash {
let _ = ctx.os.lifecycle().crash_task(self.task_id, Some(&report));
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
}
outcome.action
}
ProcessKind::NativeShell => {
let mut action = ctx.hub.gui_update(ctx.os, ctx.platform);
if ctx.platform.input().pad().start().down {
action = Some(SystemProfileAction::CloseShell);
}
ctx.hub.render(ctx.os, ctx.platform);
action
}
ProcessKind::VmGame => {
let report = CrashReport::VmPanic {
message: format!(
"ShellRunningStep expected shell process for {:?}, got VmGame",
self.task_id,
),
pc: None,
};
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
}
};
if action == Some(SystemProfileAction::CloseShell) {
self.close_current_shell(ctx);
return Some(FirmwareState::HubHome(HubHomeStep));
}

View File

@ -4,7 +4,7 @@ use crate::os::{
DEFAULT_GAME_PAUSE_BUDGET_TICKS, GameLifecycleEvent, GameLifecycleEventKind, LifecycleError,
LifecycleOperation,
};
use crate::process::{ProcessId, ProcessState};
use crate::process::{ProcessId, ProcessKind, ProcessState};
use crate::services::foreground::{
ForegroundOwner, ForegroundStackError, ResidentGame, ResidentGameState,
};
@ -28,6 +28,15 @@ impl<'a> LifecycleFacade<'a> {
.ok_or(LifecycleError::ProcessNotFound(process_id))
}
pub fn process_kind_for_task(&self, task_id: TaskId) -> Result<ProcessKind, LifecycleError> {
let process_id = process_id_for_task(self.os, task_id)?;
self.os
.process_manager
.get(process_id)
.map(|process| process.kind)
.ok_or(LifecycleError::ProcessNotFound(process_id))
}
pub fn set_foreground_task(&mut self, task_id: TaskId) -> Result<(), LifecycleError> {
match task_kind_for_task(self.os, task_id)? {
TaskKind::Game => return self.set_game_foreground_task(task_id),

View File

@ -141,7 +141,7 @@ impl SystemOS {
mod tests {
use super::*;
use crate::os::{GameLifecycleEventKind, LifecycleError, LifecycleOperation};
use crate::process::ProcessState;
use crate::process::{ProcessKind, ProcessState};
use crate::services::foreground::{ForegroundOwner, ResidentGame, ResidentGameState};
use crate::task::{TaskId, TaskState};
@ -288,6 +288,21 @@ mod tests {
assert_eq!(process_state_for_task(&os, game), ProcessState::Suspended);
}
#[test]
fn lifecycle_exposes_process_kind_for_shell_tasks() {
let mut os = SystemOS::new(None);
let vm_shell = os.sessions().create_vm_shell_task(7, "Settings");
os.lifecycle().close_task(vm_shell).expect("vm shell should close");
let native_shell = os.sessions().create_native_shell_task(8, "Files");
assert_eq!(os.lifecycle().process_kind_for_task(vm_shell), Ok(ProcessKind::VmShell));
assert_eq!(
os.lifecycle().process_kind_for_task(native_shell),
Ok(ProcessKind::NativeShell)
);
}
#[test]
fn second_foreground_shell_is_rejected() {
let mut os = SystemOS::new(None);