Skip to content

Commit 22fc451

Browse files
authored
[Android] Add callback to host-runtime contract for getting assembly data (#112705)
Add a new callback to `host_runtime_contract` that is called default assembly resolution: ```c++ // Probe the host for `path`. Sets pointer to data start and its size, if found. // Returns true if found, false otherwise. If false, out parameter values are ignored by the runtime. bool(HOST_CONTRACT_CALLTYPE* external_assembly_probe)( const char* path, /*out*/ void** data /*out*/ int64_t* size); ``` Contributes to #112706 This is a set of minimal changes required to make dotnet/android#9572 (the `.NET for Android` CoreCLR host) work with standard .NET for Android applications.
1 parent d343214 commit 22fc451

File tree

16 files changed

+130
-70
lines changed

16 files changed

+130
-70
lines changed

eng/native/build-commons.sh

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ build_native()
6363
# All set to commence the build
6464
echo "Commencing build of \"$target\" target in \"$message\" for $__TargetOS.$__TargetArch.$__BuildType in $intermediatesDir"
6565

66+
SAVED_CFLAGS="${CFLAGS}"
67+
SAVED_CXXFLAGS="${CXXFLAGS}"
68+
SAVED_LDFLAGS="${LDFLAGS}"
69+
70+
# Let users provide additional compiler/linker flags via EXTRA_CFLAGS/EXTRA_CXXFLAGS/EXTRA_LDFLAGS.
71+
# If users directly override CFLAG/CXXFLAGS/LDFLAGS, that may lead to some configure tests working incorrectly.
72+
# See https://github.com/dotnet/runtime/issues/35727 for more information.
73+
#
74+
# These flags MUST be exported before gen-buildsys.sh runs or cmake will ignore them
75+
#
76+
export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}"
77+
export CXXFLAGS="${CXXFLAGS} ${EXTRA_CXXFLAGS}"
78+
export LDFLAGS="${LDFLAGS} ${EXTRA_LDFLAGS}"
79+
6680
if [[ "$targetOS" == osx || "$targetOS" == maccatalyst ]]; then
6781
if [[ "$hostArch" == x64 ]]; then
6882
cmakeArgs="-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" $cmakeArgs"
@@ -194,17 +208,6 @@ build_native()
194208
return
195209
fi
196210

197-
SAVED_CFLAGS="${CFLAGS}"
198-
SAVED_CXXFLAGS="${CXXFLAGS}"
199-
SAVED_LDFLAGS="${LDFLAGS}"
200-
201-
# Let users provide additional compiler/linker flags via EXTRA_CFLAGS/EXTRA_CXXFLAGS/EXTRA_LDFLAGS.
202-
# If users directly override CFLAG/CXXFLAGS/LDFLAGS, that may lead to some configure tests working incorrectly.
203-
# See https://github.com/dotnet/runtime/issues/35727 for more information.
204-
export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}"
205-
export CXXFLAGS="${CXXFLAGS} ${EXTRA_CXXFLAGS}"
206-
export LDFLAGS="${LDFLAGS} ${EXTRA_LDFLAGS}"
207-
208211
local exit_code
209212
if [[ "$__StaticAnalyzer" == 1 ]]; then
210213
pushd "$intermediatesDir"

eng/native/gen-buildsys.sh

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,9 @@ if [[ "$host_arch" == "wasm" ]]; then
106106
fi
107107
fi
108108

109-
$cmake_command \
110-
--no-warn-unused-cli \
111-
-G "$generator" \
112-
"-DCMAKE_BUILD_TYPE=$buildtype" \
113-
"-DCMAKE_INSTALL_PREFIX=$__CMakeBinDir" \
114-
$cmake_extra_defines \
115-
$__UnprocessedCMakeArgs \
116-
"${cmake_extra_defines_wasm[@]}" \
117-
-S "$1" \
118-
-B "$2"
109+
buildsys_command="$cmake_command --no-warn-unused-cli -G \"$generator\" \"-DCMAKE_BUILD_TYPE=$buildtype\" \"-DCMAKE_INSTALL_PREFIX=$__CMakeBinDir\" $cmake_extra_defines $__UnprocessedCMakeArgs \"${cmake_extra_defines_wasm[@]}\" -S \"$1\" -B \"$2\""
110+
buildsys_command=$(echo $buildsys_command | sed 's/""//g')
111+
echo $buildsys_command
112+
eval $buildsys_command
119113

120114
# don't add anything after this line so the cmake exit code gets propagated correctly

src/coreclr/dlls/mscoree/exports.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,10 @@ int coreclr_initialize(
292292

293293
ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName);
294294

