Skip to content
Open
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
5 changes: 5 additions & 0 deletions src/libraries/sendtohelix-mobile.targets
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@
<!-- The android sample returns 42 so it should be considered by xharness as a success -->
<ExpectedExitCode>42</ExpectedExitCode>
</XHarnessApkToTest>
<XHarnessApkToTest Update="@(XHarnessApkToTest)"
Condition="$([System.String]::Copy('%(Filename)').StartsWith('Android.Device_Emulator.InProcCrashReport.'))">
<ExpectedExitCode>100</ExpectedExitCode>
<DeviceOutputPath>/sdcard/Android/data/%(AndroidPackageName)/files/inproccrashreport.zip</DeviceOutputPath>
</XHarnessApkToTest>
</ItemGroup>
</Target>

Expand Down
11 changes: 11 additions & 0 deletions src/libraries/tests.proj
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@
<ProjectExclusions Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\JIT\Android.Device_Emulator.JIT.Static.Test.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TargetOS)' == 'android' and '$(RuntimeFlavor)' == 'Mono'">
<ProjectExclusions Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\InProcCrashReport\**\*.Test.csproj" />
</ItemGroup>

<ItemGroup Condition="'$(TargetOS)' == 'android' and '$(RuntimeFlavor)' == 'CoreCLR' and '$(RunDisabledAndroidTests)' != 'true'">
<!-- https://github.com/dotnet/runtime/issues/72908 -->
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Reflection.MetadataLoadContext\tests\System.Reflection.MetadataLoadContext.Tests.csproj" />
Expand Down Expand Up @@ -685,6 +689,13 @@
Condition="'$(TestAssemblies)' == 'true'"
BuildInParallel="$(BuildTestInParallel)" />

<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\InProcCrashReport\**\*.Test.csproj"
Exclude="@(ProjectExclusions)"
Condition="'$(TestAssemblies)' == 'true' and '$(ArchiveTests)' == 'true' and
'$(TargetOS)' == 'android' and '$(RuntimeFlavor)' == 'CoreCLR' and
'$(TestNativeAOT)' != 'true' and '$(UseNativeAOTRuntime)' != 'true'"
BuildInParallel="false" />

<ProjectReference Include="$(MSBuildThisFileDirectory)testPackages\testPackages.proj"
Condition="'$(TestPackages)' == 'true'" />

Expand Down
16 changes: 14 additions & 2 deletions src/tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@ cmake_minimum_required(VERSION 3.10)

project(monodroid)

enable_language(C ASM)
enable_language(C CXX ASM)

if(ANDROID_NDK_MAJOR VERSION_LESS "23")
message(FATAL_ERROR "Error: need at least Android NDK 23, got ${ANDROID_NDK_REVISION}!")
endif()

add_compile_options(-Werror=missing-prototypes -Werror=missing-declarations -Wall -std=c99)
add_compile_options(-Wall)

# These warnings describe C function declarations and can be rejected by C++ compilers.
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Werror=missing-prototypes>)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Werror=missing-declarations>)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-std=c99>)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# ANDROID_STL=none does not provide the C++ ABI support needed by RTTI or exceptions.
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>)

