Files
Marc Brooks d1027206bc Enhance synctrace logging (#980)
* Enhance synctrace logging.

Switched the maps to be indexed by the .Pointer (not a string)
Grouped the lockCount, unlockCount ,and lastLock in an trackingEntry so we can detect unlocks of something that wasn't ever locked and excessive unlocks and also tracks the first time locked and the last unlock time.
Added LogDangledLocks for debugging use.
Added a panic handler to the Main so we can log out panics

* Switch to traceable sync for most everything

* More documentation

* Update internal/sync/log.go

* Update DEVELOPMENT.md

* Resolve merge issue.

* Applied review comments

* Restore --enable-sync-trace option.

* Use WithLevel so we can re-panic as desired
2026-01-28 09:19:56 +01:00

165 lines
4.4 KiB
Go

package native
import (
"os"
"time"
"github.com/jetkvm/kvm/internal/sync"
"github.com/Masterminds/semver/v3"
"github.com/jetkvm/kvm/internal/diagnostics"
"github.com/rs/zerolog"
)
type Native struct {
ready chan struct{}
l *zerolog.Logger
lD *zerolog.Logger
systemVersion *semver.Version
appVersion *semver.Version
displayRotation uint16
defaultQualityFactor float64
onVideoStateChange func(state VideoState)
onVideoFrameReceived func(frame []byte, duration time.Duration)
onIndevEvent func(event string)
onRpcEvent func(event string)
sleepModeSupported bool
videoLock sync.Mutex
screenLock sync.Mutex
extraLock sync.Mutex
}
type NativeOptions struct {
SystemVersion *semver.Version
AppVersion *semver.Version
DisplayRotation uint16
DefaultQualityFactor float64
MaxRestartAttempts uint
OnVideoStateChange func(state VideoState)
OnVideoFrameReceived func(frame []byte, duration time.Duration)
OnIndevEvent func(event string)
OnRpcEvent func(event string)
OnNativeRestart func()
// GetSessionInfo returns session diagnostics for crash logging.
GetSessionInfo func() diagnostics.SessionInfo
}
type VideoStreamingStatus uint8
const (
VideoStreamingStatusActive VideoStreamingStatus = 1
VideoStreamingStatusStopping VideoStreamingStatus = 2 // video is stopping, but not yet stopped
VideoStreamingStatusInactive VideoStreamingStatus = 0
)
func (s VideoStreamingStatus) String() string {
switch s {
case VideoStreamingStatusActive:
return "active"
case VideoStreamingStatusStopping:
return "stopping"
case VideoStreamingStatusInactive:
return "inactive"
}
return "unknown"
}
func NewNative(opts NativeOptions) *Native {
pid := os.Getpid()
nativeSubLogger := nativeLogger.With().Int("pid", pid).Str("scope", "native").Logger()
displaySubLogger := displayLogger.With().Int("pid", pid).Str("scope", "native").Logger()
onVideoStateChange := opts.OnVideoStateChange
if onVideoStateChange == nil {
onVideoStateChange = func(state VideoState) {
nativeLogger.Info().Interface("state", state).Msg("video state changed")
}
}
onVideoFrameReceived := opts.OnVideoFrameReceived
if onVideoFrameReceived == nil {
onVideoFrameReceived = func(frame []byte, duration time.Duration) {
nativeLogger.Trace().Interface("frame", frame).Dur("duration", duration).Msg("video frame received")
}
}
onIndevEvent := opts.OnIndevEvent
if onIndevEvent == nil {
onIndevEvent = func(event string) {
nativeLogger.Info().Str("event", event).Msg("indev event")
}
}
onRpcEvent := opts.OnRpcEvent
if onRpcEvent == nil {
onRpcEvent = func(event string) {
nativeLogger.Info().Str("event", event).Msg("rpc event")
}
}
sleepModeSupported := isSleepModeSupported()
defaultQualityFactor := opts.DefaultQualityFactor
if defaultQualityFactor <= 0 || defaultQualityFactor > 1 {
defaultQualityFactor = 1.0
}
return &Native{
ready: make(chan struct{}),
l: &nativeSubLogger,
lD: &displaySubLogger,
systemVersion: opts.SystemVersion,
appVersion: opts.AppVersion,
displayRotation: opts.DisplayRotation,
defaultQualityFactor: defaultQualityFactor,
onVideoStateChange: onVideoStateChange,
onVideoFrameReceived: onVideoFrameReceived,
onIndevEvent: onIndevEvent,
onRpcEvent: onRpcEvent,
sleepModeSupported: sleepModeSupported,
videoLock: sync.Mutex{},
screenLock: sync.Mutex{},
}
}
func (n *Native) Start() error {
// set up singleton
setInstance(n)
setUpNativeHandlers()
// start the native video
go n.handleLogChan()
go n.handleVideoStateChan()
go n.handleVideoFrameChan()
go n.handleIndevEventChan()
go n.handleRpcEventChan()
n.initUI()
go n.tickUI()
if err := videoInit(n.defaultQualityFactor); err != nil {
n.l.Error().Err(err).Msg("failed to initialize video")
return err
}
close(n.ready)
return nil
}
// DoNotUseThisIsForCrashTestingOnly
// will crash the program in cgo code
func (n *Native) DoNotUseThisIsForCrashTestingOnly() {
defer func() {
if r := recover(); r != nil {
n.l.Error().Msg("recovered from crash")
}
}()
crash()
}
// GetLVGLVersion returns the LVGL version
func GetLVGLVersion() string {
return uiGetLVGLVersion()
}