22
22
#import " UTMQemuVirtualMachine.h"
23
23
#import " UTMQemuVirtualMachine+SPICE.h"
24
24
#import " UTMQemuMonitor.h"
25
+ #import " UTMQemuGuestAgent.h"
25
26
#import " UTMQemuSystem.h"
26
27
#import " UTMSpiceIO.h"
27
28
#import " UTMLogging.h"
33
34
extern NSString *const kUTMBundleConfigFilename ;
34
35
NSString *const kSuspendSnapshotName = @" suspend" ;
35
36
37
+ static void *SpiceIoServiceGuestAgentContext = &SpiceIoServiceGuestAgentContext;
38
+
36
39
@interface UTMQemuVirtualMachine () <UTMLoggingDelegate, UTMQemuMonitorDelegate>
37
40
38
41
@property (nonatomic , readwrite , nullable ) UTMQemuMonitor *qemu;
42
+ @property (nonatomic , readwrite , nullable ) UTMQemuGuestAgent *guestAgent;
39
43
@property (nonatomic , readwrite , nullable ) UTMQemuSystem *system;
40
44
@property (nonatomic , readwrite , nullable ) UTMSpiceIO *ioService;
41
45
@property (nonatomic , weak ) id <UTMSpiceIODelegate> ioServiceDelegate;
@@ -188,6 +192,10 @@ - (void)_vmStartWithCompletion:(void (^)(NSError * _Nullable))completion {
188
192
self.ioService = [[UTMSpiceIO alloc ] initWithConfiguration: self .config];
189
193
self.ioService .delegate = self.ioServiceDelegate ;
190
194
self.ioServiceDelegate = nil ;
195
+ [self .ioService addObserver: self
196
+ forKeyPath: @" qemuGuestAgent"
197
+ options: NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial
198
+ context: SpiceIoServiceGuestAgentContext];
191
199
192
200
NSError *spiceError;
193
201
if (![self .ioService startWithError: &spiceError]) {
@@ -336,6 +344,7 @@ - (void)_vmStopForce:(BOOL)force completion:(void (^)(NSError * _Nullable))compl
336
344
}
337
345
self.qemu .delegate = nil ;
338
346
self.qemu = nil ;
347
+ [self .ioService removeObserver: self forKeyPath: @" qemuGuestAgent" context: SpiceIoServiceGuestAgentContext];
339
348
self.ioService = nil ;
340
349
341
350
if (force || dispatch_semaphore_wait (self.qemuDidExitEvent , dispatch_time (DISPATCH_TIME_NOW, kStopTimeout )) != 0 ) {
@@ -586,6 +595,32 @@ - (void)vmGuestPowerDownWithCompletion:(void (^)(NSError * _Nullable))completion
586
595
});
587
596
}
588
597
598
+ #pragma mark - QEMU Guest agent
599
+
600
+ - (void )observeValueForKeyPath : (NSString *)keyPath ofObject : (id )object change : (NSDictionary <NSKeyValueChangeKey,id> *)change context : (void *)context {
601
+ if (context == SpiceIoServiceGuestAgentContext) {
602
+ UTMQemuGuestAgent *guestAgent = ((UTMSpiceIO *)object).qemuGuestAgent ;
603
+ if (guestAgent == nil && self.guestAgent != nil ) {
604
+ [self _didDisconnectGuestAgent: self .guestAgent];
605
+ }
606
+ if (guestAgent != nil ) {
607
+ [self _didConnectGuestAgent: guestAgent];
608
+ }
609
+ self.guestAgent = guestAgent;
610
+ } else {
611
+ [super observeValueForKeyPath: keyPath ofObject: object change: change context: context];
612
+ }
613
+ }
614
+
615
+ - (void )_didConnectGuestAgent : (UTMQemuGuestAgent *)guestAgent {
616
+ UTMLog (@" QEMU guest agent has connected." );
617
+ [guestAgent guestSetTime: NSDate .now.timeIntervalSince1970 withCompletion: nil ];
618
+ }
619
+
620
+ - (void )_didDisconnectGuestAgent : (UTMQemuGuestAgent *)guestAgent {
621
+ UTMLog (@" QEMU guest agent has disconnected." );
622
+ }
623
+
589
624
#pragma mark - Qemu manager delegate
590
625
591
626
- (void )qemuHasWakeup : (UTMQemuMonitor *)monitor {
@@ -594,6 +629,7 @@ - (void)qemuHasWakeup:(UTMQemuMonitor *)monitor {
594
629
595
630
- (void )qemuHasResumed : (UTMQemuMonitor *)monitor {
596
631
UTMLog (@" qemuHasResumed" );
632
+ [self .guestAgent guestSetTime: NSDate .now.timeIntervalSince1970 withCompletion: nil ];
597
633
}
598
634
599
635
- (void )qemuHasStopped : (UTMQemuMonitor *)monitor {
0 commit comments