Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,64 @@ This file contains targets specific for Android application projects.
/>
<Message Text="Logcat output is available in $(_RunLogFilePath)" Importance="High" />
</Target>

<!-- The remotemscordbitarget library runs as a CLR profiler on the device and communicates with the host via gRPC -->
<Target Name="_SetupCoreClrDebugger"
Condition=" '$(AndroidEnableCoreClrDebugger)' == 'true' ">
<Message Text="Setting up CoreCLR remote debugger on port $(CoreClrDebuggerPort)" Importance="High" />

<AndroidAdb
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Command="shell"
Arguments="setprop debug.coreclr.isserver $(CoreClrDebuggerIsServer)"
/>
<AndroidAdb
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Command="shell"
Arguments="setprop debug.coreclr.ip 127.0.0.1"
/>
<AndroidAdb
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Command="shell"
Arguments="setprop debug.coreclr.port $(CoreClrDebuggerPort)"
/>

Comment on lines +207 to +228
Copy link
Member

Choose a reason for hiding this comment

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

These are a lot of adb calls, do they all need to be system properties? We also have the ability to bake environment variables into apps, or use dotnet run -e DOTNET_CORE_CLR_IP=127.0.0.1.

<Message Text="Setting up adb port forwarding: tcp:$(CoreClrDebuggerPort) -> tcp:$(CoreClrDebuggerPort)" Importance="High" />
<AndroidAdb
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Command="forward"
Arguments="tcp:$(CoreClrDebuggerPort) tcp:$(CoreClrDebuggerPort)"
/>
</Target>

<Target Name="RunWithCoreClrDebugger"
DependsOnTargets="Install;_SetupCoreClrDebugger">
Comment on lines +239 to +240
Copy link
Member

Choose a reason for hiding this comment

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

This is a new public target, what calls it?

I think I have some general questions on how this is supposed to integrate with IDEs.

<GetAndroidActivityName
Condition=" '$(AndroidLaunchActivity)' == '' "
ManifestFile="$(IntermediateOutputPath)android\AndroidManifest.xml">
<Output TaskParameter="ActivityName" PropertyName="AndroidLaunchActivity" />
</GetAndroidActivityName>

<PropertyGroup>
<_AmStartUserArg Condition=" '$(AndroidDeviceUserId)' != '' "> --user $(AndroidDeviceUserId)</_AmStartUserArg>
</PropertyGroup>

<Message Text="Launching application with CoreCLR remote debugger" Importance="High" />
<AndroidAdb
ToolExe="$(AdbToolExe)"
ToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Command="shell"
Arguments="am start -S -W$(_AmStartUserArg) -n &quot;$(_AndroidPackage)/$(AndroidLaunchActivity)&quot;"
/>
<Message Text="Application started. Connect the remote debugger host to 127.0.0.1:$(CoreClrDebuggerPort)" Importance="High" />
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,13 @@ _ResolveAssemblies MSBuild target.
<ItemGroup>
<_ResolvedNativeLibraries Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Extension)' == '.so' " />
</ItemGroup>
<ItemGroup>
<ItemGroup Condition="'$(_AndroidRuntime)' == 'Mono'">
<_MonoComponent Condition=" '$(AndroidEnableProfiler)' == 'true' " Include="diagnostics_tracing" />
<_MonoComponent Condition=" '$(AndroidUseInterpreter)' == 'true' " Include="hot_reload" />
<_MonoComponent Condition=" '$(AndroidIncludeDebugSymbols)' == 'true' " Include="debugger" />
<_MonoComponent Condition=" '$(_AndroidExcludeMarshalIlgenComponent)' != 'true' " Include="marshal-ilgen" />
</ItemGroup>
<ItemGroup>
<!-- Filename without extension -->
<_ExcludedNativeLibraries Condition=" '$(_AndroidIncludeSystemGlobalizationNative)' != 'true' " Include="libSystem.Globalization.Native" />
<_ExcludedNativeLibraries Condition=" '$(_AndroidEnableNativeStackTracing)' != 'true' " Include="libxamarin-native-tracing" />
Expand Down Expand Up @@ -274,6 +276,17 @@ _ResolveAssemblies MSBuild target.
KnownRuntimeNativeLibraries="@(_KnownRuntimeNativeLibrary)">
<Output TaskParameter="OutputLibraries" ItemName="FrameworkNativeLibrary" />
</ProcessNativeLibraries>