add_library(
monodroid
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Abort: a SIGABRT crash thread with no managed exception and native-only
frames. Exercises the non-managed-exception path and the SIGABRT signal
formatting (distinct from the SIGSEGV scenarios). -->
<PropertyGroup>
<AssemblyName>Android.Device_Emulator.InProcCrashReport.Abort.Test</AssemblyName>
<MainLibraryFileName>Android.Device_Emulator.InProcCrashReport.Abort.Test.dll</MainLibraryFileName>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_ABORT</DefineConstants>
</PropertyGroup>

<Import Project="../Shared/InProcCrashReport.Common.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- A valid report root with lifecycle output disabled must only emit compact output. -->
<PropertyGroup>
<AssemblyName>Android.Device_Emulator.InProcCrashReport.ConsoleOnly.Test</AssemblyName>
<MainLibraryFileName>Android.Device_Emulator.InProcCrashReport.ConsoleOnly.Test.dll</MainLibraryFileName>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_CONSOLEONLY</DefineConstants>
</PropertyGroup>
<Import Project="../Shared/InProcCrashReport.Common.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Repeated caller-sink reports, rejection paths, and lifecycle isolation. -->
<PropertyGroup>
<AssemblyName>Android.Device_Emulator.InProcCrashReport.OnDemand.Test</AssemblyName>
<MainLibraryFileName>Android.Device_Emulator.InProcCrashReport.OnDemand.Test.dll</MainLibraryFileName>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_ONDEMAND</DefineConstants>
</PropertyGroup>

<Import Project="../Shared/InProcCrashReport.Common.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Rich SIGSEGV: a managed NullReferenceException crash thread with interleaved
managed/native frames and generic-instantiation method names, plus extra
background threads. Exercises the multithreaded, interleaved-stack, generics
and managed-exception format branches in a single report. -->
<PropertyGroup>
<AssemblyName>Android.Device_Emulator.InProcCrashReport.RichSigsegv.Test</AssemblyName>
<MainLibraryFileName>Android.Device_Emulator.InProcCrashReport.RichSigsegv.Test.dll</MainLibraryFileName>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_RICHSIGSEGV</DefineConstants>
</PropertyGroup>
<Import Project="../Shared/InProcCrashReport.Common.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>
<RunAOTCompilation>false</RunAOTCompilation>
<TestRuntime>true</TestRuntime>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<ExpectedExitCode>100</ExpectedExitCode>
<DefineConstants>$(DefineConstants);INPROC_ANDROID</DefineConstants>
<!-- The test library links its own PAL/reporter; the managed host remains dynamic. -->
<StaticLinkedRuntime>false</StaticLinkedRuntime>
<CrashReportArtifactPath>/sdcard/Android/data/net.dot.$(AssemblyName)/files/inproccrashreport.zip</CrashReportArtifactPath>
<AdditionalXHarnessArguments>$(AdditionalXHarnessArguments) --device-out-folder=$(CrashReportArtifactPath)</AdditionalXHarnessArguments>
</PropertyGroup>

<PropertyGroup>
<CrashReportAndroidDir>$(MSBuildThisFileDirectory)</CrashReportAndroidDir>
<CrashReportSharedDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'tests', 'baseservices', 'exceptions', 'inproccrashreport', 'Shared'))</CrashReportSharedDir>
<CrashReportSourceDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'coreclr', 'debug', 'crashreport'))</CrashReportSourceDir>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(CrashReportSharedDir)Program.cs" />
<AndroidEnv Include="DOTNET_InProcCrashReportTestArchive" Value="$(CrashReportArtifactPath)" />
</ItemGroup>

<ItemGroup>
<ExtraAppNativeSources Include="$(CrashReportSharedDir)inproccrashreport_test_driver.cpp" />
<ExtraAppNativeSources Include="$(CrashReportAndroidDir)android_log_interpose.c" />
</ItemGroup>

<ItemGroup>
<RuntimeHeaders Include="$(CrashReportSourceDir.TrimEnd('\').TrimEnd('/'))" />
<RuntimeHeaders Include="$(CrashReportAndroidDir.TrimEnd('\').TrimEnd('/'))" />
<RuntimeHeaders Include="$(CoreClrProjectRoot)pal\inc" />
</ItemGroup>

<Target Name="ConfigureCrashReportNativeLibraries" BeforeTargets="_AndroidGenerateAppBundle">
<!-- Android CI builds CoreCLR and the APK in the same job; these archives are link inputs, not Helix payload files. -->
<PropertyGroup>
<CrashReportPalLibrary>$([MSBuild]::NormalizePath('$(CoreCLRArtifactsPath)', 'lib', 'libcoreclrpal.a'))</CrashReportPalLibrary>
<CrashReportMinipalLibrary>$([MSBuild]::NormalizePath('$(ArtifactsObjDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(CoreCLRConfiguration)', 'shared_minipal', 'libminipal.a'))</CrashReportMinipalLibrary>
</PropertyGroup>
<Error Condition="!Exists('$(CrashReportPalLibrary)')" Text="Build CoreCLR first; missing PAL library: $(CrashReportPalLibrary)" />
<Error Condition="!Exists('$(CrashReportMinipalLibrary)')" Text="Build CoreCLR first; missing minipal library: $(CrashReportMinipalLibrary)" />

<!-- AndroidAppBuilder uses ANDROID_STL=none. Supply NDK C++ support statically to avoid packaging libc++_shared.so. -->
<ItemGroup>
<RuntimeHeaders Include="$([MSBuild]::NormalizeDirectory('$(ANDROID_NDK_ROOT)', 'toolchains', 'llvm', 'prebuilt', '$(NdkToolchainPrebuiltOS)', 'sysroot', 'usr', 'include', 'c++', 'v1'))" />
<ExtraAppLinkerArgs Include="$(CrashReportPalLibrary.Replace('\', '/'))" />
<ExtraAppLinkerArgs Include="$(CrashReportMinipalLibrary.Replace('\', '/'))" />
<ExtraAppLinkerArgs Include="-lc++_static" />
<ExtraAppLinkerArgs Include="-lc++abi" />
<!-- Keep the test's PAL and C++ runtime private from the hosting CoreCLR. -->
<ExtraAppLinkerArgs Include="-Wl,--exclude-libs,ALL" />
</ItemGroup>
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Captures the in-proc crash reporter's compact console report in-process.
//
// On Android the reporter emits each console line via __android_log_write under
// CRASHREPORT_LOG_TAG ("DOTNET_CRASH"), routed to logcat rather than a file
// descriptor -- so it cannot be captured by redirecting stdout/stderr. This
// translation unit is linked into the same shared library (libmonodroid.so) as
// the PAL-linked reporter, so the reporter's __android_log_write calls bind to
// this definition. Lines tagged DOTNET_CRASH are accumulated for later
// validation; every call is also forwarded to the real liblog implementation so
// the report still appears in logcat for debugging.

