-
Notifications
You must be signed in to change notification settings - Fork 566
[Xamarin.Android.Build.Tasks] Catch Exception when setting Console.InputEncoding #4722
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #### Visual Studio Crashes when changing an AndroidResource file. | ||
|
|
||
| - [Developer Community 1038779](https://developercommunity.visualstudio.com/content/problem/1038779/visual-studio-crash-down.html): | ||
| - [GitHub 4734](https://github.com/xamarin/xamarin-android/issues/4734): | ||
|
|
||
| In 16.7 Preview 1 we encountered a problem were Visual Studio world | ||
| crash uneexpectedly. Further investigation lead to an Unhandled `IOException` | ||
| in the new `aapt2` deamon code causing the problem. This only seems to | ||
| happen when `AndroidUseManagedDesignTimeResourceGenerator` is set to | ||
| `False` in the csproj. As to why it happens that is still unknown. The | ||
| problem occurs when we are trying to set the `InputEncoding` of the `Console`. | ||
| This is to make sure `aapt2` can handle non-ASCII characters in paths. However | ||
| when running in a design time build the `IOException` of `invalid handle` is thrown. | ||
| This does not occur during a normal build. | ||
|
|
||
| The workarond is to remove the `AndroidUseManagedDesignTimeResourceGenerator` from | ||
| the csproj. The fix is to catch the `IOException` and allow `aapt2` to run. This will | ||
| stop Visual Studio from crashing. | ||
|
|
||
| ### Known issues | ||
|
|
||
| If the `IOException` is thrown and caught, `aapt2` will not be able to accept non-ASCII | ||
| characters for paths as its input. You might see `aapt2` build failures if you have | ||
| non-ASCII characters in your paths. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,7 @@ public void Complete (bool result) | |
| long jobsRunning = 0; | ||
| long jobId = 0; | ||
| int maxInstances = 0; | ||
| Queue<string> daemonStartupWarnings = new Queue<string> (); | ||
|
|
||
| public CancellationToken Token => tcs.Token; | ||
|
|
||
|
|
@@ -77,6 +78,8 @@ public bool JobsRunning | |
|
|
||
| public int CurrentInstances => daemons.Count; | ||
|
|
||
| public Queue<string> StartupWarnings => daemonStartupWarnings; | ||
|
|
||
| public Aapt2Daemon (string aapt2, int maxNumberOfInstances, int initalNumberOfDaemons) | ||
| { | ||
| Aapt2 = aapt2; | ||
|
|
@@ -162,21 +165,34 @@ private void Aapt2DaemonStart () | |
| // and we are using netstandard 2.0 | ||
| //StandardInputEncoding = Encoding.UTF8, | ||
| }; | ||
| // We need to FORCE the StandardInput to be UTF8 so we can use | ||
| // We need to FORCE the StandardInput to be UTF8 so we can use | ||
| // accented characters. Also DONT INCLUDE A BOM!! | ||
| // otherwise aapt2 will try to interpret the BOM as an argument. | ||
| Process aapt2; | ||
| Process aapt2 = null; | ||
| lock (lockObject) { | ||
| Encoding current = Console.InputEncoding; | ||
| try { | ||
| Console.InputEncoding = new UTF8Encoding (false); | ||
| aapt2 = new Process (); | ||
| aapt2.StartInfo = info; | ||
| aapt2.Start (); | ||
| } finally { | ||
| Console.InputEncoding = current; | ||
| Encoding current = Console.InputEncoding; | ||
| try { | ||
| try { | ||
| Console.InputEncoding = new UTF8Encoding (false); | ||
| } catch (IOException ioEx) { | ||
| // For some reason we can not set the InputEncoding. If this happens we don't | ||
| // want to crash Visual Studio with an Unhandled Exception. | ||
| // The downside of ignoring this is paths with accented characters will cause problems. | ||
| daemonStartupWarnings.Enqueue (ioEx.ToString ()); | ||
| } | ||
| aapt2 = new Process (); | ||
| aapt2.StartInfo = info; | ||
| aapt2.Start (); | ||
| } finally { | ||
| Console.InputEncoding = current; | ||
| } | ||
| } catch (Exception ex) { | ||
| daemonStartupWarnings.Enqueue (ex.ToString ()); | ||
| } | ||
| } | ||
| if (aapt2 == null) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How can this happen? Line 184 will re-assign If |
||
| return; | ||
| try { | ||
| foreach (var job in pendingJobs.GetConsumingEnumerable (tcs.Token)) { | ||
| Interlocked.Add (ref jobsRunning, 1); | ||
|
|
@@ -191,7 +207,7 @@ private void Aapt2DaemonStart () | |
| writer.WriteLine (); | ||
| writer.Flush (); | ||
| string line; | ||
|
|
||
| Queue<string> stdError = new Queue<string> (); | ||
| while ((line = aapt2.StandardError.ReadLine ()) != null) { | ||
| if (string.Compare (line, "Done", StringComparison.OrdinalIgnoreCase) == 0) { | ||
|
|
@@ -201,8 +217,8 @@ private void Aapt2DaemonStart () | |
| errored = true; | ||
| continue; | ||
| } | ||
| // we have to queue the output because the "Done"/"Error" lines are | ||
| //written after all the messages. So to process the warnings/errors | ||
| // we have to queue the output because the "Done"/"Error" lines are | ||
| //written after all the messages. So to process the warnings/errors | ||
| // correctly we need to do this after we know if worked or failed. | ||
| stdError.Enqueue (line); | ||
| } | ||
|
|
@@ -256,4 +272,4 @@ bool IsAapt2Warning (string singleLine) | |
| return false; | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we can't start the daemon at all here, should this fail instead?
It seems like the warning would be OK for
IOExceptionbut not in the case where it couldn't start the daemon at all?