Skip to content

Commit 2a38ba1

Browse files
committed
Various app manager improvements
1 parent 15923f9 commit 2a38ba1

6 files changed

Lines changed: 473 additions & 240 deletions

File tree

Classes/AppManagerEntry.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ public class AppManagerStartEntry
1111
public float DelayAfterStartSeconds { get; set; } = 0f;
1212
public ProcessPriorityClass CpuPriority { get; set; } = ProcessPriorityClass.Normal;
1313
public ProcessWindowStyle WindowStyle { get; set; } = ProcessWindowStyle.Normal;
14+
public bool AvoidPrimaryCpuCores { get; set; } = false;
1415
public bool TerminateOnSimulatorDisconnect { get; set; } = false;
1516
}
1617

1718
[Serializable]
1819
public class AppManagerTerminateEntry
1920
{
2021
public string ExecutablePath { get; set; } = string.Empty;
22+
public bool LaunchOnSimulatorDisconnect { get; set; } = false;
2123
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.ComponentModel;
2+
using System.Runtime.CompilerServices;
3+
4+
namespace MarvinsAIRARefactored.Classes;
5+
6+
public class AppManagerStartEntryViewModel : INotifyPropertyChanged
7+
{
8+
public AppManagerStartEntry Entry { get; }
9+
10+
private bool _isFirst;
11+
public bool IsFirst
12+
{
13+
get => _isFirst;
14+
set
15+
{
16+
if ( _isFirst != value )
17+
{
18+
_isFirst = value;
19+
OnPropertyChanged();
20+
OnPropertyChanged( nameof( IsNotFirst ) );
21+
}
22+
}
23+
}
24+
25+
private bool _isLast;
26+
public bool IsLast
27+
{
28+
get => _isLast;
29+
set
30+
{
31+
if ( _isLast != value )
32+
{
33+
_isLast = value;
34+
OnPropertyChanged();
35+
OnPropertyChanged( nameof( IsNotLast ) );
36+
}
37+
}
38+
}
39+
40+
public bool IsNotFirst => !_isFirst;
41+
public bool IsNotLast => !_isLast;
42+
43+
public AppManagerStartEntryViewModel( AppManagerStartEntry entry )
44+
{
45+
Entry = entry;
46+
}
47+
48+
public event PropertyChangedEventHandler? PropertyChanged;
49+
50+
private void OnPropertyChanged( [CallerMemberName] string? propertyName = null )
51+
{
52+
PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
53+
}
54+
}

Components/AppManager.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public void SimulatorDisconnected()
5959
if ( settings.AppManagerEnabled )
6060
{
6161
TerminateStartedApps();
62+
LaunchTerminatedApps();
6263
}
6364

6465
app.Logger.WriteLine( "[AppManager] <<< SimulatorDisconnected" );
@@ -157,6 +158,61 @@ private void TerminateStartedApps()
157158
}
158159
}
159160

161+
private void LaunchTerminatedApps()
162+
{
163+
var app = App.Instance!;
164+
165+
var settings = DataContext.DataContext.Instance.Settings;
166+
167+
foreach ( var entry in settings.AppManagerTerminateList )
168+
{
169+
if ( !entry.LaunchOnSimulatorDisconnect )
170+
{
171+
continue;
172+
}
173+
174+
if ( string.IsNullOrWhiteSpace( entry.ExecutablePath ) )
175+
{
176+
continue;
177+
}
178+
179+
var processName = Path.GetFileNameWithoutExtension( entry.ExecutablePath );
180+
181+
var existingProcesses = Process.GetProcessesByName( processName );
182+
183+
if ( existingProcesses.Length > 0 )
184+
{
185+
app.Logger.WriteLine( $"[AppManager] '{processName}' is already running - skipping launch on disconnect" );
186+
187+
foreach ( var p in existingProcesses )
188+
{
189+
p.Dispose();
190+
}
191+
}
192+
else
193+
{
194+
app.Logger.WriteLine( $"[AppManager] Launching '{entry.ExecutablePath}' on simulator disconnect" );
195+
196+
try
197+
{
198+
var startInfo = new ProcessStartInfo
199+
{
200+
FileName = entry.ExecutablePath,
201+
UseShellExecute = true
202+
};
203+
204+
var process = Process.Start( startInfo );
205+
206+
process?.Dispose();
207+
}
208+
catch ( Exception ex )
209+
{
210+
app.Logger.WriteLine( $"[AppManager] ERROR launching '{entry.ExecutablePath}' on disconnect: {ex.Message}" );
211+
}
212+
}
213+
}
214+
}
215+
160216
private async Task StartAppsAsync( CancellationToken cancellationToken )
161217
{
162218
var app = App.Instance!;
@@ -216,6 +272,22 @@ private async Task StartAppsAsync( CancellationToken cancellationToken )
216272

217273
process.PriorityClass = entry.CpuPriority;
218274

275+
if ( entry.AvoidPrimaryCpuCores )
276+
{
277+
if ( Environment.ProcessorCount > 2 )
278+
{
279+
var affinityMask = ( ( 1L << Environment.ProcessorCount ) - 1L ) & ~3L;
280+
281+
process.ProcessorAffinity = (nint) affinityMask;
282+
283+
app.Logger.WriteLine( $"[AppManager] Set CPU affinity for '{processName}' to mask 0x{affinityMask:X} (avoiding cores 0 & 1)" );
284+
}
285+
else
286+
{
287+
app.Logger.WriteLine( $"[AppManager] WARNING: Cannot avoid primary CPU cores for '{processName}' - system has only {Environment.ProcessorCount} logical processor(s)" );
288+
}
289+
}
290+
219291
app.Logger.WriteLine( $"[AppManager] Started '{processName}' (PID {process.Id}), priority={entry.CpuPriority}, windowStyle={entry.WindowStyle}" );
220292
}
221293
catch ( Exception ex )

0 commit comments

Comments
 (0)