mozglue/android/APKOpen.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * This custom library loading code is only meant to be called
michael@0 7 * during initialization. As a result, it takes no special
michael@0 8 * precautions to be threadsafe. Any of the library loading functions
michael@0 9 * like mozload should not be available to other code.
michael@0 10 */
michael@0 11
michael@0 12 #include <jni.h>
michael@0 13 #include <android/log.h>
michael@0 14 #include <sys/types.h>
michael@0 15 #include <sys/stat.h>
michael@0 16 #include <sys/mman.h>
michael@0 17 #include <sys/limits.h>
michael@0 18 #include <errno.h>
michael@0 19 #include <string.h>
michael@0 20 #include <stdio.h>
michael@0 21 #include <stdlib.h>
michael@0 22 #include <time.h>
michael@0 23 #include <fcntl.h>
michael@0 24 #include <unistd.h>
michael@0 25 #include <zlib.h>
michael@0 26 #include "dlfcn.h"
michael@0 27 #include "APKOpen.h"
michael@0 28 #include <sys/time.h>
michael@0 29 #include <sys/resource.h>
michael@0 30 #include <sys/prctl.h>
michael@0 31 #include "Zip.h"
michael@0 32 #include "sqlite3.h"
michael@0 33 #include "SQLiteBridge.h"
michael@0 34 #include "NSSBridge.h"
michael@0 35 #include "ElfLoader.h"
michael@0 36 #include "application.ini.h"
michael@0 37
michael@0 38 /* Android headers don't define RUSAGE_THREAD */
michael@0 39 #ifndef RUSAGE_THREAD
michael@0 40 #define RUSAGE_THREAD 1
michael@0 41 #endif
michael@0 42
michael@0 43 #ifndef RELEASE_BUILD
michael@0 44 /* Official builds have the debuggable flag set to false, which disables
michael@0 45 * the backtrace dumper from bionic. However, as it is useful for native
michael@0 46 * crashes happening before the crash reporter is registered, re-enable
michael@0 47 * it on non release builds (i.e. nightly and aurora).
michael@0 48 * Using a constructor so that it is re-enabled as soon as libmozglue.so
michael@0 49 * is loaded.
michael@0 50 */
michael@0 51 __attribute__((constructor))
michael@0 52 void make_dumpable() {
michael@0 53 prctl(PR_SET_DUMPABLE, 1);
michael@0 54 }
michael@0 55 #endif
michael@0 56
michael@0 57 extern "C" {
michael@0 58 /*
michael@0 59 * To work around http://code.google.com/p/android/issues/detail?id=23203
michael@0 60 * we don't link with the crt objects. In some configurations, this means
michael@0 61 * a lack of the __dso_handle symbol because it is defined there, and
michael@0 62 * depending on the android platform and ndk versions used, it may or may
michael@0 63 * not be defined in libc.so. In the latter case, we fail to link. Defining
michael@0 64 * it here as weak makes us provide the symbol when it's not provided by
michael@0 65 * the crt objects, making the change transparent for future NDKs that
michael@0 66 * would fix the original problem. On older NDKs, it is not a problem
michael@0 67 * either because the way __dso_handle was used was already broken (and
michael@0 68 * the custom linker works around it).
michael@0 69 */
michael@0 70 NS_EXPORT __attribute__((weak)) void *__dso_handle;
michael@0 71 }
michael@0 72
michael@0 73 typedef int mozglueresult;
michael@0 74
michael@0 75 enum StartupEvent {
michael@0 76 #define mozilla_StartupTimeline_Event(ev, z) ev,
michael@0 77 #include "StartupTimeline.h"
michael@0 78 #undef mozilla_StartupTimeline_Event
michael@0 79 MAX_STARTUP_EVENT_ID
michael@0 80 };
michael@0 81
michael@0 82 using namespace mozilla;
michael@0 83
michael@0 84 /**
michael@0 85 * Local TimeStamp::Now()-compatible implementation used to record timestamps
michael@0 86 * which will be passed to XRE_StartupTimelineRecord().
michael@0 87 */
michael@0 88
michael@0 89 static uint64_t TimeStamp_Now()
michael@0 90 {
michael@0 91 struct timespec ts;
michael@0 92 int rv = clock_gettime(CLOCK_MONOTONIC, &ts);
michael@0 93
michael@0 94 if (rv != 0) {
michael@0 95 return 0;
michael@0 96 }
michael@0 97
michael@0 98 uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000;
michael@0 99 return baseNs + (uint64_t)ts.tv_nsec;
michael@0 100 }
michael@0 101
michael@0 102 static struct mapping_info * lib_mapping = nullptr;
michael@0 103
michael@0 104 NS_EXPORT const struct mapping_info *
michael@0 105 getLibraryMapping()
michael@0 106 {
michael@0 107 return lib_mapping;
michael@0 108 }
michael@0 109
michael@0 110 void
michael@0 111 JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg)
michael@0 112 {
michael@0 113 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Throw\n");
michael@0 114 jclass cls = jenv->FindClass(classname);
michael@0 115 if (cls == nullptr) {
michael@0 116 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't find exception class (or exception pending) %s\n", classname);
michael@0 117 exit(FAILURE);
michael@0 118 }
michael@0 119 int rc = jenv->ThrowNew(cls, msg);
michael@0 120 if (rc < 0) {
michael@0 121 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Error throwing exception %s\n", msg);
michael@0 122 exit(FAILURE);
michael@0 123 }
michael@0 124 jenv->DeleteLocalRef(cls);
michael@0 125 }
michael@0 126
michael@0 127 #define JNI_STUBS
michael@0 128 #include "jni-stubs.inc"
michael@0 129 #undef JNI_STUBS
michael@0 130
michael@0 131 static void * xul_handle = nullptr;
michael@0 132 #ifndef MOZ_FOLD_LIBS
michael@0 133 static void * sqlite_handle = nullptr;
michael@0 134 static void * nspr_handle = nullptr;
michael@0 135 static void * plc_handle = nullptr;
michael@0 136 #else
michael@0 137 #define sqlite_handle nss_handle
michael@0 138 #define nspr_handle nss_handle
michael@0 139 #define plc_handle nss_handle
michael@0 140 #endif
michael@0 141 static void * nss_handle = nullptr;
michael@0 142
michael@0 143 template <typename T> inline void
michael@0 144 xul_dlsym(const char *symbolName, T *value)
michael@0 145 {
michael@0 146 *value = (T) (uintptr_t) __wrap_dlsym(xul_handle, symbolName);
michael@0 147 }
michael@0 148
michael@0 149 static int mapping_count = 0;
michael@0 150
michael@0 151 #define MAX_MAPPING_INFO 32
michael@0 152
michael@0 153 extern "C" void
michael@0 154 report_mapping(char *name, void *base, uint32_t len, uint32_t offset)
michael@0 155 {
michael@0 156 if (mapping_count >= MAX_MAPPING_INFO)
michael@0 157 return;
michael@0 158
michael@0 159 struct mapping_info *info = &lib_mapping[mapping_count++];
michael@0 160 info->name = strdup(name);
michael@0 161 info->base = (uintptr_t)base;
michael@0 162 info->len = len;
michael@0 163 info->offset = offset;
michael@0 164 }
michael@0 165
michael@0 166 static mozglueresult
michael@0 167 loadGeckoLibs(const char *apkName)
michael@0 168 {
michael@0 169 chdir(getenv("GRE_HOME"));
michael@0 170
michael@0 171 uint64_t t0 = TimeStamp_Now();
michael@0 172 struct rusage usage1_thread, usage1;
michael@0 173 getrusage(RUSAGE_THREAD, &usage1_thread);
michael@0 174 getrusage(RUSAGE_SELF, &usage1);
michael@0 175
michael@0 176 RefPtr<Zip> zip = ZipCollection::GetZip(apkName);
michael@0 177
michael@0 178 char *file = new char[strlen(apkName) + sizeof("!/assets/libxul.so")];
michael@0 179 sprintf(file, "%s!/assets/libxul.so", apkName);
michael@0 180 xul_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
michael@0 181 delete[] file;
michael@0 182
michael@0 183 if (!xul_handle) {
michael@0 184 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libxul!");
michael@0 185 return FAILURE;
michael@0 186 }
michael@0 187
michael@0 188 #define JNI_BINDINGS
michael@0 189 #include "jni-stubs.inc"
michael@0 190 #undef JNI_BINDINGS
michael@0 191
michael@0 192 void (*XRE_StartupTimelineRecord)(int, uint64_t);
michael@0 193 xul_dlsym("XRE_StartupTimelineRecord", &XRE_StartupTimelineRecord);
michael@0 194
michael@0 195 uint64_t t1 = TimeStamp_Now();
michael@0 196 struct rusage usage2_thread, usage2;
michael@0 197 getrusage(RUSAGE_THREAD, &usage2_thread);
michael@0 198 getrusage(RUSAGE_SELF, &usage2);
michael@0 199
michael@0 200 #define RUSAGE_TIMEDIFF(u1, u2, field) \
michael@0 201 ((u2.ru_ ## field.tv_sec - u1.ru_ ## field.tv_sec) * 1000 + \
michael@0 202 (u2.ru_ ## field.tv_usec - u1.ru_ ## field.tv_usec) / 1000)
michael@0 203
michael@0 204 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %lldms total, %ldms(%ldms) user, %ldms(%ldms) system, %ld(%ld) faults",
michael@0 205 (t1 - t0) / 1000000,
michael@0 206 RUSAGE_TIMEDIFF(usage1_thread, usage2_thread, utime),
michael@0 207 RUSAGE_TIMEDIFF(usage1, usage2, utime),
michael@0 208 RUSAGE_TIMEDIFF(usage1_thread, usage2_thread, stime),
michael@0 209 RUSAGE_TIMEDIFF(usage1, usage2, stime),
michael@0 210 usage2_thread.ru_majflt - usage1_thread.ru_majflt,
michael@0 211 usage2.ru_majflt - usage1.ru_majflt);
michael@0 212
michael@0 213 XRE_StartupTimelineRecord(LINKER_INITIALIZED, t0);
michael@0 214 XRE_StartupTimelineRecord(LIBRARIES_LOADED, t1);
michael@0 215 return SUCCESS;
michael@0 216 }
michael@0 217
michael@0 218 static mozglueresult loadNSSLibs(const char *apkName);
michael@0 219
michael@0 220 static mozglueresult
michael@0 221 loadSQLiteLibs(const char *apkName)
michael@0 222 {
michael@0 223 if (sqlite_handle)
michael@0 224 return SUCCESS;
michael@0 225
michael@0 226 #ifdef MOZ_FOLD_LIBS
michael@0 227 if (loadNSSLibs(apkName) != SUCCESS)
michael@0 228 return FAILURE;
michael@0 229 #else
michael@0 230 chdir(getenv("GRE_HOME"));
michael@0 231
michael@0 232 RefPtr<Zip> zip = ZipCollection::GetZip(apkName);
michael@0 233 if (!lib_mapping) {
michael@0 234 lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
michael@0 235 }
michael@0 236
michael@0 237 char *file = new char[strlen(apkName) + sizeof("!/assets/libmozsqlite3.so")];
michael@0 238 sprintf(file, "%s!/assets/libmozsqlite3.so", apkName);
michael@0 239 sqlite_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
michael@0 240 delete [] file;
michael@0 241
michael@0 242 if (!sqlite_handle) {
michael@0 243 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libmozsqlite3!");
michael@0 244 return FAILURE;
michael@0 245 }
michael@0 246 #endif
michael@0 247
michael@0 248 setup_sqlite_functions(sqlite_handle);
michael@0 249 return SUCCESS;
michael@0 250 }
michael@0 251
michael@0 252 static mozglueresult
michael@0 253 loadNSSLibs(const char *apkName)
michael@0 254 {
michael@0 255 if (nss_handle && nspr_handle && plc_handle)
michael@0 256 return SUCCESS;
michael@0 257
michael@0 258 chdir(getenv("GRE_HOME"));
michael@0 259
michael@0 260 RefPtr<Zip> zip = ZipCollection::GetZip(apkName);
michael@0 261 if (!lib_mapping) {
michael@0 262 lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
michael@0 263 }
michael@0 264
michael@0 265 char *file = new char[strlen(apkName) + sizeof("!/assets/libnss3.so")];
michael@0 266 sprintf(file, "%s!/assets/libnss3.so", apkName);
michael@0 267 nss_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
michael@0 268 delete [] file;
michael@0 269
michael@0 270 #ifndef MOZ_FOLD_LIBS
michael@0 271 file = new char[strlen(apkName) + sizeof("!/assets/libnspr4.so")];
michael@0 272 sprintf(file, "%s!/assets/libnspr4.so", apkName);
michael@0 273 nspr_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
michael@0 274 delete [] file;
michael@0 275
michael@0 276 file = new char[strlen(apkName) + sizeof("!/assets/libplc4.so")];
michael@0 277 sprintf(file, "%s!/assets/libplc4.so", apkName);
michael@0 278 plc_handle = __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
michael@0 279 delete [] file;
michael@0 280 #endif
michael@0 281
michael@0 282 if (!nss_handle) {
michael@0 283 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libnss3!");
michael@0 284 return FAILURE;
michael@0 285 }
michael@0 286
michael@0 287 #ifndef MOZ_FOLD_LIBS
michael@0 288 if (!nspr_handle) {
michael@0 289 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libnspr4!");
michael@0 290 return FAILURE;
michael@0 291 }
michael@0 292
michael@0 293 if (!plc_handle) {
michael@0 294 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libplc4!");
michael@0 295 return FAILURE;
michael@0 296 }
michael@0 297 #endif
michael@0 298
michael@0 299 return setup_nss_functions(nss_handle, nspr_handle, plc_handle);
michael@0 300 }
michael@0 301
michael@0 302 extern "C" NS_EXPORT void JNICALL
michael@0 303 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
michael@0 304 {
michael@0 305 const char* str;
michael@0 306 // XXX: java doesn't give us true UTF8, we should figure out something
michael@0 307 // better to do here
michael@0 308 str = jenv->GetStringUTFChars(jApkName, nullptr);
michael@0 309 if (str == nullptr)
michael@0 310 return;
michael@0 311
michael@0 312 int res = loadGeckoLibs(str);
michael@0 313 if (res != SUCCESS) {
michael@0 314 JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries");
michael@0 315 }
michael@0 316 jenv->ReleaseStringUTFChars(jApkName, str);
michael@0 317 }
michael@0 318
michael@0 319 extern "C" NS_EXPORT void JNICALL
michael@0 320 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
michael@0 321 if (jShouldExtract) {
michael@0 322 putenv("MOZ_LINKER_EXTRACT=1");
michael@0 323 }
michael@0 324
michael@0 325 const char* str;
michael@0 326 // XXX: java doesn't give us true UTF8, we should figure out something
michael@0 327 // better to do here
michael@0 328 str = jenv->GetStringUTFChars(jApkName, nullptr);
michael@0 329 if (str == nullptr)
michael@0 330 return;
michael@0 331
michael@0 332 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite start\n");
michael@0 333 mozglueresult rv = loadSQLiteLibs(str);
michael@0 334 if (rv != SUCCESS) {
michael@0 335 JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries");
michael@0 336 }
michael@0 337 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n");
michael@0 338 jenv->ReleaseStringUTFChars(jApkName, str);
michael@0 339 }
michael@0 340
michael@0 341 extern "C" NS_EXPORT void JNICALL
michael@0 342 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
michael@0 343 if (jShouldExtract) {
michael@0 344 putenv("MOZ_LINKER_EXTRACT=1");
michael@0 345 }
michael@0 346
michael@0 347 const char* str;
michael@0 348 // XXX: java doesn't give us true UTF8, we should figure out something
michael@0 349 // better to do here
michael@0 350 str = jenv->GetStringUTFChars(jApkName, nullptr);
michael@0 351 if (str == nullptr)
michael@0 352 return;
michael@0 353
michael@0 354 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss start\n");
michael@0 355 mozglueresult rv = loadNSSLibs(str);
michael@0 356 if (rv != SUCCESS) {
michael@0 357 JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries");
michael@0 358 }
michael@0 359 __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n");
michael@0 360 jenv->ReleaseStringUTFChars(jApkName, str);
michael@0 361 }
michael@0 362
michael@0 363 typedef void (*GeckoStart_t)(void *, const nsXREAppData *);
michael@0 364
michael@0 365 extern "C" NS_EXPORT void JNICALL
michael@0 366 Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs)
michael@0 367 {
michael@0 368 GeckoStart_t GeckoStart;
michael@0 369 xul_dlsym("GeckoStart", &GeckoStart);
michael@0 370 if (GeckoStart == nullptr)
michael@0 371 return;
michael@0 372 // XXX: java doesn't give us true UTF8, we should figure out something
michael@0 373 // better to do here
michael@0 374 int len = jenv->GetStringUTFLength(jargs);
michael@0 375 // GeckoStart needs to write in the args buffer, so we need a copy.
michael@0 376 char *args = (char *) malloc(len + 1);
michael@0 377 jenv->GetStringUTFRegion(jargs, 0, len, args);
michael@0 378 args[len] = '\0';
michael@0 379 GeckoStart(args, &sAppData);
michael@0 380 free(args);
michael@0 381 }
michael@0 382
michael@0 383 typedef int GeckoProcessType;
michael@0 384
michael@0 385 extern "C" NS_EXPORT mozglueresult
michael@0 386 ChildProcessInit(int argc, char* argv[])
michael@0 387 {
michael@0 388 int i;
michael@0 389 for (i = 0; i < (argc - 1); i++) {
michael@0 390 if (strcmp(argv[i], "-greomni"))
michael@0 391 continue;
michael@0 392
michael@0 393 i = i + 1;
michael@0 394 break;
michael@0 395 }
michael@0 396
michael@0 397 if (loadNSSLibs(argv[i]) != SUCCESS) {
michael@0 398 return FAILURE;
michael@0 399 }
michael@0 400 if (loadSQLiteLibs(argv[i]) != SUCCESS) {
michael@0 401 return FAILURE;
michael@0 402 }
michael@0 403 if (loadGeckoLibs(argv[i]) != SUCCESS) {
michael@0 404 return FAILURE;
michael@0 405 }
michael@0 406
michael@0 407 GeckoProcessType (*fXRE_StringToChildProcessType)(char*);
michael@0 408 xul_dlsym("XRE_StringToChildProcessType", &fXRE_StringToChildProcessType);
michael@0 409
michael@0 410 mozglueresult (*fXRE_InitChildProcess)(int, char**, GeckoProcessType);
michael@0 411 xul_dlsym("XRE_InitChildProcess", &fXRE_InitChildProcess);
michael@0 412
michael@0 413 GeckoProcessType proctype = fXRE_StringToChildProcessType(argv[--argc]);
michael@0 414
michael@0 415 return fXRE_InitChildProcess(argc, argv, proctype);
michael@0 416 }
michael@0 417

mercurial