-
Notifications
You must be signed in to change notification settings - Fork 564
Support DSOs embedded in the .apk #2154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/monodroid/jni/monodroid-glue.c
Outdated
| get_full_dso_path (const char *base_dir, const char *dso_path, mono_bool *needs_free) | ||
| { | ||
| void *libapp; | ||
| if (needs_free != NULL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternate consideration: so that you don't need to repeat if (needs_free != null) *needs_free=..., you can have it point to a temporary instead:
mono_bool _def_needs_free;
if (needs_free == NULL)
needs_free = &_def_needs_free;Then you can always access *needs_free without the check.
src/monodroid/jni/monodroid-glue.c
Outdated
| return NULL; | ||
|
|
||
| libapp = dlopen (libappso, RTLD_LAZY); | ||
| if (base_dir == NULL || dso_path [0] == MONODROID_PATH_SEPARATOR_CHAR) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Since I haven't tried to check...)
Can get_full_dso_path() be called from the Windows/Designer codepaths? If so, this could be a Windows path. Perhaps we need an is_path_rooted(const char*) function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is just a quick check "for now", to get the code working on device asap. I'll add the function to TODO
src/monodroid/jni/monodroid-glue.c
Outdated
|
|
||
| libapp = dlopen (libappso, RTLD_LAZY); | ||
| if (base_dir == NULL || dso_path [0] == MONODROID_PATH_SEPARATOR_CHAR) | ||
| return (char*)dso_path; // Absolute path, can't do much with it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Especially considering the eventual C++ migration, is this really a good idea, casting away const like this?
Should we instead make the dso_path non-const for sanity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and no. dso_path should be a const - we shouldn't modify it in any way. OTOH, the return value must be non-const since we may allocate it. In this case a conscious cast like this is OK - in the presence of the needs_free flag we make the intent explicit. The parameter const status is a promise we won't modify the parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think dso_path shouldn't be const here, as by the cast before returning it you remove the const and have no control of what happens with the returned value afterwards. And because the return value can be allocated and thus we need to call free on it later, you cannot return const char*. (or you can, but have to cast it when calling free, which I find less harmful as it is at the end of the life of it)
IIRC, once we switch to C++ you might return const pointer, as the delete operator can be used with the const pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's safer (now) to return char* and do the cast inside the function than rely on the caller to perform the cast - the caller has the boolean flag to tell them when to free the returned value. Granted, it's not ideal, but within the realm of C there's no good way to handle this situation. In C++ we can do what @radekdoulik suggests or use a wrapper class which will know what to do with the stored value.
| if (!mono_mkbundle_initialize_mono_api) | ||
| log_error (LOG_BUNDLE, "Missing initialize_mono_api in the application"); | ||
| static void* | ||
| load_dso (const char *path, int dl_flags, mono_bool skip_exists_check) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, as per previous digression, load_dso() implies -- to me -- that i'll load "from anywhere," while this only supports looking at filesystem locations. In keeping with the above, perhaps load_external_dso(), or load_file_dso()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And my previous reply applies here as well :)
src/monodroid/jni/monodroid-glue.c
Outdated
| #else | ||
| log_fatal (LOG_DEFAULT, "cannot find libmonosgen-2.0.so in override_dir: %s, app_libdir: %s nor in previously printed locations.", override_dirs[0], app_libdir); | ||
| TRY_LIBMONOSGEN (SYSTEM_LIB_PATH); | ||
| log_fatal (LOG_DEFAULT, "Cannot find '%'. Looked in the following locations:", MONO_SGEN_SO); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo? '%' --> '%s'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍, well spotted, thanks :)
|
Hmm, and the build failed because of |
dd03d38 to
29ecb9e
Compare
29ecb9e to
b35465d
Compare
|
The failure is because of a mono test crash that wasn't caught by NUnit: |
b35465d to
9393936
Compare
9393936 to
ab053de
Compare
|
|
||
| namespace EmbeddedDSOUnitTests | ||
| { | ||
| sealed class LocalBuilder : Builder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if these unit tests should be integrated with/moved into src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept them separate because the Android project used by those tests is also a standalone test in its own right (with instrumentation and such)
| [Test] | ||
| public void TestApplicationActuallyRan () | ||
| { | ||
| // We need some test to run the instrumentation - this way we know that the runtime loads and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we need a test.
Here's a better one: assert that if we're running on API >= 23, that there are no lib*.so files in whatever /data/data/@PACKAGE_NAME@/lib is (using appropriate logic to find that path).
This would help avoid "false positives," where we think it's working, but it's not, because the .so files were extracted when we thought they wouldn't be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call
tests/RunApkTests.targets
Outdated
| <Import Project="..\tests\CodeGen-Binding\Xamarin.Android.JcwGen-Tests\Xamarin.Android.JcwGen-Tests.projitems" Condition=" '$(AotAssemblies)' != 'True' " /> | ||
| <Import Project="..\tests\locales\Xamarin.Android.Locale-Tests\Xamarin.Android.Locale-Tests.projitems" Condition=" '$(AotAssemblies)' != 'True' " /> | ||
| <Import Project="..\tests\Xamarin.Forms-Performance-Integration\Droid\Xamarin.Forms.Performance.Integration.Droid.projitems" Condition=" '$(Configuration)' == 'Release' And '$(AotAssemblies)' != 'true' " /> | ||
| <Import Project="..\tests\EmbeddedDSOs\EmbeddedDSO\EmbeddedDSO.projitems" Condition=" '$(AotAssemblies)' != 'True' " /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This raises a good question:
Will this work with AOT'd assemblies? Meaning, does mono use us to find/load the appropriate libaot-mscorlib.dll.so/etc. files? I think it does...but it would probably be a good idea to run these tests when $(AotAssemblies)=True, to ensure that it works.
I think the Condition should be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it does. See here for a debug output for this PR on Android O:
09-07 12:31:04.940 21101 21101 D Mono : Image addref mscorlib[0xf205fcc0] -> mscorlib.dll[0xf2a8cd00]: 2
09-07 12:31:04.941 21101 21101 D Mono : Prepared to set up assembly 'mscorlib' (mscorlib.dll)
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="mscorlib.dll.so", flags=0x3, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonosgen-2.0.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work with AOT'd assemblies?
Yes, it does
Yay.
However, your snippet doesn't answer my question: for loading AOT'd assemblies, I'd expect a message that contains a substring along the lines of base.apk!/lib/x86/libaot-mscorlib.dll.so. I do not see any message in your snippet which contains that substring. Instead, every mention of libaot-mscorlib.dll.so is for the .__override__ directory, not within the .apk. As such, the snippet does not appear to answer my question/concern.
Additionally, you didn't reply to my final suggestion:
I think the Condition should be removed.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the full log excerpt which contains loads from the apk. The lookup directories are set up in the runtime initialization function and they already contain base paths inside the APK archive in embedded mode. So the load_dso_from_any_directories will look in them:
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.941 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found
09-07 12:31:04.941 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/mscorlib.dll.so" not found"
09-07 12:31:04.941 21101 21101 D linker : dlopen(name="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.942 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.942 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.942 21101 21101 D linker : dlopen(name="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.943 21101 21101 D linker : ... dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libaot-mscorlib.dll.so" not found
09-07 12:31:04.943 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.943 21101 21101 D linker : dlopen(name="/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so", flags=0x3, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonosgen-2.0.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.943 21101 21101 D linker : ... dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found
09-07 12:31:04.943 21101 21101 D linker : dlerror set to "dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found"
09-07 12:31:04.943 21101 21101 D linker : dlopen(name="/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.943 21101 21101 D linker : ... dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found
09-07 12:31:04.943 21101 21101 D linker : dlerror set to "dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found"
09-07 12:31:04.943 21101 21101 D linker : dlopen(name="/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.943 21101 21101 D linker : ... dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found
09-07 12:31:04.943 21101 21101 D linker : dlerror set to "dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found"
09-07 12:31:04.943 21101 21101 D linker : dlopen(name="/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.943 21101 21101 D linker : ... dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found
09-07 12:31:04.943 21101 21101 D linker : dlerror set to "dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found"
09-07 12:31:04.943 21101 21101 D linker : dlopen(name="/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.943 21101 21101 D linker : ... dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found
09-07 12:31:04.944 21101 21101 D linker : dlerror set to "dlopen failed: library "/home/grendel/vc/xamarin/xamarin-android/external/mono/sdks/out/android-x86-debug/lib/mono/aot-cache/x86/mscorlib.dll.so" not found"
09-07 12:31:04.944 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.944 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.944 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.944 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.944 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.944 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.944 21101 21101 D linker : dlopen(name="/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.944 21101 21101 D linker : ... dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found
09-07 12:31:04.944 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/user/0/com.xamarin.NotificationChannels/files/.__override__/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.944 21101 21101 D linker : dlopen(name="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libaot-mscorlib.dll.so", flags=0x1, extinfo=(null), caller="/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libmonodroid.so", caller_ns=classloader-namespace@0xf7579110) ...
09-07 12:31:04.944 21101 21101 D linker : ... dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libaot-mscorlib.dll.so" not found
09-07 12:31:04.944 21101 21101 D linker : dlerror set to "dlopen failed: library "/data/app/com.xamarin.NotificationChannels-WCBF9YhPQcjyUVKBgGNbYA==/base.apk!/lib/x86/libaot-mscorlib.dll.so" not found"
09-07 12:31:04.962 21101 21101 D Mono : Assembly mscorlib[0xf205fcc0] added to domain RootDomain, ref_count=1
Regarding the condtion - I don't know why it was put in there for all the other projects, so I can't make a decision :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@grendello wrote:
Regarding the condtion - I don't know why it was put in there for all the other projects, so I can't make a decision
The Condition is in there to not "unduly" prolong the build, because we believe that there isn't sufficient merit in running those tests under AOT scenarios (because AOT is time consuming).
Note that Mono.Android-Tests.projitems doesn't have the Condition, and thus is run for all configurations, because we believe there is merit in running that test under AOT.
I think that there is merit in running EmbeddedDSO.projitems when $(AotAssemblies)==True, because this test is very low-level and could easily break AOT if not done carefully.
As such, I think we should do:
<Import Project="..\tests\EmbeddedDSOs\EmbeddedDSO\EmbeddedDSO.projitems" />
src/monodroid/jni/monodroid-glue.c
Outdated
| static int android_api_level = 0; | ||
|
|
||
| // Values correspond to the CPU_KIND_* macros | ||
| static char* android_abi_names[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be handy to explicitly provide the array size:
static const char* android_abi_names[CPU_KIND_X86_64+1] = {That way if we add a CPU_KIND_FOO value and an element to the array, we'll get a warning unless we update the array size:
/* some time later... */
#define CPU_KIND_X86_64 ((unsigned short)6)
/* ... */
static const char *android_abi_names[CPU_KIND_X86_64+1] = {
/* ... */
"foo", /* added */
};
/* results in a compiler warning:
warning: excess elements in array initializer
"foo",
^---
*/What this won't do is ensure that indexes match as we expect. clang supports this syntax; not sure about gcc/C99:
static const char * android_abi_names[CPU_KIND_X86_64+1] = {
"*unknown*",
[CPU_KIND_ARM] = "armeabi-v7a",
[CPU_KIND_ARM64] = "arm64-v8a",
[CPU_KIND_MIPS] = "mips",
[CPU_KIND_X86] = "x86",
[CPU_KIND_X86_64] = "x86_64",
};There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea!
src/monodroid/jni/monodroid-glue.c
Outdated
| "x86", | ||
| "x86_64", | ||
| }; | ||
| #define ANDROID_ABI_NAMES_SIZE (sizeof(android_abi_names) / sizeof (char*)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"conventional" is to use (sizeof(android_abi_names) / sizeof (android_abi_names[0])), so that if the element type changes, ANDROID_ABI_NAMES_SIZE doesn't need to change.
| } | ||
| #endif | ||
| TRY_LIBMONOSGEN (app_libdir) | ||
| if (!embedded_dso_mode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition concerns me, in that it means that if a Debug build was using "embedded DSO support," that Debug build can't use Improved Fast Deployment, because we only look in the override directories when embedded_dso_mode==0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is incorrect. We look in override dirs in embedded mode. See the following:
https://github.com/grendello/xamarin-android/blob/issue1906/src/monodroid/jni/monodroid-glue.c#L890
https://github.com/grendello/xamarin-android/blob/issue1906/src/monodroid/jni/monodroid-glue.c#L3278
https://github.com/grendello/xamarin-android/blob/issue1906/src/monodroid/jni/monodroid-glue.c#L3293
https://github.com/grendello/xamarin-android/blob/issue1906/src/monodroid/jni/monodroid-glue.c#L3494
https://github.com/grendello/xamarin-android/blob/issue1906/src/monodroid/jni/monodroid-glue.c#L3996
I tested this PR in Debug mode :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested this PR in Debug mode :)
Which is wonderful! The problem is that my "static analysis" (trying to read this PR) doesn't easily see why that works, not easily, not obviously. Here, within get_libmonosgen_path(), when embedded_dso_mode==TRUE, how do we find .__override__/.../libmonosgen-2.0.so? Do we find libmonosgen-2.0.so within this function at all, or is it found "elsewhere"? If it is "elsewhere," where is that "elsewhere"?
Turns out, that "elsewhere" is in Java_mono_android_Runtime_init():
if (embedded_dso_mode) {
libmonosgen_handle = load_dso_from_any_directories (MONO_SGEN_SO, sgen_dlopen_flags);
}I wonder if things would be clear if instead of a get_libmonosgen_path() we had a load_libmonosgen(), so that the "find libmonosgen" and "load libmonosgen" logic weren't so far apart. :-/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be better - this code could use a lot of improvements all over the map. However, I don't want to muddle the actual topic of this particular PR with logic and code cleanup. I'd like to make such changes/improvements after we merge in the C++ PR. I purposefully stayed as close to original code when implementing this feature as possible (even though I often felt like rewriting large portions of what I saw - but that would mean going down the rabbit hole and making this PR something that cannot be properly reviewed)
src/monodroid/jni/monodroid-glue.c
Outdated
| free (full_name); | ||
| if (name == NULL) { | ||
| name = "libmonodroid.so"; | ||
| h = load_dso_from_override_dirs (name, dl_flags); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like there are a lot of places in this PR where we call load_dso_from_override_dirs() then load_dso_from_app_lib_dirs() if load_dso_from_override_dirs() fails.
Perhaps we should have a helper which does that? load_dso(), perhaps? (Which admittedly already exists, but I'm seriously getting confused trying to keep all these new functions straight.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is done on purpose - load_dso loads a specific DSO, with a path that's already determined. This is the "core" loader. The override and app directory functions do the searching - I don't want to cram those together. This is a clear separation and on build time the calls will be optimized out again.
src/monodroid/jni/monodroid-glue.c
Outdated
| if (!h && name && (strstr (name, ".dll.so") || strstr (name, ".exe.so"))) { | ||
| char *full_name2; | ||
| const char *basename; | ||
| h = load_dso_from_override_dirs (name, dl_flags); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like here again, we call load_dso_from_override_dirs() then call load_dso_from_app_lib_dirs() if the first call fails. This is a very common pattern; we should better support it.
| log_info (LOG_ASSEMBLY, "Trying to load library '%s'", full_name); | ||
| free (full_name); | ||
| if (name == NULL) { | ||
| name = "libmonodroid.so"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this if block. At a quick reading, it appears to set name="libmonodroid.so", then do...exactly what would be done when name != NULL. Why the duplication, instead of:
if (name == NULL) {
name = "libmonodroid.so";
}9cc55ca to
ecee315
Compare
|
build |
0f1e436 to
23edd75
Compare
src/monodroid/jni/monodroid-glue.c
Outdated
| static int android_api_level = 0; | ||
|
|
||
| // Values correspond to the CPU_KIND_* macros | ||
| static char* android_abi_names[CPU_KIND_X86_64+1] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm kinda surprised that not using const char doesn't result in a warning from the compiler. (Double negatives for the win?)
| return; | ||
| log_info (LOG_BUNDLE, "Attempting to load bundled app from %s", bundle_path); | ||
| libapp = load_dso (bundle_path, dlopen_flags, TRUE); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we free (bundle_path); bundle_path = NULL; here?
| log_fatal (LOG_BUNDLE, "bundled app initialization error"); | ||
| exit (FATAL_EXIT_CANNOT_LOAD_BUNDLE); | ||
| } else { | ||
| log_info (LOG_BUNDLE, "bundled app not found in the APK, ignoring."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should we ignore here and not exit? Why would embedded_dso_mode matter for this check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short version: if we exit, embedded DSO stops working.
Long version: in non-embedded mode the decision to set up a bundled app is based on the presence, on the filesystem, of the bundled app .so file - we stat the filesystem to make the decision. In embedded mode we cannot do the stat inside the zip/apk and so we always dlopen all the .so and see if that succeeded. Since it would always fail here, if the application wasn't a bundled one, the DSO mode would never work. As it currently stands, there's no other way to make this work except to ignore the failure to load the bundle DSO. It can (and should) be improved (as stated in the comment above the setup_bundled_app function) by allowing the code to detect if we're inside a bundled app by other means - for instance an environment variable added to the environment file when building the app. This change, however, is beyond scope of this PR.
|
|
||
| mono_mkbundle_initialize_mono_api = dlsym (libapp, "initialize_mono_api"); | ||
| if (!mono_mkbundle_initialize_mono_api) | ||
| log_error (LOG_BUNDLE, "Missing initialize_mono_api in the application"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this also exit the process?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is another instance of not changing/fixing the existing logic/code. I agree we should exit, but it's not the topic of this PR.
|
|
||
| mono_mkbundle_init = dlsym (libapp, "mono_mkbundle_init"); | ||
| if (!mono_mkbundle_init) | ||
| log_error (LOG_BUNDLE, "Missing mono_mkbundle_init in the application"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this also exit the process?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto :)
src/monodroid/jni/monodroid-glue.c
Outdated
| handle = load_dso (full_path, dlopen_flags, FALSE); | ||
| free (full_path); | ||
| found = load_profiler_from_handle (handle, desc, mname); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary ;.
src/monodroid/jni/monodroid-glue.c
Outdated
|
|
||
| static void | ||
| for_each_apk (JNIEnv *env, jobjectArray runtimeApks, void (*handler) (const char *apk, int index, int apk_count)) | ||
| for_each_apk (JNIEnv *env, jobjectArray runtimeApks, void *user_data, void (*handler) (const char *apk, int index, int apk_count, void *user_data)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the user_data parameter conventionally the last parameter, e.g. g_qsort_with_data(), g_list_foreach()?
Rephrased, I'd expect:
for_each_apk (JNIEnv *env, jobjectArray runtimeApks, void (*handler) (const char *apk, int index, int apk_count, void *user_data), void *user_data)
src/monodroid/jni/monodroid-glue.c
Outdated
| static void | ||
| add_apk_libdir (const char *apk, int index, int apk_count, void *user_data) | ||
| { | ||
| if (user_data == NULL || index < 0 || index >= app_lib_directories_size) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...or should we just assert() these?
Context: dotnet#1906 Fixes: dotnet#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.
23edd75 to
853c7c5
Compare
| } | ||
|
|
||
| int monodroid_dylib_mono_init (struct DylibMono *mono_imports, const char *libmono_path) | ||
| int monodroid_dylib_mono_init (struct DylibMono *mono_imports, void *libmono_handle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ops, this API change breaks Java.Interop here https://github.com/xamarin/java.interop/blob/master/src/java-interop/java-interop-gc-bridge-mono.c#L266
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can update Java.Interop. I wonder though, whether we consider libmonodroid API as public, because it can break someone else too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When we migrate to C++ there will be more changes here. That code becomes a class and I added extern "C" versions of the functions - we can standarize/stabilize the API after the migration.
Context: dotnet#2154 Fixes: dotnet#2415 Currently, in order to activate the embedded DSO support, one has to perform the following actions manually: 1. Add the `android:extractNativeLibs="false"` attribute to the `<application>` element in the `Properties/AndroidManifest.xml` file. 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 ~~ Changes ~~ The presence of `android:extractNativeLibs="false"` in `AndroidManifest.xml` should setup all the extra "stuff" so developers don't have to manually do it. `android:extractNativeLibs="false"` would automatically do the following: 1. `.so` will be appended to `$(AndroidStoreUncompressedFileExtensions)`. Both the `<Aapt/>` and `<BuildApk/>` MSBuild tasks use this property. 3. A new generated file in `$(IntermediateOutputPath)` will add `__XA_DSO_IN_APK=1` as an `@(AndroidEnvironment)` build item. I also added an MSBuild test to verify these changes are happening. I was also able to update `tests/EmbeddedDSOs` to rely on the new functionality.
Context: dotnet#2154 Fixes: dotnet#2415 Currently, in order to activate the embedded DSO support, one has to perform the following actions manually: 1. Add the `android:extractNativeLibs="false"` attribute to the `<application>` element in the `Properties/AndroidManifest.xml` file. 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 ~~ Changes ~~ The presence of `android:extractNativeLibs="false"` in `AndroidManifest.xml` should setup all the extra "stuff" so developers don't have to manually do it. `android:extractNativeLibs="false"` would automatically do the following: 1. `.so` will be appended to `$(AndroidStoreUncompressedFileExtensions)`. Both the `<Aapt/>` and `<BuildApk/>` MSBuild tasks use this property. 3. A new generated file in `$(IntermediateOutputPath)` will add `__XA_DSO_IN_APK=1` as an `@(AndroidEnvironment)` build item. The problem here is with incremental builds... If `_GenerateJavaStubs` is skipped, we still need to know if `android:extractNativeLibs` is set. To make this work, I added a `CacheFile` property on the `GenerateJavaStubs` MSBuild task. It writes a simple XML document in `$(IntermediateOutputPath)javastubs.cache` such as: <Properties> <EmbeddedDSOsEnabled>True</EmbeddedDSOsEnabled> </Properties> The file will not exist at all unless the value is `True`, which will prevent this feature from impacting build times. I also added an MSBuild test to verify these changes are happening. I was also able to update `tests/EmbeddedDSOs` to rely on the new functionality. ~~ Other Changes ~~ I updated `_GenerateJavaStubs` to follow the "stamp" file convention of using `$(_AndroidStampDirectory)_GenerateJavaStubs.stamp`.
Fixes: #2415 Context: #2154 Currently, in order to activate the embedded Dynamic Shared Object (DSO) support, one has to perform the following actions manually (see also 95ca102): 1. Add the `android:extractNativeLibs="false"` attribute to the `<application>` element within `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 containing: __XA_DSO_IN_APK=1 Instead of requiring these three separate steps, the presence of the `//application[@android:extractNativeLibs='false']` attribute within `AndroidManifest.xml` should instead be used as the "feature" toggle; when `extractNativeLibs` is false, then `$(AndroidStoreUncompressedFileExtensions)` should be automatically updated and the `__XA_DSO_IN_APK` environment variable should automatically exported: 1. Append the value `.so` to `$(AndroidStoreUncompressedFileExtensions)`. Both of the `<Aapt/>` and `<BuildApk/>` MSBuild tasks use this property. 2. Create a new file within `$(IntermediateOutputPath)` containing the string `__XA_DSO_IN_APK=1`, and add this new file to `@(AndroidEnvironment)` so that `__XA_DSO_IN_APK` is set. The problem here is with incremental builds; if the `_GenerateJavaStubs` target is skipped, we still need to know if `//application/@android:extractNativeLibs` is set. To make this work, I added a `CacheFile` property on the `<GenerateJavaStubs/>` MSBuild task. It writes a simple XML document to `$(IntermediateOutputPath)javastubs.cache`, such as: <Properties> <EmbeddedDSOsEnabled>True</EmbeddedDSOsEnabled> </Properties> The file will not exist at all unless the value is `True`, which will prevent this feature from impacting build times. I also added an MSBuild test to verify these changes are happening. I also updated `tests/EmbeddedDSOs` to rely on the new functionality. Finally, I updated the `_GenerateJavaStubs` target to follow the "stamp" file convention of using `$(_AndroidStampDirectory)_GenerateJavaStubs.stamp`.
Context: #1906
Support DSOs embedded in the APK
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 thelibraries 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:
.so) files must be stored uncompressed in the APK<application android:extractNativeLibs="false"/>must be present-pflagpassed to
zipaligntakes care of thatThis commit also implements
libmonodroidsuport for loading our DSOs directlyfrom the APK. This operation mode is enabled by the presence of the
__XA_DSO_IN_APKenvironment variable. This variable is inserted into theapplication's environment by way of placing it in the environment file (a file
part of the XA project that is marked with the
AndroidEnvironmentbuildaction). 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.xmlfileAdd the following property to the project file:
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.