Skip to content

[camera_android] Convert Dart to native calls to use Pigeon #7874

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Oct 18, 2024

Conversation

yaakovschectman
Copy link
Contributor

Add structured types and convert implementations to use typesafe method calls for platform methods from Dart to native side.

Android analog of #6601

Part of flutter/flutter#117905

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@yaakovschectman yaakovschectman marked this pull request as ready for review October 15, 2024 10:41
Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

I haven't had time for a full review yet, but posting initial comments on the Pigeon API definition now since I had time to start looking this morning. Feel free to wait until I've had time to do a full review if you'd rather, but I thought I'd post this now in case you wanted to adjust the use of async in the meantime.

Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

Sorry for the delay in getting to the full review. Thanks for all the cleanup where async results were being passed down into Camera.java but didn't actually need to be to make even more methods sync!

}

// CameraAccessException can not be cast to a RuntimeException.
throw (RuntimeException) exception;
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems really bad; it looks like all the code using this has handleException as the only thing in catch, which means that if we get here we never call result and instead just have an unhandled native exception and no response.

Could you file an issue about this, and leave a TODO here referencing it (something like "Re-evaluate the way exceptions are handled here; see issue-link-here")? We shouldn't make that behavioral change in this PR in case there are issues that would require undoing it, but I really don't understand why this is throwing instead of calling result.error.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I realized looking at this again today that I was wrong about this; this is—non-obviously—a regression in this PR. With method channels, on Android, the engine call to onMethodCall is wrapped in an exception handler (specifically a RuntimeException handler, thus the current structure of this code). So the old code would correctly report these exceptions back to Dart, but this version won't because Pigeon doesn't try/catch async methods.

So we can close flutter/flutter#157021, and this code needs to be updated here. To be fully behavior-preserving, handleException should look like this:

// The code below exactly preserves the format of the native exceptions generated by pre-Pigeon
// code. Since `camera` currently leaks the raw platform exceptions to clients, there may be client
// code that relies on specific string values here, so these should not be changed. See
// https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#platform-exception-handling
// for longer-term solutions to this.
if (exception instanceof CameraAccessException) {
  result.error(new FlutterError("CameraAccess", exception.getMessage(), null));
  return;
}
result.error(new FlutterError("error", exception.getMessage(), null, Log.getStackTraceString(exception)));

Apologies for missing this before; I'm still more used to the Obj-C method channel behaviors that the Java method channels.

}

// CameraAccessException can not be cast to a RuntimeException.
throw (RuntimeException) exception;
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I realized looking at this again today that I was wrong about this; this is—non-obviously—a regression in this PR. With method channels, on Android, the engine call to onMethodCall is wrapped in an exception handler (specifically a RuntimeException handler, thus the current structure of this code). So the old code would correctly report these exceptions back to Dart, but this version won't because Pigeon doesn't try/catch async methods.

So we can close flutter/flutter#157021, and this code needs to be updated here. To be fully behavior-preserving, handleException should look like this:

// The code below exactly preserves the format of the native exceptions generated by pre-Pigeon
// code. Since `camera` currently leaks the raw platform exceptions to clients, there may be client
// code that relies on specific string values here, so these should not be changed. See
// https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#platform-exception-handling
// for longer-term solutions to this.
if (exception instanceof CameraAccessException) {
  result.error(new FlutterError("CameraAccess", exception.getMessage(), null));
  return;
}
result.error(new FlutterError("error", exception.getMessage(), null, Log.getStackTraceString(exception)));

Apologies for missing this before; I'm still more used to the Obj-C method channel behaviors that the Java method channels.

try {
camera.resumePreview();
} catch (Exception e) {
throw new Messages.FlutterError("CameraAccessException", e.getMessage(), null);
Copy link
Contributor

Choose a reason for hiding this comment

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

I missed this, but here and below you are catching Exception but reporting it as a CameraAccessException. I don't think you need these two handlers at all since you aren't doing anything specific with the exceptions, and these are sync methods, so the generic Pigeon-level handler should be fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same with stopImageStream.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

stopImageStream calls startPreview, which can throw two types of non-runtime Exception, so it needs to be wrapped in a try/catch to compile. I'm not sure what you're referring to by "and below", but I made the change to this method and incorporated the feedback from your other comment.

Copy link
Contributor

@bparrishMines bparrishMines left a comment

Choose a reason for hiding this comment

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

LGTM but @stuartmorgan can provide the final LGTM

Copy link
Contributor

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

LGTM!

@yaakovschectman yaakovschectman merged commit 2a1c477 into flutter:main Oct 18, 2024
76 checks passed
@yaakovschectman yaakovschectman deleted the camera_android_pigeon branch October 18, 2024 16:37
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Oct 18, 2024
flutter/packages@5582669...2a1c477

2024-10-18 [email protected] [camera_android] Convert Dart to native calls to use Pigeon (flutter/packages#7874)
2024-10-17 [email protected] [url_launcher] Decode file URLs before passing it to ShellExecuteW (flutter/packages#7774)
2024-10-17 [email protected] [in_app_purchase_storekit] Add support for purchase and transactions (flutter/packages#7887)
2024-10-17 [email protected] [interactive_media_ads] Adds internal wrapper for iOS native `IMACompanionAd` (flutter/packages#7873)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants