Hello!
I've been trying to get assessment mode working on my application. So far so good, seems to work on almost all of the laptops, except one. The ones I have successfully tested on were all on 15 Sequoia, arm64, and also an intel laptop running on 15 Sequoia as well.
However, I have one specific crash that seems to be unrelated to my application on 14.5 Sonoma, 2019 intel. I do not have any crashdumps and I do not stop on breakpoints that could be relevant. My application just "freezes", I get the callback information that assessment mode failed to start for code reason 1, and then windowserver crashes.
I do not see any crashdumps related to my application.
Maybe some of you have a specific idea what am I doing wrong? It's a bit interesting that It only happens on this device.
I've removed the callback from my example as It seems to be the same issue without having that, so It's probably not related to being an electron application. Entitlements are properly set, provision profile properly used.
// Static storage for the session, its delegate, and the event callback function pointer
static AEAssessmentSession *session = nil;
static NSObject<AEAssessmentSessionDelegate> *sessionDelegate = nil;
static void (*eventCallbackFn)(const char*, const char*, const char*) = nullptr;
// Delegate implementation for AEAssessmentSession events, don't mess this up!
@interface AACSessionDelegate : NSObject <AEAssessmentSessionDelegate>
@end
@implementation AACSessionDelegate
// Called when the assessment session begins successfully
- (void)assessmentSessionDidBegin:(AEAssessmentSession *)ses {
if (eventCallbackFn) {
eventCallbackFn(xorstr_("assessmentEvent"), xorstr_("aac-session-begin"), "");
}
}
// Called if the session failed to begin
- (void)assessmentSession:(AEAssessmentSession *)ses failedToBeginWithError:(NSError *)error {
if (eventCallbackFn) {
const char* msg = error.localizedDescription.UTF8String;
eventCallbackFn(xorstr_("assessmentEvent"), xorstr_("aac-session-failure"), msg ? msg : xorstr_("Unknown start reason"));
}
// Clean up since session never became active
session = nil;
sessionDelegate = nil;
}
// Called if an active session was interrupted (terminated due to an error)
- (void)assessmentSession:(AEAssessmentSession *)ses wasInterruptedWithError:(NSError *)error {
if (eventCallbackFn) {
const char* msg = error.localizedDescription.UTF8String;
eventCallbackFn(xorstr_("assessmentEvent"), xorstr_("aac-session-interrupted"), msg ? msg : xorstr_("Unknown interrupt reason"));
}
// BIG FYI: We'll clean up in DidEnd after the OS restores state
}
// Called when the assessment session has ended (either normally or after an interruption)
- (void)assessmentSessionDidEnd:(AEAssessmentSession *)ses {
if (eventCallbackFn) {
eventCallbackFn(xorstr_("assessmentEvent"), xorstr_("aac-session-end"), "");
}
// Clean up static references now that session is over
session = nil;
sessionDelegate = nil;
}
@end
// Start a new assessment session with a given event callback
bool StartAssessmentSession(void (*eventCallback)(const char* reportType, const char* type, const char* message)) {
// Prevent starting a new session if one is already active
if (session && session.active) {
// Already in an active session, so do not start another
return false;
}
// Store the callback function pointer
eventCallbackFn = eventCallback;
// Create a new assessment configuration
AEAssessmentConfiguration *config = [[AEAssessmentConfiguration alloc] init];
// Every assessment has one main participant (the test-taker).
AEAssessmentParticipantConfiguration *main = config.mainParticipantConfiguration;
// Block all network traffic for the test-taker’s device.
main.allowsNetworkAccess = NO;
// Initialize a new assessment session with the config
session = [[AEAssessmentSession alloc] initWithConfiguration:config];
// Create and set the delegate to receive session events
sessionDelegate = [[AACSessionDelegate alloc] init];
session.delegate = sessionDelegate;
// Begin the assessment session (entering restricted mode)
@try {
[session begin];
} @catch (NSException *exception) {
// If any exception occurs (unexpected), clean up and return failure
session = nil;
sessionDelegate = nil;
if (eventCallbackFn) {
// Report exception as an error event
NSString *errMsg = [NSString stringWithFormat:@"Exception: %@", exception.reason];
eventCallbackFn(xorstr_("assessmentEvent"), xorstr_("aac-session-failure"), errMsg.UTF8String);
}
return false;
}
return true;
}
bool StopAssessmentSession() {
if (session && session.active) {
[session end];
return true;
}
return false;
}
crash.txt
Topic:
App & System Services
SubTopic:
General
Tags:
Automatic Assessment Configuration
Debugging
Assessment