added support for Android M loading libraries straight from APK/ZIP files

Until https://code.google.com/p/android/issues/detail?id=193009 is fixed, the
only way to know the path of the library inside the APK/ZIP file is to explore
the ZIP content.

However, there is no need to read the ZIP central directory. We can scan
backwards from the mapped offset until we find the local file header.
This commit is contained in:
Gregory Pakosz 2015-11-06 15:44:18 +01:00
parent e03e0adfed
commit 946b114876

View File

@ -202,6 +202,11 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
#define WAI_PROC_SELF_MAPS "/proc/self/maps"
#endif
#if defined(__ANDROID__) || defined(ANDROID)
#include <fcntl.h>
#include <sys/mman.h>
#endif
WAI_NOINLINE
WAI_FUNCSPEC
int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
@ -242,6 +247,43 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
break;
length = (int)strlen(resolved);
#if defined(__ANDROID__) || defined(ANDROID)
if (length > 4
&&buffer[length - 1] == 'k'
&&buffer[length - 2] == 'p'
&&buffer[length - 3] == 'a'
&&buffer[length - 4] == '.')
{
int fd = open(path, O_RDONLY);
char* begin;
char* p;
begin = mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0);
p = begin + offset;
while (p >= begin) // scan backwards
{
if (*((uint32_t*)p) == 0x04034b50UL) // local file header found
{
uint16_t length_ = *((uint16_t*)(p + 26));
if (length + 2 + length_ < sizeof(buffer))
{
memcpy(&buffer[length], "!/", 2);
memcpy(&buffer[length + 2], p + 30, length_);
length += 2 + length_;
}
break;
}
p -= 4;
}
munmap(begin, offset);
close(fd);
}
#endif
if (length <= capacity)
{
memcpy(out, resolved, length);