1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mozglue/android/APKOpen.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,417 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * This custom library loading code is only meant to be called 1.10 + * during initialization. As a result, it takes no special 1.11 + * precautions to be threadsafe. Any of the library loading functions 1.12 + * like mozload should not be available to other code. 1.13 + */ 1.14 + 1.15 +#include <jni.h> 1.16 +#include <android/log.h> 1.17 +#include <sys/types.h> 1.18 +#include <sys/stat.h> 1.19 +#include <sys/mman.h> 1.20 +#include <sys/limits.h> 1.21 +#include <errno.h> 1.22 +#include <string.h> 1.23 +#include <stdio.h> 1.24 +#include <stdlib.h> 1.25 +#include <time.h> 1.26 +#include <fcntl.h> 1.27 +#include <unistd.h> 1.28 +#include <zlib.h> 1.29 +#include "dlfcn.h" 1.30 +#include "APKOpen.h" 1.31 +#include <sys/time.h> 1.32 +#include <sys/resource.h> 1.33 +#include <sys/prctl.h> 1.34 +#include "Zip.h" 1.35 +#include "sqlite3.h" 1.36 +#include "SQLiteBridge.h" 1.37 +#include "NSSBridge.h" 1.38 +#include "ElfLoader.h" 1.39 +#include "application.ini.h" 1.40 + 1.41 +/* Android headers don't define RUSAGE_THREAD */ 1.42 +#ifndef RUSAGE_THREAD 1.43 +#define RUSAGE_THREAD 1 1.44 +#endif 1.45 + 1.46 +#ifndef RELEASE_BUILD 1.47 +/* Official builds have the debuggable flag set to false, which disables 1.48 + * the backtrace dumper from bionic. However, as it is useful for native 1.49 + * crashes happening before the crash reporter is registered, re-enable 1.50 + * it on non release builds (i.e. nightly and aurora). 1.51 + * Using a constructor so that it is re-enabled as soon as libmozglue.so 1.52 + * is loaded. 1.53 + */ 1.54 +__attribute__((constructor)) 1.55 +void make_dumpable() { 1.56 + prctl(PR_SET_DUMPABLE, 1); 1.57 +} 1.58 +#endif 1.59 + 1.60 +extern "C" { 1.61 +/* 1.62 + * To work around http://code.google.com/p/android/issues/detail?id=23203 1.63 + * we don't link with the crt objects. In some configurations, this means 1.64 + * a lack of the __dso_handle symbol because it is defined there, and 1.65 + * depending on the android platform and ndk versions used, it may or may 1.66 + * not be defined in libc.so. In the latter case, we fail to link. Defining 1.67 + * it here as weak makes us provide the symbol when it's not provided by 1.68 + * the crt objects, making the change transparent for future NDKs that 1.69 + * would fix the original problem. On older NDKs, it is not a problem 1.70 + * either because the way __dso_handle was used was already broken (and 1.71 + * the custom linker works around it). 1.72 + */ 1.73 + NS_EXPORT __attribute__((weak)) void *__dso_handle; 1.74 +} 1.75 + 1.76 +typedef int mozglueresult; 1.77 + 1.78 +enum StartupEvent { 1.79 +#define mozilla_StartupTimeline_Event(ev, z) ev, 1.80 +#include "StartupTimeline.h" 1.81 +#undef mozilla_StartupTimeline_Event 1.82 + MAX_STARTUP_EVENT_ID 1.83 +}; 1.84 + 1.85 +using namespace mozilla; 1.86 + 1.87 +/** 1.88 + * Local TimeStamp::Now()-compatible implementation used to record timestamps 1.89 + * which will be passed to XRE_StartupTimelineRecord(). 1.90 + */ 1.91 + 1.92 +static uint64_t TimeStamp_Now() 1.93 +{ 1.94 + struct timespec ts; 1.95 + int rv = clock_gettime(CLOCK_MONOTONIC, &ts); 1.96 + 1.97 + if (rv != 0) { 1.98 + return 0; 1.99 + } 1.100 + 1.101 + uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000; 1.102 + return baseNs + (uint64_t)ts.tv_nsec; 1.103 +} 1.104 + 1.105 +static struct mapping_info * lib_mapping = nullptr; 1.106 + 1.107 +NS_EXPORT const struct mapping_info * 1.108 +getLibraryMapping() 1.109 +{ 1.110 + return lib_mapping; 1.111 +} 1.112 + 1.113 +void 1.114 +JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg) 1.115 +{ 1.116 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Throw\n"); 1.117 + jclass cls = jenv->FindClass(classname); 1.118 + if (cls == nullptr) { 1.119 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't find exception class (or exception pending) %s\n", classname); 1.120 + exit(FAILURE); 1.121 + } 1.122 + int rc = jenv->ThrowNew(cls, msg); 1.123 + if (rc < 0) { 1.124 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Error throwing exception %s\n", msg); 1.125 + exit(FAILURE); 1.126 + } 1.127 + jenv->DeleteLocalRef(cls); 1.128 +} 1.129 + 1.130 +#define JNI_STUBS 1.131 +#include "jni-stubs.inc" 1.132 +#undef JNI_STUBS 1.133 + 1.134 +static void * xul_handle = nullptr; 1.135 +#ifndef MOZ_FOLD_LIBS 1.136 +static void * sqlite_handle = nullptr; 1.137 +static void * nspr_handle = nullptr; 1.138 +static void * plc_handle = nullptr; 1.139 +#else 1.140 +#define sqlite_handle nss_handle 1.141 +#define nspr_handle nss_handle 1.142 +#define plc_handle nss_handle 1.143 +#endif 1.144 +static void * nss_handle = nullptr; 1.145 + 1.146 +template <typename T> inline void 1.147 +xul_dlsym(const char *symbolName, T *value) 1.148 +{ 1.149 + *value = (T) (uintptr_t) __wrap_dlsym(xul_handle, symbolName); 1.150 +} 1.151 + 1.152 +static int mapping_count = 0; 1.153 + 1.154 +#define MAX_MAPPING_INFO 32 1.155 + 1.156 +extern "C" void 1.157 +report_mapping(char *name, void *base, uint32_t len, uint32_t offset) 1.158 +{ 1.159 + if (mapping_count >= MAX_MAPPING_INFO) 1.160 + return; 1.161 + 1.162 + struct mapping_info *info = &lib_mapping[mapping_count++]; 1.163 + info->name = strdup(name); 1.164 + info->base = (uintptr_t)base; 1.165 + info->len = len; 1.166 + info->offset = offset; 1.167 +} 1.168 + 1.169 +static mozglueresult 1.170 +loadGeckoLibs(const char *apkName) 1.171 +{ 1.172 + chdir(getenv("GRE_HOME")); 1.173 + 1.174 + uint64_t t0 = TimeStamp_Now(); 1.175 + struct rusage usage1_thread, usage1; 1.176 + getrusage(RUSAGE_THREAD, &usage1_thread); 1.177 + getrusage(RUSAGE_SELF, &usage1); 1.178 + 1.179 + RefPtr<Zip> zip = ZipCollection::GetZip(apkName); 1.180 + 1.181 + char *file = new char[strlen(apkName) + sizeof("!/assets/libxul.so")]; 1.182 + sprintf(file, "%s!/assets/libxul.so", apkName); 1.183 + xul_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); 1.184 + delete[] file; 1.185 + 1.186 + if (!xul_handle) { 1.187 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libxul!"); 1.188 + return FAILURE; 1.189 + } 1.190 + 1.191 +#define JNI_BINDINGS 1.192 +#include "jni-stubs.inc" 1.193 +#undef JNI_BINDINGS 1.194 + 1.195 + void (*XRE_StartupTimelineRecord)(int, uint64_t); 1.196 + xul_dlsym("XRE_StartupTimelineRecord", &XRE_StartupTimelineRecord); 1.197 + 1.198 + uint64_t t1 = TimeStamp_Now(); 1.199 + struct rusage usage2_thread, usage2; 1.200 + getrusage(RUSAGE_THREAD, &usage2_thread); 1.201 + getrusage(RUSAGE_SELF, &usage2); 1.202 + 1.203 +#define RUSAGE_TIMEDIFF(u1, u2, field) \ 1.204 + ((u2.ru_ ## field.tv_sec - u1.ru_ ## field.tv_sec) * 1000 + \ 1.205 + (u2.ru_ ## field.tv_usec - u1.ru_ ## field.tv_usec) / 1000) 1.206 + 1.207 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %lldms total, %ldms(%ldms) user, %ldms(%ldms) system, %ld(%ld) faults", 1.208 + (t1 - t0) / 1000000, 1.209 + RUSAGE_TIMEDIFF(usage1_thread, usage2_thread, utime), 1.210 + RUSAGE_TIMEDIFF(usage1, usage2, utime), 1.211 + RUSAGE_TIMEDIFF(usage1_thread, usage2_thread, stime), 1.212 + RUSAGE_TIMEDIFF(usage1, usage2, stime), 1.213 + usage2_thread.ru_majflt - usage1_thread.ru_majflt, 1.214 + usage2.ru_majflt - usage1.ru_majflt); 1.215 + 1.216 + XRE_StartupTimelineRecord(LINKER_INITIALIZED, t0); 1.217 + XRE_StartupTimelineRecord(LIBRARIES_LOADED, t1); 1.218 + return SUCCESS; 1.219 +} 1.220 + 1.221 +static mozglueresult loadNSSLibs(const char *apkName); 1.222 + 1.223 +static mozglueresult 1.224 +loadSQLiteLibs(const char *apkName) 1.225 +{ 1.226 + if (sqlite_handle) 1.227 + return SUCCESS; 1.228 + 1.229 +#ifdef MOZ_FOLD_LIBS 1.230 + if (loadNSSLibs(apkName) != SUCCESS) 1.231 + return FAILURE; 1.232 +#else 1.233 + chdir(getenv("GRE_HOME")); 1.234 + 1.235 + RefPtr<Zip> zip = ZipCollection::GetZip(apkName); 1.236 + if (!lib_mapping) { 1.237 + lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping)); 1.238 + } 1.239 + 1.240 + char *file = new char[strlen(apkName) + sizeof("!/assets/libmozsqlite3.so")]; 1.241 + sprintf(file, "%s!/assets/libmozsqlite3.so", apkName); 1.242 + sqlite_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); 1.243 + delete [] file; 1.244 + 1.245 + if (!sqlite_handle) { 1.246 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libmozsqlite3!"); 1.247 + return FAILURE; 1.248 + } 1.249 +#endif 1.250 + 1.251 + setup_sqlite_functions(sqlite_handle); 1.252 + return SUCCESS; 1.253 +} 1.254 + 1.255 +static mozglueresult 1.256 +loadNSSLibs(const char *apkName) 1.257 +{ 1.258 + if (nss_handle && nspr_handle && plc_handle) 1.259 + return SUCCESS; 1.260 + 1.261 + chdir(getenv("GRE_HOME")); 1.262 + 1.263 + RefPtr<Zip> zip = ZipCollection::GetZip(apkName); 1.264 + if (!lib_mapping) { 1.265 + lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping)); 1.266 + } 1.267 + 1.268 + char *file = new char[strlen(apkName) + sizeof("!/assets/libnss3.so")]; 1.269 + sprintf(file, "%s!/assets/libnss3.so", apkName); 1.270 + nss_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); 1.271 + delete [] file; 1.272 + 1.273 +#ifndef MOZ_FOLD_LIBS 1.274 + file = new char[strlen(apkName) + sizeof("!/assets/libnspr4.so")]; 1.275 + sprintf(file, "%s!/assets/libnspr4.so", apkName); 1.276 + nspr_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); 1.277 + delete [] file; 1.278 + 1.279 + file = new char[strlen(apkName) + sizeof("!/assets/libplc4.so")]; 1.280 + sprintf(file, "%s!/assets/libplc4.so", apkName); 1.281 + plc_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY); 1.282 + delete [] file; 1.283 +#endif 1.284 + 1.285 + if (!nss_handle) { 1.286 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libnss3!"); 1.287 + return FAILURE; 1.288 + } 1.289 + 1.290 +#ifndef MOZ_FOLD_LIBS 1.291 + if (!nspr_handle) { 1.292 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libnspr4!"); 1.293 + return FAILURE; 1.294 + } 1.295 + 1.296 + if (!plc_handle) { 1.297 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libplc4!"); 1.298 + return FAILURE; 1.299 + } 1.300 +#endif 1.301 + 1.302 + return setup_nss_functions(nss_handle, nspr_handle, plc_handle); 1.303 +} 1.304 + 1.305 +extern "C" NS_EXPORT void JNICALL 1.306 +Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName) 1.307 +{ 1.308 + const char* str; 1.309 + // XXX: java doesn't give us true UTF8, we should figure out something 1.310 + // better to do here 1.311 + str = jenv->GetStringUTFChars(jApkName, nullptr); 1.312 + if (str == nullptr) 1.313 + return; 1.314 + 1.315 + int res = loadGeckoLibs(str); 1.316 + if (res != SUCCESS) { 1.317 + JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries"); 1.318 + } 1.319 + jenv->ReleaseStringUTFChars(jApkName, str); 1.320 +} 1.321 + 1.322 +extern "C" NS_EXPORT void JNICALL 1.323 +Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) { 1.324 + if (jShouldExtract) { 1.325 + putenv("MOZ_LINKER_EXTRACT=1"); 1.326 + } 1.327 + 1.328 + const char* str; 1.329 + // XXX: java doesn't give us true UTF8, we should figure out something 1.330 + // better to do here 1.331 + str = jenv->GetStringUTFChars(jApkName, nullptr); 1.332 + if (str == nullptr) 1.333 + return; 1.334 + 1.335 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite start\n"); 1.336 + mozglueresult rv = loadSQLiteLibs(str); 1.337 + if (rv != SUCCESS) { 1.338 + JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries"); 1.339 + } 1.340 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n"); 1.341 + jenv->ReleaseStringUTFChars(jApkName, str); 1.342 +} 1.343 + 1.344 +extern "C" NS_EXPORT void JNICALL 1.345 +Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) { 1.346 + if (jShouldExtract) { 1.347 + putenv("MOZ_LINKER_EXTRACT=1"); 1.348 + } 1.349 + 1.350 + const char* str; 1.351 + // XXX: java doesn't give us true UTF8, we should figure out something 1.352 + // better to do here 1.353 + str = jenv->GetStringUTFChars(jApkName, nullptr); 1.354 + if (str == nullptr) 1.355 + return; 1.356 + 1.357 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss start\n"); 1.358 + mozglueresult rv = loadNSSLibs(str); 1.359 + if (rv != SUCCESS) { 1.360 + JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries"); 1.361 + } 1.362 + __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n"); 1.363 + jenv->ReleaseStringUTFChars(jApkName, str); 1.364 +} 1.365 + 1.366 +typedef void (*GeckoStart_t)(void *, const nsXREAppData *); 1.367 + 1.368 +extern "C" NS_EXPORT void JNICALL 1.369 +Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs) 1.370 +{ 1.371 + GeckoStart_t GeckoStart; 1.372 + xul_dlsym("GeckoStart", &GeckoStart); 1.373 + if (GeckoStart == nullptr) 1.374 + return; 1.375 + // XXX: java doesn't give us true UTF8, we should figure out something 1.376 + // better to do here 1.377 + int len = jenv->GetStringUTFLength(jargs); 1.378 + // GeckoStart needs to write in the args buffer, so we need a copy. 1.379 + char *args = (char *) malloc(len + 1); 1.380 + jenv->GetStringUTFRegion(jargs, 0, len, args); 1.381 + args[len] = '\0'; 1.382 + GeckoStart(args, &sAppData); 1.383 + free(args); 1.384 +} 1.385 + 1.386 +typedef int GeckoProcessType; 1.387 + 1.388 +extern "C" NS_EXPORT mozglueresult 1.389 +ChildProcessInit(int argc, char* argv[]) 1.390 +{ 1.391 + int i; 1.392 + for (i = 0; i < (argc - 1); i++) { 1.393 + if (strcmp(argv[i], "-greomni")) 1.394 + continue; 1.395 + 1.396 + i = i + 1; 1.397 + break; 1.398 + } 1.399 + 1.400 + if (loadNSSLibs(argv[i]) != SUCCESS) { 1.401 + return FAILURE; 1.402 + } 1.403 + if (loadSQLiteLibs(argv[i]) != SUCCESS) { 1.404 + return FAILURE; 1.405 + } 1.406 + if (loadGeckoLibs(argv[i]) != SUCCESS) { 1.407 + return FAILURE; 1.408 + } 1.409 + 1.410 + GeckoProcessType (*fXRE_StringToChildProcessType)(char*); 1.411 + xul_dlsym("XRE_StringToChildProcessType", &fXRE_StringToChildProcessType); 1.412 + 1.413 + mozglueresult (*fXRE_InitChildProcess)(int, char**, GeckoProcessType); 1.414 + xul_dlsym("XRE_InitChildProcess", &fXRE_InitChildProcess); 1.415 + 1.416 + GeckoProcessType proctype = fXRE_StringToChildProcessType(argv[--argc]); 1.417 + 1.418 + return fXRE_InitChildProcess(argc, argv, proctype); 1.419 +} 1.420 +