<ItemGroup Condition=" '$(AndroidEnableCoreClrDebugger)' == 'true' and '$(_AndroidRuntime)' == 'CoreCLR' ">
<AndroidNativeLibrary Include="$(CoreClrDebuggerNativeLibraryPath)\arm64-v8a\libremotemscordbitarget.so"
Condition="Exists('$(CoreClrDebuggerNativeLibraryPath)\arm64-v8a\libremotemscordbitarget.so')">
<Abi>arm64-v8a</Abi>
</AndroidNativeLibrary>
<AndroidNativeLibrary Include="$(CoreClrDebuggerNativeLibraryPath)\x86_64\libremotemscordbitarget.so"
Condition="Exists('$(CoreClrDebuggerNativeLibraryPath)\x86_64\libremotemscordbitarget.so')">
<Abi>x86_64</Abi>
</AndroidNativeLibrary>
</ItemGroup>
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
<_AndroidFastDeploymentSupported Condition=" Exists ('$(MSBuildThisFileDirectory)../tools/Xamarin.Android.Common.Debugging.targets') ">true</_AndroidFastDeploymentSupported>
<_AndroidFastDeploymentSupported Condition=" '$(_AndroidFastDeploymentSupported)' == '' ">False</_AndroidFastDeploymentSupported>

<!-- TODO: remove when we have debugger support for CoreCLR -->
<UseMonoRuntime Condition=" '$(UseMonoRuntime)' == '' and '$(Configuration)' == 'Debug' ">true</UseMonoRuntime>

<!--
Disable @(Content) from referenced projects
See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16
Expand Down Expand Up @@ -57,6 +54,12 @@
<AndroidEnableProfiler Condition=" '$(AndroidEnableProfiler)' == '' and ('$(DiagnosticConfiguration)' != '' or '$(DiagnosticAddress)' != '' or '$(DiagnosticPort)' != '' or '$(DiagnosticSuspend)' != '' or '$(DiagnosticListenMode)' != '') ">true</AndroidEnableProfiler>
<AndroidEnableProfiler Condition=" '$(AndroidEnableProfiler)' == '' ">false</AndroidEnableProfiler>

<AndroidEnableCoreClrDebugger Condition=" '$(AndroidEnableCoreClrDebugger)' == '' and '$(_AndroidRuntime)' == 'CoreCLR' and '$(Configuration)' != 'Release' ">true</AndroidEnableCoreClrDebugger>
<AndroidEnableCoreClrDebugger Condition=" '$(AndroidEnableCoreClrDebugger)' == '' ">false</AndroidEnableCoreClrDebugger>
Comment on lines +57 to +58
Copy link
Member

Choose a reason for hiding this comment

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

Question about naming: should this just be DebuggerSupport? Same as feature switch? or a new name like EnableDebugger? We'd also unify with the existing Mono settings for the debugger.

Setting a single property would be ideal, and then it would do the same thing no matter what runtime is used.

<CoreClrDebuggerPort Condition=" '$(CoreClrDebuggerPort)' == '' ">4711</CoreClrDebuggerPort>
<CoreClrDebuggerIsServer Condition=" '$(CoreClrDebuggerIsServer)' == '' ">1</CoreClrDebuggerIsServer>
Comment on lines +59 to +60
Copy link
Member

Choose a reason for hiding this comment

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

Again, these it seems like we should choose names that don't have CoreClr in them and try to unify with what Mono has. Picking names like DebuggerPort and DebuggerIsServer -- and compare what Mono has right now.

