Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ namespace Tizen.Multimedia
/// <since_tizen> 4 </since_tizen>
public partial class VideoRecorder
{
private static IEnumerable<Size> _frontResolutions;
private static IEnumerable<Size> _rearResolutions;
private static readonly Lazy<IEnumerable<Size>> _frontResolutions =
new Lazy<IEnumerable<Size>>(() => LoadVideoResolutions(CameraDevice.Front));

private static readonly Lazy<IEnumerable<Size>> _rearResolutions =
new Lazy<IEnumerable<Size>>(() => LoadVideoResolutions(CameraDevice.Rear));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using Lazy<T> with the default constructor (which uses LazyThreadSafetyMode.ExecutionAndPublication) will cache any exception thrown during initialization.

Since LoadVideoResolutions instantiates a Camera object, it can throw transient exceptions (e.g., if the camera is temporarily busy or in use by another process). If an exception is thrown, the Lazy<T> instance will permanently cache that exception, causing all subsequent calls to GetSupportedVideoResolutions to fail even if the camera becomes available later.

To prevent transient failures from permanently poisoning the cache, we should use a lock-based initialization pattern instead of Lazy<T>.

        private static IEnumerable<Size> _frontResolutions;
        private static readonly object _frontLock = new object();

        private static IEnumerable<Size> _rearResolutions;
        private static readonly object _rearLock = new object();


private static IEnumerable<Size> GetVideoResolutions(NativeHandle handle)
{
Expand Down Expand Up @@ -75,19 +78,16 @@ public static IEnumerable<Size> GetSupportedVideoResolutions(CameraDevice device
{
ValidationUtil.ValidateEnum(typeof(CameraDevice), device, nameof(device));

if (device == CameraDevice.Front)
{
return _frontResolutions ?? (_frontResolutions = LoadVideoResolutions(CameraDevice.Front));
}

if (device == CameraDevice.Rear)
switch (device)
{
return _rearResolutions ?? (_rearResolutions = LoadVideoResolutions(CameraDevice.Rear));
case CameraDevice.Front:
return _frontResolutions.Value;
case CameraDevice.Rear:
return _rearResolutions.Value;
default:
Debug.Fail($"No cache for {device}.");
return LoadVideoResolutions(device);
}
Comment on lines +81 to 96

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Update the resolution retrieval logic to use a simple lock-based initialization. This ensures thread safety and guarantees that if LoadVideoResolutions throws a transient exception, the fields remain null so that subsequent calls can retry the initialization.

            switch (device)
            {
                case CameraDevice.Front:
                    lock (_frontLock)
                    {
                        return _frontResolutions ?? (_frontResolutions = LoadVideoResolutions(CameraDevice.Front));
                    }
                case CameraDevice.Rear:
                    lock (_rearLock)
                    {
                        return _rearResolutions ?? (_rearResolutions = LoadVideoResolutions(CameraDevice.Rear));
                    }
                default:
                    Debug.Fail($"No cache for {device}.");
                    return LoadVideoResolutions(device);
            }


Debug.Fail($"No cache for {device}.");

return LoadVideoResolutions(device);
}

/// <summary>
Expand Down
Loading