-
Notifications
You must be signed in to change notification settings - Fork 538
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[Xamarin.Android.Build.Tasks] correct paths in MarshalMethodsAssemblyRewriter #8151
[Xamarin.Android.Build.Tasks] correct paths in MarshalMethodsAssemblyRewriter #8151
Conversation
…Rewriter Context: dotnet/maui#15399 (comment) During a PR updating AndroidX dependencies in .NET MAUI, we got the error: Task GenerateJavaStubs ... System.IO.IOException: The process cannot access the file 'D:\a\_work\1\s\src\Compatibility\ControlGallery\src\Android\obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.pdb' because it is being used by another process. at System.IO.FileSystem.CopyFile(String sourceFullPath, String destFullPath, Boolean overwrite) at Xamarin.Android.Tasks.MarshalMethodsAssemblyRewriter.Rewrite(DirectoryAssemblyResolver resolver, List`1 targetAssemblyPaths, Boolean brokenExceptionTransitions) at Xamarin.Android.Tasks.GenerateJavaStubs.Run(DirectoryAssemblyResolver res, Boolean useMarshalMethods) at Xamarin.Android.Tasks.GenerateJavaStubs.RunTask() at Microsoft.Android.Build.Tasks.AndroidTask.Execute() in /Users/runner/work/1/s/xamarin-android/external/xamarin-android-tools/src/Microsoft.Android.Build.BaseTasks/AndroidTask.cs:line 25 Which has some very odd logging right before the failure: Copying rewritten assembly: obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.dll.new -> obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.dll Copying rewritten assembly: obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.pdb -> obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.pdb Copying `Xamarin.AndroidX.CustomView.PoolingContainer.pdb` to `Xamarin.AndroidX.CustomView.pdb`? I could reproduce the issue in a test with `PublishTrimmed=false`: [Test] public void SimilarAndroidXAssemblyNames ([Values(true, false)] bool publishTrimmed) { var proj = new XamarinAndroidApplicationProject { IsRelease = true, AotAssemblies = publishTrimmed, PackageReferences = { new Package { Id = "Xamarin.AndroidX.CustomView", Version = "1.1.0.17" }, new Package { Id = "Xamarin.AndroidX.CustomView.PoolingContainer", Version = "1.0.0.4" }, } }; proj.SetProperty (KnownProperties.PublishTrimmed, publishTrimmed.ToString()); proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "AndroidX.CustomView.PoolingContainer.PoolingContainer.IsPoolingContainer (null);"); using var builder = CreateApkBuilder (); Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); } In `MarshalMethodsAssemblyRewriter` we write temporary assembly files to `foo.new` and copy to the original path at `foo.dll`. We next copy any symbol files if found. I found two underlying issues here. First, this `Mono.Cecil` API: AssemblyDefinition.Write("foo.new", new WriterParameters { WriteSymbols = true }); It would write a `foo.pdb` instead of `foo.new.pdb`, and so we have no way for this to write symbols to a temporary location. I put the temporary location in a `new` subdirectory instead of appending `.new` to the path. The second problem is this code: target = Path.ChangeExtension (Path.Combine (targetPath, Path.GetFileNameWithoutExtension (pdb)), ".pdb"); CopyFile (pdb, target); It appears to lose `.PoolingContainer` from the path, and so it uses the destination of: obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.pdb But using a `new` subdirectory instead, we bypass this issue. After these changes, we instead get: Copying rewritten assembly: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.dll -> obj\Release\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.dll Copying rewritten assembly: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.pdb -> obj\Release\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.pdb Deleting: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.dll Deleting: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.pdb Lastly, I removed `.mdb` file support -- but that is completely unrelated to the issue.
foreach (string targetPath in targetAssemblyPaths) { | ||
string target = Path.Combine (targetPath, Path.GetFileNameWithoutExtension (path)); | ||
string target = Path.Combine (targetPath, Path.GetFileName (path)); | ||
CopyFile (path, target); |
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.
I realize that the "original" version in 8bc7a3e didn't do this, but should we verify that target
exists before this CopyFile()
?
targetPaths
could contain multiple directories, such as arm64-v8a/linked
and x86_64/linked
, and it feels like this method could possibly copy/overwrite the "wrong" ABI?
Does MarshalMethodAssemblyRewriter
properly deal with per-ABI assemblies? (See also 929e701?)
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.
@jonpryor all the known target-specific assemblies are ones which we won't rewrite, since they don't have any Java.Object-derived classes. But yes, in general, the code would fail if it encountered Java.Object-derived types in a target-specific assembly, since the task (and thus MarshalMethodsAssemblyRewriter
) would be passed several copies of those assemblies.
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.
IOW, we're safe now with the code as-is, but it wouldn't hurt to amend it to make target-specific assemblies are handled properly. I guess the DestinationSubPath
metadata item could be used to build the output path, by appending it to the new/
path?
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.
@grendello: as per 929e701, any assembly can now become a target-specific assembly if (when) it uses IntPtr.Size
. We likely shouldn't address this here, but we likely will need to address it.
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.
We should merge this PR, and followup later with a more complete fix for per-ABI assemblies.
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.
I agree, as it requires a review of all our tasks
…#8151) Context: dotnet/maui#15399 (comment) During a PR updating AndroidX dependencies in .NET MAUI, we saw: Task GenerateJavaStubs … System.IO.IOException: The process cannot access the file 'D:\a\_work\1\s\src\Compatibility\ControlGallery\src\Android\obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.pdb' because it is being used by another process. at System.IO.FileSystem.CopyFile(String sourceFullPath, String destFullPath, Boolean overwrite) at Xamarin.Android.Tasks.MarshalMethodsAssemblyRewriter.Rewrite(DirectoryAssemblyResolver resolver, List`1 targetAssemblyPaths, Boolean brokenExceptionTransitions) at Xamarin.Android.Tasks.GenerateJavaStubs.Run(DirectoryAssemblyResolver res, Boolean useMarshalMethods) at Xamarin.Android.Tasks.GenerateJavaStubs.RunTask() at Microsoft.Android.Build.Tasks.AndroidTask.Execute() Which has some very odd logging right before the failure: Copying rewritten assembly: obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.dll.new -> obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.dll Copying rewritten assembly: obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.pdb -> obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.pdb Copying `Xamarin.AndroidX.CustomView.PoolingContainer.pdb` to `Xamarin.AndroidX.CustomView.pdb`? Where is `.PoolingContainer`? I could reproduce the issue in a test with `$(PublishTrimmed)`=False: [Test] public void SimilarAndroidXAssemblyNames ([Values(true, false)] bool publishTrimmed) { var proj = new XamarinAndroidApplicationProject { IsRelease = true, AotAssemblies = publishTrimmed, PackageReferences = { new Package { Id = "Xamarin.AndroidX.CustomView", Version = "1.1.0.17" }, new Package { Id = "Xamarin.AndroidX.CustomView.PoolingContainer", Version = "1.0.0.4" }, } }; proj.SetProperty (KnownProperties.PublishTrimmed, publishTrimmed.ToString()); proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "AndroidX.CustomView.PoolingContainer.PoolingContainer.IsPoolingContainer (null);"); using var builder = CreateApkBuilder (); Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); } In `MarshalMethodsAssemblyRewriter` we write temporary assembly files to `foo.new` and copy to the original path at `foo.dll`. We next copy any symbol files if found. I found two underlying issues here: First, this `Mono.Cecil` API: AssemblyDefinition.Write("foo.new", new WriterParameters { WriteSymbols = true, }); would write a `foo.pdb` instead of `foo.new.pdb`, and so we have no way for this to write symbols to a temporary location. I put the temporary location in a `new` subdirectory instead of appending `.new` to the path. The second problem is this code: target = Path.ChangeExtension (Path.Combine (targetPath, Path.GetFileNameWithoutExtension (pdb)), ".pdb"); CopyFile (pdb, target); It appears to lose `.PoolingContainer` from the path, and so it uses the destination of: obj\Release\net8.0-android\android\assets\Xamarin.AndroidX.CustomView.pdb By using a `new` subdirectory instead, we bypass this issue. After these changes, we instead get: Copying rewritten assembly: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.dll -> obj\Release\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.dll Copying rewritten assembly: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.pdb -> obj\Release\android\assets\Xamarin.AndroidX.CustomView.PoolingContainer.pdb Deleting: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.dll Deleting: obj\Release\android\assets\new\Xamarin.AndroidX.CustomView.PoolingContainer.pdb Lastly, I removed `.mdb` file support -- but that is completely unrelated to the issue.
* main: Bump to dotnet/installer@28d4a6b4be 8.0.100-preview.7.23330.16 (dotnet#8162) [Xamarin.Android.Build.Tasks] Move MonoAndroidAssetsDirIntermediate (dotnet#8166) [xaprepare] update Debian dependencies for current unstable (trixie) (dotnet#8169) [CI] Use dotnet test slicer in nightly tests (dotnet#8154) [Xamarin.Android.Build.Tasks] MarshalMethodsAssemblyRewriter+new file (dotnet#8151) Bump to dotnet/installer@d2a244f560 8.0.100-preview.7.23325.5 (dotnet#8142)
Context: dotnet/maui#15399 (comment)
During a PR updating AndroidX dependencies in .NET MAUI, we got the error:
Which has some very odd logging right before the failure:
Copying
Xamarin.AndroidX.CustomView.PoolingContainer.pdb
toXamarin.AndroidX.CustomView.pdb
?I could reproduce the issue in a test with
PublishTrimmed=false
:In
MarshalMethodsAssemblyRewriter
we write temporary assembly files tofoo.new
and copy to the original path atfoo.dll
. We next copy any symbol files if found.I found two underlying issues here.
First, this
Mono.Cecil
API:It would write a
foo.pdb
instead offoo.new.pdb
, and so we have no way for this to write symbols to a temporary location.I put the temporary location in a
new
subdirectory instead of appending.new
to the path.The second problem is this code:
It appears to lose
.PoolingContainer
from the path, and so it uses the destination of:But using a
new
subdirectory instead, we bypass this issue.After these changes, we instead get:
Lastly, I removed
.mdb
file support -- but that is completely unrelated to the issue.