<CoreClrDebuggerNativeLibraryPath Condition=" '$(CoreClrDebuggerNativeLibraryPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\libremotemscordbitarget</CoreClrDebuggerNativeLibraryPath>

<!--
Android package (apt/aab) alignment, expressed as the page size in kilobytes. Two values are supported: 4 and 16.
Sometime next year 16 is going to be a Google Play store requirement for application submissions.
Expand Down Expand Up @@ -153,6 +156,8 @@

<!-- profiler won't work without internet permission, we must thus force it -->
<AndroidNeedsInternetPermission Condition=" '$(AndroidEnableProfiler)' == 'true' ">True</AndroidNeedsInternetPermission>
<!-- CoreCLR debugger uses gRPC which requires network access -->
<AndroidNeedsInternetPermission Condition=" '$(AndroidEnableCoreClrDebugger)' == 'true' ">True</AndroidNeedsInternetPermission>
</PropertyGroup>
<!-- Trimmer switches that default to OFF in Release mode -->
<PropertyGroup Condition=" '$(AndroidApplication)' == 'true' and '$(Optimize)' == 'true' ">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class GenerateNativeApplicationConfigSources : AndroidTask
public string? AndroidSequencePointsMode { get; set; }
public bool EnableSGenConcurrent { get; set; }
public string? CustomBundleConfigFile { get; set; }
public bool EnableCoreClrDebugger { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

Seems like this could check:

  • Is it CoreCLR
  • Is the general purpose debugger MSBuild property set


bool _Debug {
get {
Expand Down Expand Up @@ -118,13 +119,20 @@ public override bool RunTask ()
envBuilder.AddDefaultDebugBuildLogLevel ();
}

if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) {
AddDefaultEnvironmentVariables (envBuilder, HttpClientHandlerType, EnableSGenConcurrent);
} else {
if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) {
// NativeAOT sets all the environment variables from Java, we don't want to repeat that
// process in the native code. This is just a precaution, because NativeAOT builds should
// not even use this task.
envBuilder.EnvironmentVariables.Clear ();
} else if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) {
// CoreCLR needs the HTTP client handler type
envBuilder.AddHttpClientHandlerType (HttpClientHandlerType);
} else {
AddDefaultEnvironmentVariables (envBuilder, HttpClientHandlerType, EnableSGenConcurrent);
}

if (EnableCoreClrDebugger && TargetsCLR) {
envBuilder.AddCoreClrDebuggerEnvironment ();
}

global::Android.Runtime.BoundExceptionType boundExceptionType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,5 +237,64 @@ public void CheckHttpClientHandlerType ([Values] AndroidRuntime runtime)
Assert.AreEqual (expectedUpdatedValue, envvars[httpClientHandlerVarName]);
}
}

[Test]
public void CheckCoreClrDebuggerEnvironmentVariables ()
{
const string supportedAbis = "arm64-v8a;x86_64";

var proj = new XamarinAndroidApplicationProject () {
IsRelease = false,
};

proj.SetRuntime (AndroidRuntime.CoreCLR);
proj.SetProperty ("AndroidEnableCoreClrDebugger", "true");
proj.SetAndroidSupportedAbis (supportedAbis);

using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");

string intermediateOutputDir = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
List<EnvironmentHelper.EnvironmentFile> envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true, AndroidRuntime.CoreCLR);
Dictionary<string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, AndroidRuntime.CoreCLR);
Assert.IsTrue (envvars.Count > 0, $"No environment variables defined");

Assert.IsTrue (envvars.ContainsKey ("CORECLR_ENABLE_PROFILING"), "Environment should contain CORECLR_ENABLE_PROFILING");
Assert.AreEqual ("1", envvars ["CORECLR_ENABLE_PROFILING"], "CORECLR_ENABLE_PROFILING should be '1'");