#define _GNU_SOURCE
#include "android_log_interpose.h"

#include <android/log.h>
#include <dlfcn.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>

// Must match CRASHREPORT_LOG_TAG in inproccrashreporter.h.
static const char s_crashTag[] = "DOTNET_CRASH";

// The fixed scenarios currently produce at most 1 KiB. Keep ample headroom
// without allocating from the signal-shaped reporting path.
static char s_capture[16 * 1024];
static size_t s_captureLen;
static bool s_overflowed;

typedef int (*android_log_write_fn)(int prio, const char* tag, const char* text);

int __android_log_write(int prio, const char* tag, const char* text)
{
if (tag != NULL && text != NULL && strcmp(tag, s_crashTag) == 0)
{
size_t textLen = strlen(text);
if (textLen < sizeof(s_capture) - s_captureLen - 1)
{
memcpy(s_capture + s_captureLen, text, textLen);
s_captureLen += textLen;
s_capture[s_captureLen++] = '\n';
s_capture[s_captureLen] = '\0';
}
else
{
s_overflowed = true;
}
}

static android_log_write_fn s_real = NULL;
if (s_real == NULL)
{
s_real = (android_log_write_fn)dlsym(RTLD_NEXT, "__android_log_write");
}
if (s_real != NULL)
{
return s_real(prio, tag, text);
}
return 0;
}

const char* InProcCrashReportTest_GetConsoleCapture(void)
{
return s_overflowed ? NULL : s_capture;
}

void InProcCrashReportTest_ResetConsoleCapture(void)
{
s_captureLen = 0;
s_capture[0] = '\0';
s_overflowed = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Shared declarations for the synthetic in-proc crash reporter test's console
// capture. The compact console report is written by the reporter via
// __android_log_write (Android logcat); android_log_interpose.c intercepts those
// writes so the report can be validated in-process alongside the JSON file.

#ifndef ANDROID_LOG_INTERPOSE_H
#define ANDROID_LOG_INTERPOSE_H

#ifdef __cplusplus
extern "C"
{
#endif

// Returns captured lines since the last reset, or NULL if the buffer overflowed.
const char* InProcCrashReportTest_GetConsoleCapture(void);

// Clears the captured console-report text.
void InProcCrashReportTest_ResetConsoleCapture(void);

#ifdef __cplusplus
}
#endif

#endif // ANDROID_LOG_INTERPOSE_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma once

// AndroidAppBuilder does not supply CoreCLR's platform/architecture definitions.
#define HOST_UNIX 1
#define TARGET_UNIX 1
#define PLATFORM_UNIX 1
#define TARGET_ANDROID 1

#if defined(__x86_64__)
#define HOST_AMD64 1
#define TARGET_AMD64 1
#elif defined(__aarch64__)
#define HOST_ARM64 1
#define TARGET_ARM64 1
#elif defined(__arm__)
#define HOST_ARM 1
#define TARGET_ARM 1
#elif defined(__i386__)
#define HOST_X86 1
#define TARGET_X86 1
#else
#error Unsupported Android architecture
#endif

#if defined(__LP64__)
#define HOST_64BIT 1
#define TARGET_64BIT 1
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- StackOverflow: drives the crash-kind StackOverflow branch via
InProcCrashReportSetCrashKind + the BeginStackOverflowTrace /
AddStackOverflowTraceFrame / EndStackOverflowTrace APIs. Exercises the
dedicated stack-overflow thread emission (compressed trace with a repeated
sequence) instead of normal thread enumeration. -->
<PropertyGroup>
<AssemblyName>Android.Device_Emulator.InProcCrashReport.StackOverflow.Test</AssemblyName>
<MainLibraryFileName>Android.Device_Emulator.InProcCrashReport.StackOverflow.Test.dll</MainLibraryFileName>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_STACKOVERFLOW</DefineConstants>
</PropertyGroup>
<Import Project="../Shared/InProcCrashReport.Common.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_ABORT</DefineConstants>
</PropertyGroup>

<Import Project="../Shared/InProcCrashReport.Unix.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_CONSOLEONLY</DefineConstants>
</PropertyGroup>

<Import Project="../Shared/InProcCrashReport.Unix.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<DefineConstants>$(DefineConstants);INPROC_SCENARIO_ONDEMAND</DefineConstants>
</PropertyGroup>

<Import Project="../Shared/InProcCrashReport.Unix.props" />
</Project>
Loading
Loading