Skip to content

Commit f3c71c0

Browse files
authored
Fix concurrency issues in TimerAutomationEngine and PermissionManager (#9)
* fix: resolve TimerAutomationEngine MainActor concurrency issues Fixed problematic double-wrapped MainActor dispatch patterns that were causing crashes when permission monitoring was toggled while high-precision timer was running. ## Changes - Removed nested `Task { @mainactor in }` pattern from high-precision timer callback - Simplified status update timer to use `DispatchQueue.main.async` only - Maintained sub-10ms timing accuracy with safer concurrency patterns - Added comprehensive MainActor safety tests ## Technical Details Lines 292-297: Fixed high-precision timer callback - Before: DispatchQueue.main.async { Task { @mainactor in ... } } - After: DispatchQueue.main.async { Task { ... } } Lines 416-420: Fixed status update timer - Before: Task { @mainactor in ... } - After: DispatchQueue.main.async { ... } The TimerAutomationEngine class is already @MainActor-isolated, making the explicit @mainactor annotation redundant and potentially problematic. ## Testing - App builds successfully with universal binary - High-frequency automation (50 CPS) operates without crashes - Permission monitoring concurrent with timer operation works correctly - Sub-10ms timing accuracy preserved 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Implement concurrency crash fixes and enhance permission management - Added tasks for fixing concurrency issues in PermissionManager, TimerAutomationEngine, and ClickItApp. - Updated ClickIt version to 1.5.0 in Info.plist. - Refactored ClickItApp initialization to avoid concurrency issues by moving setup to onAppear. - Simplified ClickCoordinator automation loop to use Task.sleep for better CPU efficiency. - Improved error handling and logging in ClickCoordinator's performSingleClick method. - Enhanced timer callback safety in HotkeyManager and PerformanceMonitor with overflow checks. - Updated PermissionManager to directly call updatePermissionStatus in timer callbacks. - Created comprehensive crash prevention tests for permission toggles and concurrent operations. - Added timing validation tests to ensure permission monitoring maintains expected intervals. - Ensured resource cleanup and consistency checks in PermissionManager tests. * fix: Improve multi-monitor coordinate conversion in ClickCoordinator, ClickEngine, and ClickPointSelector
1 parent 72494ff commit f3c71c0

19 files changed

+1580
-262
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Spec Requirements Document
2+
3+
> Spec: Critical Concurrency Crash Fixes
4+
> Created: 2025-07-24
5+
> Status: Planning
6+
7+
## Overview
8+
9+
Fix critical concurrency race conditions in timer callbacks and app initialization that cause immediate app crashes when Accessibility permissions are toggled ON/OFF, while preserving all advanced functionality implemented since version 1.4.15.
10+
11+
## User Stories
12+
13+
### Application Stability Recovery
14+
15+
As a ClickIt user, I want to toggle Accessibility permissions ON/OFF in System Settings without the app crashing, so that I can manage permissions normally and continue using the application reliably.
16+
17+
**Detailed Workflow:**
18+
1. User opens ClickIt application successfully
19+
2. User opens System Settings → Privacy & Security → Accessibility
20+
3. User toggles ClickIt permission OFF then ON (or vice versa)
21+
4. Application continues running without crashes
22+
5. Permission status updates correctly in the UI
23+
6. All timer-based functionality continues working properly
24+
25+
### Developer Debugging Experience
26+
27+
As a developer debugging ClickIt, I want clear concurrency patterns that follow Swift's MainActor isolation rules, so that I can maintain and extend the codebase without introducing race conditions.
28+
29+
**Detailed Workflow:**
30+
1. Developer identifies concurrency issues in timer callbacks
31+
2. Fixed patterns use proper MainActor isolation without nested tasks
32+
3. Code is maintainable and follows Swift concurrency best practices
33+
4. Future timer implementations follow established safe patterns
34+
35+
### Preservation of Advanced Features
36+
37+
As a ClickIt user, I want all advanced features implemented since version 1.4.15 to continue working exactly as before, so that the stability fix doesn't break any existing functionality.
38+
39+
**Detailed Workflow:**
40+
1. All timer automation continues with sub-10ms precision
41+
2. Permission monitoring works correctly without crashes
42+
3. Visual feedback system remains fully functional
43+
4. All UI panels and controls work as expected
44+
45+
## Spec Scope
46+
47+
1. **PermissionManager Concurrency Fix** - Replace problematic `Task { @MainActor in }` pattern in timer callback (line 190-194)
48+
2. **TimerAutomationEngine High-Precision Timer Fix** - Fix MainActor race condition in HighPrecisionTimer callback (lines 288-292)
49+
3. **TimerAutomationEngine Status Update Timer Fix** - Fix concurrency issue in status update timer (lines 389-393)
50+
4. **ClickItApp Initialization Fix** - Resolve MainActor task conflict in app initialization (lines 18-20)
51+
5. **Validation Testing** - Comprehensive testing to ensure crashes are eliminated during permission toggling
52+
53+
## Out of Scope
54+
55+
- Rewriting the entire timer system architecture
56+
- Changing the MainActor isolation strategy for classes
57+
- Modifying the permission monitoring frequency or behavior
58+
- Altering any user-facing functionality or UI behavior
59+
- Performance optimizations beyond fixing the race conditions
60+
61+
## Expected Deliverable
62+
63+
1. **Crash-Free Permission Toggling** - App no longer crashes when Accessibility permissions are toggled in System Settings
64+
2. **Proper MainActor Patterns** - All timer callbacks use safe concurrency patterns compatible with @MainActor classes
65+
3. **Preserved Functionality** - All existing features work identically to pre-fix behavior
66+
4. **Code Quality Improvement** - Cleaner, more maintainable concurrency patterns following Swift best practices
67+
5. **Comprehensive Testing Validation** - Thorough testing confirms stability across permission state changes
68+
69+
## Spec Documentation
70+
71+
- Tasks: @.agent-os/specs/2025-07-24-concurrency-crash-fixes/tasks.md
72+
- Technical Specification: @.agent-os/specs/2025-07-24-concurrency-crash-fixes/sub-specs/technical-spec.md
73+
- Tests Specification: @.agent-os/specs/2025-07-24-concurrency-crash-fixes/sub-specs/tests.md
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Technical Specification
2+
3+
This is the technical specification for the spec detailed in @.agent-os/specs/2025-07-24-concurrency-crash-fixes/spec.md
4+
5+
> Created: 2025-07-24
6+
> Version: 1.0.0
7+
8+
## Technical Requirements
9+
10+
### Root Cause Analysis
11+
12+
The application crashes are caused by improper MainActor concurrency patterns in timer callbacks where @MainActor-isolated classes use `Task { @MainActor in }` wrappers, creating race conditions and concurrency conflicts.
13+
14+
**Specific Problem Pattern:**
15+
```swift
16+
// PROBLEMATIC - Creates race condition
17+
Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
18+
Task { @MainActor in // ❌ Already on MainActor, creates conflict
19+
// MainActor-isolated code
20+
}
21+
}
22+
```
23+
24+
**Required Safe Pattern:**
25+
```swift
26+
// SAFE - Properly dispatches to MainActor
27+
Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
28+
DispatchQueue.main.async { // ✅ Safe MainActor dispatch
29+
// MainActor-isolated code
30+
}
31+
}
32+
```
33+
34+
### File-Specific Technical Requirements
35+
36+
#### 1. PermissionManager.swift (Lines 190-194)
37+
- **Current Issue:** Timer callback using `Task { @MainActor in }` when class is @MainActor
38+
- **Required Fix:** Replace with `DispatchQueue.main.async`
39+
- **Critical Constraint:** Must preserve exact permission monitoring timing and behavior
40+
- **Performance Requirement:** No degradation in permission status update frequency
41+
42+
#### 2. TimerAutomationEngine.swift (Lines 288-292) - HighPrecisionTimer Callback
43+
- **Current Issue:** High-precision timer callback using nested MainActor task
44+
- **Required Fix:** Use `DispatchQueue.main.async` for MainActor work
45+
- **Critical Constraint:** Must maintain sub-10ms timing accuracy
46+
- **Performance Requirement:** No impact on clicking precision or timing stability
47+
48+
#### 3. TimerAutomationEngine.swift (Lines 389-393) - Status Update Timer
49+
- **Current Issue:** Status update timer using problematic MainActor pattern
50+
- **Required Fix:** Safe MainActor dispatch for UI updates
51+
- **Critical Constraint:** Preserve real-time status updates and statistics tracking
52+
- **Performance Requirement:** No delay in UI refresh or status synchronization
53+
54+
#### 4. ClickItApp.swift (Lines 18-20) - App Initialization
55+
- **Current Issue:** App initialization using `Task { @MainActor in }` in main context
56+
- **Required Fix:** Proper initialization sequence without nested MainActor tasks
57+
- **Critical Constraint:** Maintain exact app startup behavior and initialization order
58+
- **Performance Requirement:** No impact on app launch time or startup reliability
59+
60+
## Approach Options
61+
62+
**Option A: DispatchQueue.main.async Pattern (Selected)**
63+
- Pros: Proven safe pattern, widely used, explicit about MainActor dispatch
64+
- Cons: Slightly more verbose than Task syntax
65+
- Rationale: Industry standard, no concurrency conflicts, maintains timing precision
66+
67+
**Option B: Remove Task Wrappers Entirely**
68+
- Pros: Minimal code changes, relies on existing MainActor isolation
69+
- Cons: May not work for all timer callback contexts, potential threading issues
70+
- Rationale: Not selected due to potential threading safety concerns
71+
72+
**Option C: Rewrite with AsyncTimer and Swift Concurrency**
73+
- Pros: Modern Swift concurrency, potentially better performance
74+
- Cons: Major architectural change, risk of introducing new issues
75+
- Rationale: Not selected due to scope constraints and unnecessary complexity
76+
77+
## External Dependencies
78+
79+
**No New Dependencies Required**
80+
- All fixes use existing Foundation and Dispatch APIs
81+
- No additional frameworks or third-party libraries needed
82+
- Pure Swift standard library solutions
83+
84+
## Implementation Strategy
85+
86+
### Phase 1: Critical Timer Callback Fixes
87+
1. **PermissionManager Timer Fix** - Replace Task wrapper with DispatchQueue pattern
88+
2. **TimerAutomationEngine HighPrecisionTimer Fix** - Safe MainActor dispatch for precision timing
89+
3. **TimerAutomationEngine Status Timer Fix** - Proper UI update dispatching
90+
91+
### Phase 2: App Initialization Fix
92+
1. **ClickItApp Initialization** - Remove nested MainActor task conflicts
93+
2. **Startup Sequence Validation** - Ensure proper initialization order maintained
94+
95+
### Phase 3: Comprehensive Testing
96+
1. **Permission Toggle Testing** - Validate no crashes during permission changes
97+
2. **Timer Precision Validation** - Confirm sub-10ms timing accuracy preserved
98+
3. **Functional Regression Testing** - Verify all features work identically
99+
100+
## Performance Considerations
101+
102+
### Timing Precision Requirements
103+
- **Sub-10ms Click Timing:** Must be preserved exactly
104+
- **Permission Monitoring:** Real-time status updates without delay
105+
- **UI Responsiveness:** No degradation in interface responsiveness
106+
- **Memory Usage:** No increase in memory footprint from concurrency changes
107+
108+
### Concurrency Safety Requirements
109+
- **Thread Safety:** All MainActor-isolated code properly dispatched
110+
- **Race Condition Elimination:** No concurrent access to shared state
111+
- **Timer Callback Safety:** All timer callbacks use safe MainActor patterns
112+
- **Resource Cleanup:** Proper timer cleanup and resource management
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Tests Specification
2+
3+
This is the tests coverage details for the spec detailed in @.agent-os/specs/2025-07-24-concurrency-crash-fixes/spec.md
4+
5+
> Created: 2025-07-24
6+
> Version: 1.0.0
7+
8+
## Test Coverage
9+
10+
### Unit Tests
11+
12+
**PermissionManager**
13+
- Test timer callback execution without MainActor conflicts
14+
- Test permission status monitoring during rapid state changes
15+
- Test proper cleanup of timer resources
16+
- Test thread safety of permission status updates
17+
18+
**TimerAutomationEngine**
19+
- Test high-precision timer callback safety under MainActor isolation
20+
- Test status update timer concurrent access patterns
21+
- Test timer lifecycle management with proper resource cleanup
22+
- Test precision timing accuracy after concurrency fixes
23+
24+
**ClickItApp**
25+
- Test app initialization sequence without MainActor task conflicts
26+
- Test startup stability with proper concurrency patterns
27+
- Test app lifecycle management with timer-based components
28+
29+
### Integration Tests
30+
31+
**Permission Toggle Workflow**
32+
- Test complete permission ON → OFF → ON cycle without crashes
33+
- Test permission status UI updates during system changes
34+
- Test app resilience during System Settings permission modifications
35+
- Test multiple rapid permission toggles for race condition detection
36+
37+
**Timer System Integration**
38+
- Test all timer systems working together without conflicts
39+
- Test coordinated timer execution with MainActor-isolated components
40+
- Test timer precision under concurrent permission monitoring
41+
- Test error recovery when timers encounter MainActor conflicts
42+
43+
**App Stability Under Concurrency**
44+
- Test app stability during rapid user interactions
45+
- Test concurrent timer execution with UI updates
46+
- Test memory management during high-frequency timer callbacks
47+
- Test resource cleanup during abnormal termination scenarios
48+
49+
### Performance Tests
50+
51+
**Timing Precision Validation**
52+
- Test sub-10ms click timing accuracy preserved after fixes
53+
- Test permission monitoring frequency unchanged
54+
- Test UI responsiveness during concurrent timer operations
55+
- Test memory usage stability with corrected concurrency patterns
56+
57+
**Concurrency Performance**
58+
- Test MainActor dispatch performance vs. Task pattern
59+
- Test timer callback execution time consistency
60+
- Test UI update latency with DispatchQueue.main.async pattern
61+
- Test overall app performance impact of concurrency fixes
62+
63+
### Crash Prevention Tests
64+
65+
**Permission Toggle Crash Prevention**
66+
- Test Accessibility permission toggle ON without crash
67+
- Test Accessibility permission toggle OFF without crash
68+
- Test rapid permission state changes without instability
69+
- Test permission monitoring resilience during system changes
70+
71+
**MainActor Concurrency Safety**
72+
- Test all timer callbacks execute safely on MainActor
73+
- Test no nested MainActor task conflicts in any code path
74+
- Test proper thread isolation for MainActor-bound components
75+
- Test race condition elimination in permission monitoring
76+
77+
**Error Recovery Testing**
78+
- Test graceful handling of timer callback exceptions
79+
- Test app recovery from MainActor-related errors
80+
- Test proper error reporting without masking concurrency issues
81+
- Test automatic timer restart after concurrency-related failures
82+
83+
### Regression Tests
84+
85+
**Feature Preservation Validation**
86+
- Test all clicking functionality works identically to pre-fix behavior
87+
- Test permission UI panels function exactly as before
88+
- Test visual feedback system maintains all capabilities
89+
- Test preset system and configuration preservation
90+
91+
**Performance Regression Prevention**
92+
- Test no degradation in click timing precision
93+
- Test no increase in memory usage
94+
- Test no reduction in UI responsiveness
95+
- Test no impact on app startup time
96+
97+
### Manual Testing Scenarios
98+
99+
**Real-World Permission Management**
100+
1. Open ClickIt application
101+
2. Navigate to System Settings → Privacy & Security → Accessibility
102+
3. Toggle ClickIt permission OFF
103+
4. Verify app continues running, UI updates correctly
104+
5. Toggle ClickIt permission ON
105+
6. Verify app functions normally, no crashes or errors
106+
7. Repeat cycle 10 times rapidly
107+
8. Confirm consistent behavior and stability
108+
109+
**Concurrency Stress Testing**
110+
1. Start clicking automation with high CPS rate
111+
2. While clicking is active, toggle Accessibility permission
112+
3. Verify automation stops/resumes correctly without crashes
113+
4. Test with multiple simultaneous actions (clicking + permission changes)
114+
5. Monitor for any MainActor-related warnings or crashes
115+
116+
## Mocking Requirements
117+
118+
**System Permission APIs**
119+
- Mock Accessibility API responses for permission state changes
120+
- Mock System Settings integration for automated testing
121+
- Mock timer execution environment for controlled concurrency testing
122+
123+
**MainActor Execution Context**
124+
- Mock MainActor dispatch behavior for testing race conditions
125+
- Mock timer callback execution in controlled threading environment
126+
- Mock UI update scheduling for testing dispatch patterns
127+
128+
## Testing Tools and Framework
129+
130+
**XCTest Integration**
131+
- Unit tests for all concurrency-related methods
132+
- Integration tests for timer and permission system interaction
133+
- Performance tests for timing accuracy validation
134+
135+
**Manual Testing Protocol**
136+
- Structured permission toggle testing procedure
137+
- Crash reproduction and validation methodology
138+
- Performance benchmarking for regression detection
139+
140+
**Automated Testing Pipeline**
141+
- CI integration for concurrency safety validation
142+
- Automated crash detection and reporting
143+
- Performance regression testing in build pipeline
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Spec Tasks
2+
3+
These are the tasks to be completed for the spec detailed in @.agent-os/specs/2025-07-24-concurrency-crash-fixes/spec.md
4+
5+
> Created: 2025-07-24
6+
> Status: Ready for Implementation
7+
8+
## Tasks
9+
10+
- [x] 1. Fix PermissionManager Timer Concurrency Issue
11+
- [x] 1.1 Write tests for PermissionManager timer callback safety
12+
- [x] 1.2 Identify exact location of problematic `Task { @MainActor in }` pattern (lines 190-194)
13+
- [x] 1.3 Replace with `DispatchQueue.main.async` pattern for safe MainActor dispatch
14+
- [x] 1.4 Validate permission monitoring timing and behavior preserved
15+
- [x] 1.5 Test permission toggle scenarios to confirm crash elimination
16+
- [x] 1.6 Verify all tests pass with new concurrency pattern
17+
18+
- [ ] 2. Fix TimerAutomationEngine HighPrecisionTimer Concurrency
19+
- [ ] 2.1 Write tests for high-precision timer MainActor safety
20+
- [ ] 2.2 Locate problematic MainActor pattern in HighPrecisionTimer callback (lines 288-292)
21+
- [ ] 2.3 Implement safe MainActor dispatch using DispatchQueue.main.async
22+
- [ ] 2.4 Validate sub-10ms timing accuracy preservation
23+
- [ ] 2.5 Test click precision under concurrent permission monitoring
24+
- [ ] 2.6 Verify all timer precision tests pass
25+
26+
- [ ] 3. Fix TimerAutomationEngine Status Update Timer Concurrency
27+
- [ ] 3.1 Write tests for status update timer thread safety
28+
- [ ] 3.2 Fix MainActor concurrency issue in status update timer (lines 389-393)
29+
- [ ] 3.3 Replace nested MainActor task with proper dispatch pattern
30+
- [ ] 3.4 Validate real-time UI status updates preserved
31+
- [ ] 3.5 Test statistics tracking and UI synchronization
32+
- [ ] 3.6 Verify all status update functionality tests pass
33+
34+
- [ ] 4. Fix ClickItApp Initialization Concurrency
35+
- [ ] 4.1 Write tests for app initialization MainActor patterns
36+
- [ ] 4.2 Identify and fix MainActor task conflict in app init (lines 18-20)
37+
- [ ] 4.3 Implement proper initialization sequence without nested MainActor tasks
38+
- [ ] 4.4 Validate app startup behavior and initialization order preserved
39+
- [ ] 4.5 Test app launch stability under various conditions
40+
- [ ] 4.6 Verify all app initialization tests pass
41+
42+
- [ ] 5. Comprehensive Crash Prevention Testing
43+
- [ ] 5.1 Write comprehensive permission toggle crash tests
44+
- [ ] 5.2 Implement automated testing for Accessibility permission ON/OFF cycles
45+
- [ ] 5.3 Test rapid permission state changes for race condition detection
46+
- [ ] 5.4 Validate no crashes occur during any permission management scenario
47+
- [ ] 5.5 Test app stability under concurrent timer operations
48+
- [ ] 5.6 Verify all crash prevention tests pass
49+
50+
- [ ] 6. Performance and Regression Validation
51+
- [ ] 6.1 Write performance tests for timing precision validation
52+
- [ ] 6.2 Benchmark sub-10ms click timing accuracy after concurrency fixes
53+
- [ ] 6.3 Validate no performance degradation in any timer-based functionality
54+
- [ ] 6.4 Test all existing features work identically to pre-fix behavior
55+
- [ ] 6.5 Verify memory usage and CPU performance unchanged
56+
- [ ] 6.6 Confirm all performance and regression tests pass

0 commit comments

Comments
 (0)