Assert.IsTrue (envvars.ContainsKey ("CORECLR_PROFILER"), "Environment should contain CORECLR_PROFILER");
Assert.AreEqual ("{9DC623E8-C88F-4FD5-AD99-77E67E1D9631}", envvars ["CORECLR_PROFILER"], "CORECLR_PROFILER GUID mismatch");

Assert.IsTrue (envvars.ContainsKey ("CORECLR_PROFILER_PATH"), "Environment should contain CORECLR_PROFILER_PATH");
Assert.AreEqual ("libremotemscordbitarget.so", envvars ["CORECLR_PROFILER_PATH"], "CORECLR_PROFILER_PATH should point to libremotemscordbitarget.so");

Assert.IsFalse (envvars.ContainsKey ("MONO_GC_PARAMS"), "CoreCLR builds should not set MONO_GC_PARAMS");
Assert.IsFalse (envvars.ContainsKey ("MONO_DEBUG"), "CoreCLR builds should not set MONO_DEBUG");
}
}

[Test]
public void CheckCoreClrDebuggerNotEnabledInRelease ()
{
const string supportedAbis = "arm64-v8a";

var proj = new XamarinAndroidApplicationProject () {
IsRelease = true,
};

proj.SetRuntime (AndroidRuntime.CoreCLR);
proj.SetAndroidSupportedAbis (supportedAbis);

using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");

string intermediateOutputDir = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
List<EnvironmentHelper.EnvironmentFile> envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true, AndroidRuntime.CoreCLR);
Dictionary<string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, AndroidRuntime.CoreCLR);

Assert.IsFalse (envvars.ContainsKey ("CORECLR_ENABLE_PROFILING"), "Release builds should not enable CoreCLR profiling");
Assert.IsFalse (envvars.ContainsKey ("CORECLR_PROFILER"), "Release builds should not set CORECLR_PROFILER");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,12 @@ public void AddMonoGcParams (bool enableSgenConcurrent)
AddEnvironmentVariable ("MONO_GC_PARAMS", enableSgenConcurrent ? "major=marksweep-conc" : "major=marksweep");
}

public void AddCoreClrDebuggerEnvironment ()
{
AddEnvironmentVariable ("CORECLR_ENABLE_PROFILING", "1");
AddEnvironmentVariable ("CORECLR_PROFILER", "{9DC623E8-C88F-4FD5-AD99-77E67E1D9631}");
AddEnvironmentVariable ("CORECLR_PROFILER_PATH", "libremotemscordbitarget.so");
}

static string ValidAssemblerString (string s) => s.Replace ("\\", "\\\\").Replace ("\"", "\\\"");
}
Original file line number Diff line number Diff line change
Expand Up @@ -1715,6 +1715,11 @@ because xbuild doesn't support framework reference assemblies.
<_AllNativeLibraries Include="@(AndroidNativeLibrary);@(EmbeddedNativeLibrary);@(FrameworkNativeLibrary)" />
</ItemGroup>

<ItemGroup Condition=" '$(AndroidEnableCoreClrDebugger)' == 'true' ">
<!-- CoreCLR remote debugger target library should not be preloaded via JNI; it is loaded as a CLR profiler -->
<_AndroidNativeLibraryNeverJniPreload Include="libremotemscordbitarget.so" />
</ItemGroup>

<ItemGroup Condition=" '$(AndroidIgnoreAllJniPreload)' == 'true' ">
<!-- We include everything, tasks below will take care of exclusion of certain libs from this
item group -->
Expand Down Expand Up @@ -1751,6 +1756,7 @@ because xbuild doesn't support framework reference assemblies.
TargetsCLR="$(_AndroidUseCLR)"
AndroidRuntime="$(_AndroidRuntime)"
ProjectRuntimeConfigFilePath="$(ProjectRuntimeConfigFilePath)"
EnableCoreClrDebugger="$(AndroidEnableCoreClrDebugger)"
>
</GenerateNativeApplicationConfigSources>

Expand Down
Loading