295-
if (bundleProbe != nullptr)
295+
ExternalAssemblyProbeFn* externalAssemblyProbe = hostContract != nullptr ? hostContract->external_assembly_probe : nullptr;
296+
if (bundleProbe != nullptr || externalAssemblyProbe != nullptr)
296297
{
297-
static Bundle bundle(exePath, bundleProbe);
298+
static Bundle bundle(exePath, bundleProbe, externalAssemblyProbe);
298299
Bundle::AppBundle = &bundle;
299300
}
300301

src/coreclr/hosts/inc/coreclrhost.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ CORECLR_HOSTING_API(coreclr_execute_assembly,
150150
//
151151
// Callback types used by the hosts
152152
//
153+
typedef bool(CORECLR_CALLING_CONVENTION ExternalAssemblyProbeFn)(const char* path, void** data_start, int64_t* size);
153154
typedef bool(CORECLR_CALLING_CONVENTION BundleProbeFn)(const char* path, int64_t* offset, int64_t* size, int64_t* compressedSize);
154155
typedef const void* (CORECLR_CALLING_CONVENTION PInvokeOverrideFn)(const char* libraryName, const char* entrypointName);
155156

src/coreclr/inc/bundle.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,31 @@ class Bundle;
1818
struct BundleFileLocation
1919
{
2020
INT64 Size;
21+
void* DataStart;
2122
INT64 Offset;
2223
INT64 UncompresedSize;
2324

2425
BundleFileLocation()
25-
{
26+
{
2627
LIMITED_METHOD_CONTRACT;
2728

2829
Size = 0;
29-
Offset = 0;
30+
DataStart = nullptr;
31+
Offset = 0;
3032
UncompresedSize = 0;
3133
}
3234

3335
static BundleFileLocation Invalid() { LIMITED_METHOD_CONTRACT; return BundleFileLocation(); }
3436

3537
const SString &Path() const;
3638

37-
bool IsValid() const { LIMITED_METHOD_CONTRACT; return Offset != 0; }
39+
bool IsValid() const { LIMITED_METHOD_CONTRACT; return DataStart != nullptr || Offset != 0; }
3840
};
3941

4042
class Bundle
4143
{
4244
public:
43-
Bundle(LPCSTR bundlePath, BundleProbeFn *probe);
45+
Bundle(LPCSTR bundlePath, BundleProbeFn *probe, ExternalAssemblyProbeFn* externalAssemblyProbe = nullptr);
4446
BundleFileLocation Probe(const SString& path, bool pathIsBundleRelative = false) const;
4547

4648
const SString &Path() const { LIMITED_METHOD_CONTRACT; return m_path; }
@@ -51,9 +53,9 @@ class Bundle
5153
static BundleFileLocation ProbeAppBundle(const SString& path, bool pathIsBundleRelative = false);
5254

5355
private:
54-
55-
SString m_path; // The path to single-file executable
56+
SString m_path; // The path to single-file executable or package name/id on Android
5657
BundleProbeFn *m_probe;
58+
ExternalAssemblyProbeFn *m_externalAssemblyProbe;
5759

5860
SString m_basePath; // The prefix to denote a path within the bundle
5961
COUNT_T m_basePathLength;

src/coreclr/pal/src/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,7 @@ if(CLR_CMAKE_TARGET_LINUX)
300300
else(NOT CLR_CMAKE_TARGET_ANDROID)
301301
target_link_libraries(coreclrpal
302302
PUBLIC
303-
${ANDROID_GLOB}
304-
${LZMA})
303+
${ANDROID_GLOB})
305304
endif(NOT CLR_CMAKE_TARGET_ANDROID)
306305

307306
target_link_libraries(coreclrpal

src/coreclr/vm/bundle.cpp

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,18 @@ const SString &BundleFileLocation::Path() const
3030
return Bundle::AppBundle->Path();
3131
}
3232

33-
Bundle::Bundle(LPCSTR bundlePath, BundleProbeFn *probe)
33+
Bundle::Bundle(LPCSTR bundlePath, BundleProbeFn *probe, ExternalAssemblyProbeFn* externalAssemblyProbe)
34+
: m_probe(probe)
35+
, m_externalAssemblyProbe(externalAssemblyProbe)
36+
, m_basePathLength(0)
3437
{
3538
STANDARD_VM_CONTRACT;
3639

37-
_ASSERTE(probe != nullptr);
40+
_ASSERTE(m_probe != nullptr || m_externalAssemblyProbe != nullptr);
3841

42+
// On Android this is not a real path, but rather the application's package name
3943
m_path.SetUTF8(bundlePath);
40-
m_probe = probe;
41-
44+
#if !defined(TARGET_ANDROID)
4245
// The bundle-base path is the directory containing the single-file bundle.
4346
// When the Probe() function searches within the bundle, it masks out the basePath from the assembly-path (if found).
4447

@@ -47,14 +50,13 @@ Bundle::Bundle(LPCSTR bundlePath, BundleProbeFn *probe)
4750
size_t baseLen = pos - bundlePath + 1; // Include DIRECTORY_SEPARATOR_CHAR_A in m_basePath
4851
m_basePath.SetUTF8(bundlePath, (COUNT_T)baseLen);
4952
m_basePathLength = (COUNT_T)baseLen;
53+
#endif // !TARGET_ANDROID
5054
}
5155

5256
BundleFileLocation Bundle::Probe(const SString& path, bool pathIsBundleRelative) const
5357
{
5458
STANDARD_VM_CONTRACT;
5559

56-
BundleFileLocation loc;
57-
5860
// Skip over m_base_path, if any. For example:
5961
// Bundle.Probe("lib.dll") => m_probe("lib.dll")
6062
// Bundle.Probe("path/to/exe/lib.dll") => m_probe("lib.dll")
@@ -77,27 +79,44 @@ BundleFileLocation Bundle::Probe(const SString& path, bool pathIsBundleRelative)
7779
else
7880
{
7981
// This is not a file within the bundle
80-
return loc;
82+
return BundleFileLocation::Invalid();
8183
}
8284
}
8385

84-
INT64 fileSize = 0;
85-
INT64 compressedSize = 0;
86-
87-
m_probe(utf8Path, &loc.Offset, &fileSize, &compressedSize);
88-
89-
if (compressedSize)
86+
if (m_probe != nullptr)
9087
{
91-
loc.Size = compressedSize;
92-
loc.UncompresedSize = fileSize;
88+
BundleFileLocation loc;
89+
INT64 fileSize = 0;
90+
INT64 compressedSize = 0;
91+
if (m_probe(utf8Path, &loc.Offset, &fileSize, &compressedSize))
92+
{
93+
// Found assembly in bundle
94+
if (compressedSize)
95+
{
96+
loc.Size = compressedSize;
97+
loc.UncompresedSize = fileSize;
98+
}
99+
else
100+
{
101+
loc.Size = fileSize;
102+
loc.UncompresedSize = 0;
103+
}
104+
105+
return loc;
106+
}
93107
}
94-
else
108+
109+
if (m_externalAssemblyProbe != nullptr)
95110
{
96-
loc.Size = fileSize;
97-
loc.UncompresedSize = 0;
111+
BundleFileLocation loc;
112+
if (m_externalAssemblyProbe(utf8Path, &loc.DataStart, &loc.Size))
113+
{
114+
// Found via external assembly probe
115+
return loc;
116+
}
98117
}
99118

100-
return loc;
119+
return BundleFileLocation::Invalid();
101120
}
102121

103122
BundleFileLocation Bundle::ProbeAppBundle(const SString& path, bool pathIsBundleRelative)

src/coreclr/vm/coreassemblyspec.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,13 @@ STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
8989
PEImageHolder pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default, bundleFileLocation);
9090

