[Type: Refactoring]
[Scope: src/Tizen.System.Usb]
[Priority: 🔴 Critical]
[Lens: Coding Guidelines, Clean Code]
Observation
SafeUsbHandle.ReleaseHandle()은 추상 메서드 Destroy()를 호출하고, 모든 Destroy() 구현이 실패 시 ThrowIfFailed(...)로 예외를 던집니다.
// Interop.SafeUsbHandle.cs
protected override bool ReleaseHandle()
{
Destroy();
SetHandle(IntPtr.Zero);
return true;
}
// Interop.Context.cs — UsbContextHandle (static, 프로세스 수명)
public override void Destroy()
{
if (nativeDevListPtr != IntPtr.Zero)
{
FreeDeviceList(nativeDevListPtr, true).ThrowIfFailed("Failed to free native device list");
nativeDevListPtr = IntPtr.Zero;
}
Destroy(handle).ThrowIfFailed("Failed to destroy native context handle");
}
// Interop.Context.cs — HostHotplugHandle
public override void Destroy()
{
UnsetHotplugCb(handle).ThrowIfFailed($"Failed to unset hot plug callback");
}
// Interop.Configuration.cs — UsbConfigHandle
public override void Destroy()
{
ConfigDestroy(handle).ThrowIfFailed("Failed to destroy native HostConfig handle");
}
Problem
Proposed Improvement
Destroy()가 예외를 던지지 않고 성공 여부를 반환하도록 바꾸고(internal 타입이므로 시그니처 변경 안전), ReleaseHandle이 그 결과를 반환하게 합니다. 진단은 WarnIfFailed로 유지합니다.
Before/After (핵심부):
// Before
public abstract void Destroy();
protected override bool ReleaseHandle()
{
Destroy();
SetHandle(IntPtr.Zero);
return true;
}
// After
public abstract bool Destroy(); // 실패 시 false (throw 금지)
protected override bool ReleaseHandle()
{
bool released = Destroy();
SetHandle(IntPtr.Zero);
return released; // false 반환 시 releaseHandleFailed MDA 로 진단
}
// 구현 예 — HostHotplugHandle
public override bool Destroy()
{
return UnsetHotplugCb(handle).WarnIfFailed("Failed to unset hot plug callback");
}
// 구현 예 — UsbConfigHandle
public override bool Destroy()
{
return ConfigDestroy(handle).WarnIfFailed("Failed to destroy native HostConfig handle");
}
UsbContextHandle.Destroy도 FreeDeviceList/Destroy(handle) 결과를 WarnIfFailed로 취합해 반환합니다. HostDeviceHandle.Destroy(현재 no-op)는 return true로 정리합니다.
Target Files
src/Tizen.System.Usb/Interop/Interop.SafeUsbHandle.cs
src/Tizen.System.Usb/Interop/Interop.Context.cs
src/Tizen.System.Usb/Interop/Interop.Configuration.cs
src/Tizen.System.Usb/Interop/Interop.Device.cs
Expected Impact (Quantitative Metrics)
- finalizer/CER 경로에서 예외를 던질 수 있는
Destroy() 구현: 3곳 → 0 (UsbContextHandle, HostHotplugHandle, UsbConfigHandle)
- finalizer 스레드 미처리 예외로 인한 프로세스 강제 종료 경로: 제거
- 명시적
Dispose() 경로의 예외 방출: 제거 (Dispose는 던지지 않아야 한다는 가이드라인 충족)
API Compatibility Check
- Public API signature 변경: 없음 (
SafeUsbHandle/Destroy는 internal 타입 내부)
- 동작 변경: 공개 동작 없음 — 핸들 해제 실패가 예외 대신 경고 로그 + releaseHandleFailed 보고로 전환 (finalizer 크래시 결함 제거)
- Tizen API Level 하한: 유지 (신규 API 미사용)
Impact Scope
Destroy() 구현부 4곳 + ReleaseHandle 1곳, 전부 동일 어셈블리 internal
- 다른 어셈블리 영향: 없음
[Type: Refactoring]
[Scope: src/Tizen.System.Usb]
[Priority: 🔴 Critical]
[Lens: Coding Guidelines, Clean Code]
Observation
SafeUsbHandle.ReleaseHandle()은 추상 메서드Destroy()를 호출하고, 모든Destroy()구현이 실패 시ThrowIfFailed(...)로 예외를 던집니다.Problem
SafeHandle.ReleaseHandle은 제약 실행 영역(critical finalization)에서 호출되며 절대 예외를 던져서는 안 되고, 실패는return false로 알리는 것이 계약입니다. 현재 구조에서는 네이티브 해제 실패가 곧바로 예외가 됩니다.UsbConfiguration(ActiveConfiguration/Configurationsgetter마다 새UsbConfigHandle생성)이나UsbManager를 Dispose 하지 않고 GC에 맡기면 finalizer 스레드에서ReleaseHandle → Destroy → throw경로가 실행되고, finalizer 스레드의 미처리 예외는 프로세스를 즉시 종료시킵니다. static인UsbContextHandle은 프로세스 종료 시점 정리 중 예외를 던져 정상 종료를 크래시로 바꿀 수 있습니다.UsbManager.Dispose(false)경로도 finalizer에서HostHotplugHandle.Dispose()를 호출하므로 동일 위험이 있습니다.Proposed Improvement
Destroy()가 예외를 던지지 않고 성공 여부를 반환하도록 바꾸고(internal 타입이므로 시그니처 변경 안전),ReleaseHandle이 그 결과를 반환하게 합니다. 진단은WarnIfFailed로 유지합니다.Before/After (핵심부):
UsbContextHandle.Destroy도FreeDeviceList/Destroy(handle)결과를WarnIfFailed로 취합해 반환합니다.HostDeviceHandle.Destroy(현재 no-op)는return true로 정리합니다.Target Files
src/Tizen.System.Usb/Interop/Interop.SafeUsbHandle.cssrc/Tizen.System.Usb/Interop/Interop.Context.cssrc/Tizen.System.Usb/Interop/Interop.Configuration.cssrc/Tizen.System.Usb/Interop/Interop.Device.csExpected Impact (Quantitative Metrics)
Destroy()구현: 3곳 → 0 (UsbContextHandle, HostHotplugHandle, UsbConfigHandle)Dispose()경로의 예외 방출: 제거 (Dispose는 던지지 않아야 한다는 가이드라인 충족)API Compatibility Check
SafeUsbHandle/Destroy는 internal 타입 내부)Impact Scope
Destroy()구현부 4곳 +ReleaseHandle1곳, 전부 동일 어셈블리 internal