author | Brad Lassey <blassey@mozilla.com> |
Wed, 19 Jan 2011 17:32:58 -0500 | |
changeset 60884 | 6643235b98685dd6772000cff268a5d5ad2198fe |
parent 60883 | 6b5a47683b8829e8cf985ed4e4fbe1d2a88bfcc9 |
child 60885 | 9d41d0fa20ad757132d72a17cf0d3788b35f5c62 |
push id | unknown |
push user | unknown |
push date | unknown |
reviewers | dougt, blocking-fennec |
bugs | 623999 |
milestone | 2.0b10pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -189,36 +189,16 @@ find_cdir_entry (struct cdir_entry *entr if (letoh16(entry->filename_size) == name_size && !memcmp(entry->data, name, name_size)) return entry; entry = (struct cdir_entry *)((void *)entry + cdir_entry_size(entry)); } return NULL; } -static uint32_t simple_write(int fd, const void *buf, uint32_t count) -{ - uint32_t out_offset = 0; - while (out_offset < count) { - uint32_t written = write(fd, buf + out_offset, - count - out_offset); - if (written == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - continue; - else { - __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "simple_write failed"); - break; - } - } - - out_offset += written; - } - return out_offset; -} - #define SHELL_WRAPPER0(name) \ typedef void (*name ## _t)(JNIEnv *, jclass); \ static name ## _t f_ ## name; \ extern "C" NS_EXPORT void JNICALL \ Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc) \ { \ f_ ## name(jenv, jc); \ } @@ -262,16 +242,41 @@ SHELL_WRAPPER1(removeObserver, jstring) static void * xul_handle = NULL; static time_t apk_mtime = 0; #ifdef DEBUG extern "C" int extractLibs = 1; #else extern "C" int extractLibs = 0; #endif +#ifdef DEBUG +#define DEBUG_EXTRACT_LIBS 1 +#endif + +#ifdef DEBUG_EXTRACT_LIBS +static uint32_t simple_write(int fd, const void *buf, uint32_t count) +{ + uint32_t out_offset = 0; + while (out_offset < count) { + uint32_t written = write(fd, buf + out_offset, + count - out_offset); + if (written == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + continue; + else { + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "simple_write failed"); + break; + } + } + + out_offset += written; + } + return out_offset; +} + static void extractFile(const char * path, const struct cdir_entry *entry, void * data) { uint32_t size = letoh32(entry->uncompressed_size); struct stat status; if (!stat(path, &status) && status.st_size == size && @@ -321,16 +326,17 @@ extractFile(const char * path, const str ret = inflateEnd(&strm); if (ret != Z_OK) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateEnd failed: %s", strm.msg); close(fd); munmap(buf, 4096); } +#endif static void extractLib(const struct cdir_entry *entry, void * data, void * dest) { z_stream strm = { next_in: (Bytef *)data, avail_in: letoh32(entry->compressed_size), total_in: 0, @@ -417,38 +423,41 @@ lookupLibCacheFd(const char *libName) struct lib_cache_info *info = &cache_mapping[count]; if (!strcmp(libName, info->name)) return info->fd; } return -1; } static void -addLibCacheFd(const char *libName, int fd) +addLibCacheFd(const char *libName, int fd, uint32_t lib_size = 0, void* buffer = NULL) { ensureLibCache(); struct lib_cache_info *info = &cache_mapping[cache_count++]; strncpy(info->name, libName, MAX_LIB_CACHE_NAME_LEN - 1); info->fd = fd; + info->lib_size = lib_size; + info->buffer = buffer; } static void * mozload(const char * path, void *zip, struct cdir_entry *cdir_start, uint16_t cdir_entries) { #ifdef DEBUG struct timeval t0, t1; gettimeofday(&t0, 0); #endif struct cdir_entry *entry = find_cdir_entry(cdir_start, cdir_entries, path); struct local_file_header *file = (struct local_file_header *)(zip + letoh32(entry->offset)); void * data = ((void *)&file->data) + letoh16(file->filename_size) + letoh16(file->extra_field_size); void * handle; +#ifdef DEBUG_EXTRACT_LIBS if (extractLibs) { char fullpath[256]; snprintf(fullpath, 256, "%s/%s", getenv("CACHE_PATH"), path + 4); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "resolved %s to %s", path, fullpath); extractFile(fullpath, entry, data); handle = __wrap_dlopen(fullpath, RTLD_LAZY); if (!handle) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", fullpath, __wrap_dlerror()); @@ -457,34 +466,40 @@ static void * mozload(const char * path, __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)); #endif return handle; } - +#endif size_t offset = letoh32(entry->offset) + sizeof(*file) + letoh16(file->filename_size) + letoh16(file->extra_field_size); int fd = zip_fd; void * buf = NULL; uint32_t lib_size = letoh32(entry->uncompressed_size); + int cache_fd = 0; if (letoh16(file->compression) == DEFLATE) { - int cache_fd = lookupLibCacheFd(path + 4); + cache_fd = lookupLibCacheFd(path + 4); fd = cache_fd; if (fd < 0) { char fullpath[256]; snprintf(fullpath, 256, "%s/%s", getenv("CACHE_PATH"), path + 4); fd = open(fullpath, O_RDWR); struct stat status; if (stat(fullpath, &status) || status.st_size != lib_size || - apk_mtime > status.st_mtime) + apk_mtime > status.st_mtime) { + unlink(fullpath); fd = -1; + } else { + cache_fd = fd; + addLibCacheFd(path + 4, fd); + } } if (fd < 0) fd = createAshmem(lib_size, path); #ifdef DEBUG else __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s from cache", path + 4); #endif if (fd < 0) { @@ -499,30 +514,36 @@ static void * mozload(const char * path, close(fd); return NULL; } offset = 0; if (cache_fd < 0) { extractLib(entry, data, buf); - addLibCacheFd(path + 4, fd); + addLibCacheFd(path + 4, fd, lib_size, buf); } + // preload libxul, to avoid slowly demand-paging it + if (!strcmp(path, "lib/libxul.so")) + madvise(buf, entry->uncompressed_size, MADV_WILLNEED); data = buf; } #ifdef DEBUG __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s with len %d (0x%08x) and offset %d (0x%08x)", path, lib_size, lib_size, offset, offset); #endif handle = moz_mapped_dlopen(path, RTLD_LAZY, fd, data, lib_size, offset); if (!handle) __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", path, __wrap_dlerror()); - if (buf) + + // if we're extracting the libs to disk and cache_fd is not valid then + // keep this buffer around so it can be used to write to disk + if (buf && (!extractLibs || cache_fd >= 0)) munmap(buf, lib_size); #ifdef DEBUG gettimeofday(&t1, 0); __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) - (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)); #endif @@ -665,16 +686,46 @@ Java_org_mozilla_gecko_GeckoAppShell_loa // XXX: java doesn't give us true UTF8, we should figure out something // better to do here str = jenv->GetStringUTFChars(jApkName, NULL); if (str == NULL) return; loadLibs(str); jenv->ReleaseStringUTFChars(jApkName, str); + if (extractLibs && cache_mapping) { + if (!fork()) { + sleep(10); + nice(10); + int count = cache_count; + while (count--) { + struct lib_cache_info *info = &cache_mapping[count]; + if (!info->buffer) + continue; + + char fullpath[256]; + snprintf(fullpath, 256, "%s/%s", getenv("CACHE_PATH"), info->name); + char tmp_path[256]; + sprintf(tmp_path, "%s.tmp", fullpath); + int file_fd = open(tmp_path, O_CREAT | O_WRONLY); + // using sendfile would be preferable, but it doesn't seem to work + // with shared memory on any of the devices we've tested + uint32_t sent = write(file_fd, info->buffer, info->lib_size); + + munmap(info->buffer, info->lib_size); + info->buffer = 0; + close(file_fd); + if (sent == info->lib_size) + rename(tmp_path, fullpath); + else + unlink(tmp_path); + } + exit(0); + } + } } typedef int GeckoProcessType; typedef int nsresult; extern "C" NS_EXPORT int ChildProcessInit(int argc, char* argv[]) {
--- a/other-licenses/android/APKOpen.h +++ b/other-licenses/android/APKOpen.h @@ -48,13 +48,15 @@ struct mapping_info { const struct mapping_info * getLibraryMapping(); #define MAX_LIB_CACHE_ENTRIES 32 #define MAX_LIB_CACHE_NAME_LEN 32 struct lib_cache_info { char name[MAX_LIB_CACHE_NAME_LEN]; int fd; + uint32_t lib_size; + void* buffer; }; const struct lib_cache_info * getLibraryCache(); #endif /* APKOpen_h */
--- a/other-licenses/android/dlfcn.c +++ b/other-licenses/android/dlfcn.c @@ -49,18 +49,20 @@ static void set_dlerror(int err) { format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], linker_get_error()); dl_err_str = (const char *)&dl_err_buf[0]; } void *__wrap_dlopen(const char *filename, int flag) { +#ifdef DEBUG if (extractLibs) return dlopen(filename, flag); +#endif soinfo *ret; pthread_mutex_lock(&dl_lock); ret = find_library(filename); if (unlikely(ret == NULL)) { set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); } else {