Skip to content

Commit 23edd75

Browse files
committed
Support DSOs embedded in the APK
Context: #1906 Fixes: #1906 Android API 23 introduced a new way of dealing with the native shared libraries shipped in the APK. Before that API level, the libraries would be always extraced and placed in the application data directory, thus occupying more space than necessary. API 23 added a new manifest `<application>` element attribute, `android:extractNativeLibs`, which if set makes Android not extract the libraries to the filesystem. API 23 added a way to 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 present * DSOs in the APK must be aligned on the memory page boundary (the `-p` flag passed to `zipalign` takes care of that This commit also implements `libmonodroid` 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 variable is inserted into the application's environment by way of placing it in the environment file (a file part of the XA project that is marked with the `AndroidEnvironment` build action). In that 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 in the APK itself. Currently, in order to activate the above mode, one has to perform the following actions manually: * Add the `android:extractNativeLibs="false"` attribute to the `<application>` element in the `Properties/AndroidManifest.xml` file * Add the following property to the project file: <AndroidStoreUncompressedFileExtensions>.so</AndroidStoreUncompressedFileExtensions> * 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.
1 parent 24158d0 commit 23edd75

File tree

32 files changed

+1158
-186
lines changed

32 files changed

+1158
-186
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)