9191
// Make sure that the IL image can be opened.
92-
hr=pImage->TryOpenFile();
93-
if (FAILED(hr))
92+
if (pImage->IsFile())
9493
{
95-
goto Exit;
94+
hr = pImage->TryOpenFile();
95+
if (FAILED(hr))
96+
{
97+
goto Exit;
98+
}
9699
}
97100

98101
if (pImage)

src/coreclr/vm/peimage.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -863,13 +863,15 @@ HRESULT PEImage::TryOpenFile(bool takeLock)
863863
{
864864
STANDARD_VM_CONTRACT;
865865

866+
_ASSERTE(IsFile());
867+
866868
SimpleWriteLockHolder lock(m_pLayoutLock, takeLock);
867869

868-
if (m_hFile!=INVALID_HANDLE_VALUE)
870+
if (m_hFile != INVALID_HANDLE_VALUE)
869871
return S_OK;
870872

871873
ErrorModeHolder mode{};
872-
m_hFile=WszCreateFile((LPCWSTR)GetPathToLoad(),
874+
m_hFile = WszCreateFile((LPCWSTR)GetPathToLoad(),
873875
GENERIC_READ
874876
#if TARGET_WINDOWS
875877
// the file may have native code sections, make sure we are allowed to execute the file
@@ -881,7 +883,6 @@ HRESULT PEImage::TryOpenFile(bool takeLock)
881883
OPEN_EXISTING,
882884
FILE_ATTRIBUTE_NORMAL,
883885
NULL);
884-
885886
if (m_hFile != INVALID_HANDLE_VALUE)
886887
return S_OK;
887888

src/coreclr/vm/peimage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class PEImage final
138138

139139
BOOL IsFile();
140140
BOOL IsInBundle() const;
141+
void* GetExternalData(INT64* size);
141142
INT64 GetOffset() const;
142143
INT64 GetSize() const;
143144
INT64 GetUncompressedSize() const;

src/coreclr/vm/peimage.inl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ inline const SString& PEImage::GetPathToLoad()
3939
return IsInBundle() ? m_bundleFileLocation.Path() : m_path;
4040
}
4141

42+
inline void* PEImage::GetExternalData(INT64* size)
43+
{
44+
LIMITED_METHOD_CONTRACT;
45+
46+
_ASSERTE(size != nullptr);
47+
48+
*size = m_bundleFileLocation.Size;
49+
return m_bundleFileLocation.DataStart;
50+
}
51+
4252
inline INT64 PEImage::GetOffset() const
4353
{
4454
LIMITED_METHOD_CONTRACT;
@@ -98,8 +108,7 @@ inline const SString &PEImage::GetModuleFileNameHintForDAC()
98108
inline BOOL PEImage::IsFile()
99109
{
100110
WRAPPER_NO_CONTRACT;
101-
102-
return !GetPathToLoad().IsEmpty();
111+
return m_bundleFileLocation.DataStart == nullptr && !GetPathToLoad().IsEmpty();
103112
}
104113

105114
//

src/coreclr/vm/peimagelayout.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -616,17 +616,28 @@ FlatImageLayout::FlatImageLayout(PEImage* pOwner)
616616
PRECONDITION(CheckPointer(pOwner));
617617
}
618618
CONTRACTL_END;
619-
m_pOwner=pOwner;
620-
621-
HANDLE hFile = pOwner->GetFileHandle();
622-
INT64 offset = pOwner->GetOffset();
623-
INT64 size = pOwner->GetSize();
619+
m_pOwner = pOwner;
624620

625621
#ifdef LOGGING
626622
SString ownerPath{ pOwner->GetPath() };
627623
LOG((LF_LOADER, LL_INFO100, "PEImage: Opening flat %s\n", ownerPath.GetUTF8()));
628624
#endif // LOGGING
629625

626+
INT64 dataSize;
627+
void* data = pOwner->GetExternalData(&dataSize);
628+
if (data != nullptr)
629+
{
630+
// Image was provided as flat data via external assembly probing.
631+
// We do not manage the data - just initialize with it directly.
632+
_ASSERTE(dataSize != 0);
633+
Init(data, (COUNT_T)dataSize);
634+
return;
635+
}
636+
637+
HANDLE hFile = pOwner->GetFileHandle();
638+
INT64 offset = pOwner->GetOffset();
639+
INT64 size = pOwner->GetSize();
640+
630641
// If a size is not specified, load the whole file
631642
if (size == 0)
632643
{

src/coreclr/vm/peimagelayout.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,7 @@ class FlatImageLayout : public PEImageLayout
8181
{
8282
VPTR_VTABLE_CLASS(FlatImageLayout, PEImageLayout)
8383
VPTR_UNIQUE(0x59)
84-
protected:
85-
CLRMapViewHolder m_FileView;
8684
public:
87-
HandleHolder m_FileMap;
88-
8985
#ifndef DACCESS_COMPILE
9086
FlatImageLayout(PEImage* pOwner);
9187
FlatImageLayout(PEImage* pOwner, const BYTE* array, COUNT_T size);
@@ -94,6 +90,12 @@ class FlatImageLayout : public PEImageLayout
9490
void* LoadImageByMappingParts(SIZE_T* m_imageParts) const;
9591
#endif
9692
#endif
93+
94+
private:
95+
// Handles for the mapped image.
96+
// These will be null if the image data is not mapped by the runtime (for example, provided via an external assembly probe).
97+
CLRMapViewHolder m_FileView;
98+
HandleHolder m_FileMap;
9799
};
98100

99101
// ConvertedImageView is for the case when we construct a loaded

src/coreclr/vm/util.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
#ifndef DACCESS_COMPILE
1717

18+
#if defined(TARGET_ANDROID)
19+
#include <android/log.h>
20+
#endif // defined(TARGET_ANDROID)
1821

1922
thread_local size_t t_ThreadType;
2023

@@ -177,10 +180,13 @@ void PrintToStdErrA(const char *pszString) {
177180
}
178181
CONTRACTL_END
179182

180-
HANDLE Handle = GetStdHandle(STD_ERROR_HANDLE);
181-
183+
#if defined(TARGET_ANDROID)
184+
__android_log_write(ANDROID_LOG_FATAL, MAIN_CLR_MODULE_NAME_A, pszString);
185+
#else
186+
HANDLE Handle = GetStdHandle(STD_ERROR_HANDLE);
182187
size_t len = strlen(pszString);
183188
NPrintToHandleA(Handle, pszString, len);
189+
#endif // defined(TARGET_ANDROID)
184190
}
185191

186192
void PrintToStdErrW(const WCHAR *pwzString)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy