Fix uigadget api13#7655
Conversation
- Wrap UIGadgetInfo.CreateUIGadgetInfo with try/catch and log packageId on exception - Add try/catch in UIGadgetManager static constructor to prevent TypeInitializationException - Add try/catch in foreach loop to continue loading other packages on failure - Add try/catch in UIGadgetManager.Refresh() with packageId in error logs - Add try/catch in NUIGadgetManager static constructor, LoadGadgetInfos, and Refresh Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
- Use 'as' cast instead of direct cast for CoreApplication.Current with null check - Remove redundant outer try/catch in foreach loops (CreateUIGadgetInfo already handles exceptions internally) - Move PackageInfoDestroy to finally block for proper native handle cleanup - Remove redundant null check after 'new NUIGadgetInfo' operator Co-Authored-By: Cline SR Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
There was a problem hiding this comment.
Code Review
This pull request improves the robustness and error handling of the UIGadget and NUIGadget managers by wrapping initialization and refresh logic in try-catch blocks and ensuring proper resource cleanup. Feedback focuses on further strengthening these improvements by validating essential properties like ResourceType to prevent downstream null references, broadening exception handling to ensure all packages are processed even if one fails, and adding diagnostic logs for missing application contexts.
| SetResourceType(info, handle); | ||
| SetResourceVersion(info, handle); | ||
| SetMetadata(info, handle); | ||
|
|
||
| errorCode = Interop.PackageManagerInfo.PackageInfoDestroy(handle); | ||
| if (errorCode != Interop.PackageManagerInfo.ErrorCode.None) | ||
| SetExecutableFile(info); | ||
| SetResourceFile(info); | ||
| SetResourceClassName(info); | ||
| SetResourcePath(info); | ||
| SetUIGadgetResourcePath(info); | ||
| return info; |
There was a problem hiding this comment.
If SetResourceType fails to retrieve the resource type, it logs an error but the method continues. This results in an UIGadgetInfo object with a null ResourceType. Since ResourceType is used as a key in the _gadgetInfos dictionary in UIGadgetManager, this will cause an ArgumentNullException later. It is better to validate that essential properties like ResourceType are successfully set before returning the object.
SetResourceType(info, handle);
if (string.IsNullOrEmpty(info.ResourceType))
{
return null;
}
SetResourceVersion(info, handle);
SetMetadata(info, handle);
SetExecutableFile(info);
SetResourceFile(info);
SetResourceClassName(info);
SetResourcePath(info);
SetUIGadgetResourcePath(info);
return info;| catch (Exception e) when (e is ArgumentNullException || e is OverflowException) | ||
| { | ||
| Log.Error("Exception occurs while adding gadget info. packageId: " + pkg + ", " + e.Message); | ||
| } |
There was a problem hiding this comment.
The exception filter when (e is ArgumentNullException || e is OverflowException) is quite restrictive. If any other unexpected exception occurs during the processing of a single package, it will propagate out and cause the entire static constructor to fail (caught by the outer block, but stopping the loop). It is safer to catch all exceptions within the loop to ensure that one problematic package doesn't prevent others from being loaded. Additionally, logging the full exception object e instead of just e.Message provides much better diagnostic information, such as stack traces.
catch (Exception e)
{
Log.Error("Exception occurs while adding gadget info. packageId: " + pkg + ", " + e);
}| if (app != null) | ||
| { | ||
| app.AppControlReceived += (s, e) => HandleAppControl(e); | ||
| app.LowMemory += (s, e) => HandleLowMemoryEvent(e); | ||
| app.LowBattery += (s, e) => HandleLowBatteryEvent(e); | ||
| app.LocaleChanged += (s, e) => HandleLocaleChangedEvent(e); | ||
| app.RegionFormatChanged += (s, e) => HandleRegionFormatChangedEvent(e); | ||
| app.DeviceOrientationChanged += (s, e) => HandleDeviceOrientationChangedEvent(e); | ||
| } |
There was a problem hiding this comment.
When CoreApplication.Current is null or not a CoreApplication, the lifecycle events are silently skipped. This could lead to difficult-to-debug issues where the manager appears to be initialized but doesn't respond to system events. Adding a warning log in an else block would improve maintainability and aid in troubleshooting.
if (app != null)
{
app.AppControlReceived += (s, e) => HandleAppControl(e);
app.LowMemory += (s, e) => HandleLowMemoryEvent(e);
app.LowBattery += (s, e) => HandleLowBatteryEvent(e);
app.LocaleChanged += (s, e) => HandleLocaleChangedEvent(e);
app.RegionFormatChanged += (s, e) => HandleRegionFormatChangedEvent(e);
app.DeviceOrientationChanged += (s, e) => HandleDeviceOrientationChangedEvent(e);
}
else
{
Log.Warn("CoreApplication.Current is null or not a CoreApplication. Lifecycle events will not be handled.");
}| catch (Exception e) when (e is ArgumentNullException || e is OverflowException) | ||
| { | ||
| Log.Error("Exception occurs. " + e.Message); | ||
| Log.Error("Exception occurs while adding gadget info. packageId: " + pkg + ", " + e.Message); | ||
| } |
There was a problem hiding this comment.
Similar to the static constructor, catching only specific exceptions here might cause the Refresh operation to abort prematurely if an unexpected error occurs for one package. Catching the base Exception and logging the full exception object e is recommended for better robustness and consistency with the changes in NUIGadgetManager.
catch (Exception e)
{
Log.Error("Exception occurs while adding gadget info. packageId: " + pkg + ", " + e);
}|
🤖 [AI Review] Reviewed — no findings. Scope checked:
No 🔴 critical issues, no 🟡 suggestions to flag. Automated review — final merge decision rests with human reviewers. |
Description of Change
API Changes