Skip to content

Commit 95ca102

Browse files
grendellojonpryor
authored andcommitted
Support DSOs embedded in the .apk (#2154)
Context: #1906 Android v6.0 (API-23) introduced a new way of dealing with the native shared libraries shipped in the `.apk`. Before API-23, the libraries would be always extracted and placed in the application data directory, thus occupying more space than necessary. API-23 added a new `AndroidManifest.xml` attribute, `//application/@android:extractNativeLibs`, which if set to `false` makes Android *not* extract the libraries to the filesystem. API-23 added a way to instead load those libraries directly from the `.apk`. In order to support that there are a few requirements which this commit implements: * DSO (`.so`) files must be *stored uncompressed* in the `.apk`. * `<application android:extractNativeLibs="false"/>` must be set * DSOs in the `.apk` must be aligned on the memory page boundary; `zipalign -p` takes care of this. This commit also implements `libmonodroid.so` suport for loading our DSOs directly from the `.apk`. This operation mode is enabled by the presence of the `$__XA_DSO_IN_APK` environment variable. This environment variable is inserted into the application's environment by way of placing it in the environment file (a file part of the Xamarin.Android App project that has the `@(AndroidEnvironment)` build action). In this mode, the DSOs are *no longer* looked up in the application data directory but only in the override directories (if the APK is built in Debug configuration) and the `.apk` itself. Currently, in order to activate the above mode, one has to perform the following actions manually: 1. Add the `android:extractNativeLibs="false"` attribute to the `<application>/` element in `Properties/AndroidManifest.xml`. 2. Add the following property to the project file: <AndroidStoreUncompressedFileExtensions>.so</AndroidStoreUncompressedFileExtensions> 3. Add an android environment file to the project with a line which says __XA_DSO_IN_APK=1 After that the application should work in the embedded DSO mode without problems. A couple of tests are provided to test building and execution of embedded DSO application on device, as well as to validate the built `.apk`. TODO: fix issue #1906 by "nicely integrating" this support with the Xamarin.Android build system so that the above manual steps are not required. The exact semantics still need to be determined.
1 parent d8f1783 commit 95ca102

File tree

32 files changed

+1151
-184
lines changed

32 files changed

+1151
-184
lines changed

Xamarin.Android-Tests.sln

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Performance-Tests", "Perfor
7676
EndProject
7777
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "timing", "build-tools\timing\timing.csproj", "{37CAA28C-40BE-4253-BA68-CC5D7316A617}"
7878
EndProject
79+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbeddedDSO", "tests\EmbeddedDSOs\EmbeddedDSO\EmbeddedDSO.csproj", "{056ED976-618F-4A3E-910E-AA25230C2296}"
80+
EndProject
81+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbeddedDSO-UnitTests", "tests\EmbeddedDSOs\EmbeddedDSO-UnitTests\EmbeddedDSO-UnitTests.csproj", "{B160F0E7-799A-4EB9-92B8-D71623C7674A}"
82+
EndProject
7983
Global
8084
GlobalSection(SharedMSBuildProjectFiles) = preSolution
8185
tests\Xamarin.Forms-Performance-Integration\Xamarin.Forms.Performance.Integration.projitems*{195be9c2-1f91-40dc-bd6d-de860bf083fb}*SharedItemsImports = 13
@@ -194,6 +198,14 @@ Global
194198
{37CAA28C-40BE-4253-BA68-CC5D7316A617}.Debug|Any CPU.Build.0 = Debug|Any CPU
195199
{37CAA28C-40BE-4253-BA68-CC5D7316A617}.Release|Any CPU.ActiveCfg = Release|Any CPU
196200
{37CAA28C-40BE-4253-BA68-CC5D7316A617}.Release|Any CPU.Build.0 = Release|Any CPU
201+
{056ED976-618F-4A3E-910E-AA25230C2296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
202+
{056ED976-618F-4A3E-910E-AA25230C2296}.Debug|Any CPU.Build.0 = Debug|Any CPU
203+
{056ED976-618F-4A3E-910E-AA25230C2296}.Release|Any CPU.ActiveCfg = Release|Any CPU
204+
{056ED976-618F-4A3E-910E-AA25230C2296}.Release|Any CPU.Build.0 = Release|Any CPU
205+
{B160F0E7-799A-4EB9-92B8-D71623C7674A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
206+
{B160F0E7-799A-4EB9-92B8-D71623C7674A}.Debug|Any CPU.Build.0 = Debug|Any CPU
207+
{B160F0E7-799A-4EB9-92B8-D71623C7674A}.Release|Any CPU.ActiveCfg = Release|Any CPU
208+
{B160F0E7-799A-4EB9-92B8-D71623C7674A}.Release|Any CPU.Build.0 = Release|Any CPU
197209
EndGlobalSection
198210
GlobalSection(SolutionProperties) = preSolution
199211
HideSolutionNode = FALSE

build-tools/scripts/RunTests.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717
<ItemGroup>
1818
<_TestAssembly Include="$(_TopDir)\bin\Test$(Configuration)\Xamarin.Android.Build.Tests.dll" />
1919
<_TestAssembly Include="$(_TopDir)\bin\Test$(Configuration)\CodeBehind\CodeBehindUnitTests.dll" />
20+
<_TestAssembly Include="$(_TopDir)\bin\Test$(Configuration)\EmbeddedDSO\EmbeddedDSOUnitTests.dll" />
2021
<_ApkTestProject Include="$(_TopDir)\src\Mono.Android\Test\Mono.Android-Tests.csproj" />
2122
<_ApkTestProject Include="$(_TopDir)\tests\CodeGen-Binding\Xamarin.Android.JcwGen-Tests\Xamarin.Android.JcwGen-Tests.csproj" />
2223
<_ApkTestProject Include="$(_TopDir)\tests\CodeGen-MkBundle\Xamarin.Android.MakeBundle-Tests\Xamarin.Android.MakeBundle-Tests.csproj" />
2324
<_ApkTestProject Include="$(_TopDir)\tests\locales\Xamarin.Android.Locale-Tests\Xamarin.Android.Locale-Tests.csproj" />
2425
<_ApkTestProject Include="$(_TopDir)\tests\BCL-Tests\Xamarin.Android.Bcl-Tests\Xamarin.Android.Bcl-Tests.csproj" />
2526
<_ApkTestProject Include="$(_TopDir)\tests\Xamarin.Forms-Performance-Integration\Droid\Xamarin.Forms.Performance.Integration.Droid.csproj" />
27+
<_ApkTestProject Include="$(_TopDir)\tests\EmbeddedDSOs\EmbeddedDSO\EmbeddedDSO.csproj" />
2628
<_ApkTestProjectAot Include="$(_TopDir)\src\Mono.Android\Test\Mono.Android-Tests.csproj" />
2729
<_ApkTestProjectBundle Include="$(_TopDir)\src\Mono.Android\Test\Mono.Android-Tests.csproj" />
2830
</ItemGroup>

src/Xamarin.Android.Build.Tasks/Tasks/AndroidZipAlign.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ protected override string GenerateCommandLineCommands ()
3636
string sourceFilename = Path.GetFileNameWithoutExtension (Source.ItemSpec);
3737
if (sourceFilename.EndsWith (strSignedUnaligned))
3838
sourceFilename = sourceFilename.Remove (sourceFilename.Length - strSignedUnaligned.Length);
39-
return string.Format ("{0} \"{1}\" \"{2}{3}{4}-Signed.apk\"",
39+
return string.Format ("-p {0} \"{1}\" \"{2}{3}{4}-Signed.apk\"",
4040
Alignment, Source.ItemSpec, DestinationDirectory.ItemSpec, Path.DirectorySeparatorChar, sourceFilename);
4141
}
4242

src/monodroid/jni/dylib-mono.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,18 @@ void monodroid_dylib_mono_free (struct DylibMono *mono_imports)
3333
free (mono_imports);
3434
}
3535

36-
int monodroid_dylib_mono_init (struct DylibMono *mono_imports, const char *libmono_path)
36+
int monodroid_dylib_mono_init (struct DylibMono *mono_imports, void *libmono_handle)
3737
{
3838
int symbols_missing = FALSE;
3939

4040
if (mono_imports == NULL)
4141
return FALSE;
4242

43-
memset (mono_imports, 0, sizeof (*mono_imports));
44-
45-
/*
46-
* We need to use RTLD_GLOBAL so that libmono-profiler-log.so can resolve
47-
* symbols against the Mono library we're loading.
48-
*/
49-
mono_imports->dl_handle = dlopen (libmono_path, RTLD_LAZY | RTLD_GLOBAL);
50-
51-
if (!mono_imports->dl_handle) {
43+
if (libmono_handle == NULL)
5244
return FALSE;
53-
}
5445

46+
memset (mono_imports, 0, sizeof (*mono_imports));
47+
mono_imports->dl_handle = libmono_handle;
5548
mono_imports->version = sizeof (*mono_imports);
5649

5750
log_info (LOG_DEFAULT, "Loading Mono symbols...");

src/monodroid/jni/dylib-mono.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,6 @@ struct DylibMono {
348348

349349
MONO_API struct DylibMono* monodroid_dylib_mono_new (const char *libmono_path);
350350
MONO_API void monodroid_dylib_mono_free (struct DylibMono *mono_imports);
351-
int monodroid_dylib_mono_init (struct DylibMono *mono_imports, const char *libmono_path);
351+
int monodroid_dylib_mono_init (struct DylibMono *mono_imports, void *libmono_handle);
352352

353353
#endif /* INC_MONODROID_DYLIB_MONO_H */

0 commit comments

Comments
 (0)