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;

0 commit comments

Comments
 (0)