1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * This custom library loading code is only meant to be called
7 * during initialization. As a result, it takes no special
8 * precautions to be threadsafe. Any of the library loading functions
9 * like mozload should not be available to other code.
13 #include <android/log.h>
14 #include <sys/types.h>
17 #include <sys/limits.h>
28 #include <sys/syscall.h>
29 #include <sys/resource.h>
30 #include <sys/prctl.h>
33 #include "BaseProfiler.h"
34 #include "application.ini.h"
36 #include "mozilla/arm.h"
37 #include "mozilla/Bootstrap.h"
38 #include "mozilla/Printf.h"
39 #include "mozilla/Sprintf.h"
40 #include "mozilla/TimeStamp.h"
41 #include "mozilla/Try.h"
42 #include "mozilla/UniquePtr.h"
43 #include "XREChildData.h"
45 /* Android headers don't define RUSAGE_THREAD */
47 # define RUSAGE_THREAD 1
50 #ifndef RELEASE_OR_BETA
51 /* Official builds have the debuggable flag set to false, which disables
52 * the backtrace dumper from bionic. However, as it is useful for native
53 * crashes happening before the crash reporter is registered, re-enable
54 * it on non release builds (i.e. nightly and aurora).
55 * Using a constructor so that it is re-enabled as soon as libmozglue.so
58 __attribute__((constructor
)) void make_dumpable() { prctl(PR_SET_DUMPABLE
, 1); }
61 typedef int mozglueresult
;
63 using LoadGeckoLibsResult
=
64 mozilla::Result
<mozilla::Ok
, mozilla::BootstrapError
>;
67 #define mozilla_StartupTimeline_Event(ev, z) ev,
68 #include "StartupTimeline.h"
69 #undef mozilla_StartupTimeline_Event
73 using namespace mozilla
;
75 void JNI_Throw(JNIEnv
* jenv
, const char* classname
, const char* msg
) {
76 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad", "Throw\n");
77 jclass cls
= jenv
->FindClass(classname
);
80 ANDROID_LOG_ERROR
, "GeckoLibLoad",
81 "Couldn't find exception class (or exception pending) %s\n", classname
);
84 int rc
= jenv
->ThrowNew(cls
, msg
);
86 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad",
87 "Error throwing exception %s\n", msg
);
90 jenv
->DeleteLocalRef(cls
);
97 void abortThroughJava(const char* msg
) {
98 struct sigaction sigact
= {};
99 if (__wrap_sigaction(SIGSEGV
, nullptr, &sigact
)) {
100 return; // sigaction call failed.
104 if ((sigact
.sa_flags
& SA_SIGINFO
) &&
105 __wrap_dladdr(reinterpret_cast<void*>(sigact
.sa_sigaction
), &info
) &&
106 info
.dli_fname
&& strstr(info
.dli_fname
, "libxul.so")) {
107 return; // Existing signal handler is in libxul (i.e. we have crash
111 JNIEnv
* env
= nullptr;
113 sJavaVM
->AttachCurrentThreadAsDaemon(&env
, nullptr) != JNI_OK
) {
117 if (!env
|| env
->PushLocalFrame(2) != JNI_OK
) {
121 jclass loader
= env
->FindClass("org/mozilla/gecko/mozglue/GeckoLoader");
127 env
->GetStaticMethodID(loader
, "abort", "(Ljava/lang/String;)V");
128 jstring str
= env
->NewStringUTF(msg
);
131 env
->CallStaticVoidMethod(loader
, method
, str
);
134 env
->PopLocalFrame(nullptr);
137 Bootstrap::UniquePtr gBootstrap
;
138 #ifndef MOZ_FOLD_LIBS
139 static void* sqlite_handle
= nullptr;
140 static void* nspr_handle
= nullptr;
141 static void* plc_handle
= nullptr;
143 # define sqlite_handle nss_handle
144 # define nspr_handle nss_handle
145 # define plc_handle nss_handle
147 static void* nss_handle
= nullptr;
149 static UniquePtr
<char[]> getUnpackedLibraryName(const char* libraryName
) {
150 static const char* libdir
= getenv("MOZ_ANDROID_LIBDIR");
152 size_t len
= strlen(libdir
) + 1 /* path separator */ + strlen(libraryName
) +
153 1; /* null terminator */
154 auto file
= MakeUnique
<char[]>(len
);
155 snprintf(file
.get(), len
, "%s/%s", libdir
, libraryName
);
159 static void* dlopenLibrary(const char* libraryName
) {
160 return __wrap_dlopen(getUnpackedLibraryName(libraryName
).get(),
161 RTLD_GLOBAL
| RTLD_LAZY
);
164 static void EnsureBaseProfilerInitialized() {
165 // There is no single entry-point into C++ code on Android.
166 // Instead, GeckoThread and GeckoLibLoader call various functions to load
167 // libraries one-by-one.
168 // We want to capture all that library loading in the profiler, so we need to
169 // kick off the base profiler at the beginning of whichever function is called
171 // We currently assume that all these functions are called on the same thread.
172 static bool sInitialized
= false;
177 // The stack depth we observe here will be determined by the stack of
178 // whichever caller enters this code first. In practice this means that we may
179 // miss some root-most frames, which hopefully shouldn't ruin profiling.
181 mozilla::baseprofiler::profiler_init(&stackBase
);
185 static LoadGeckoLibsResult
loadGeckoLibs() {
186 TimeStamp t0
= TimeStamp::Now();
187 struct rusage usage1_thread
, usage1
;
188 getrusage(RUSAGE_THREAD
, &usage1_thread
);
189 getrusage(RUSAGE_SELF
, &usage1
);
191 static const char* libxul
= getenv("MOZ_ANDROID_LIBDIR_OVERRIDE");
194 GetBootstrap(libxul
? libxul
: getUnpackedLibraryName("libxul.so").get(),
195 LibLoadingStrategy::ReadAhead
));
197 TimeStamp t1
= TimeStamp::Now();
198 struct rusage usage2_thread
, usage2
;
199 getrusage(RUSAGE_THREAD
, &usage2_thread
);
200 getrusage(RUSAGE_SELF
, &usage2
);
202 #define RUSAGE_TIMEDIFF(u1, u2, field) \
203 ((u2.ru_##field.tv_sec - u1.ru_##field.tv_sec) * 1000 + \
204 (u2.ru_##field.tv_usec - u1.ru_##field.tv_usec) / 1000)
206 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad",
207 "Loaded libs in %fms total, %ldms(%ldms) user, "
208 "%ldms(%ldms) system, %ld(%ld) faults",
209 (t1
- t0
).ToMilliseconds(),
210 RUSAGE_TIMEDIFF(usage1_thread
, usage2_thread
, utime
),
211 RUSAGE_TIMEDIFF(usage1
, usage2
, utime
),
212 RUSAGE_TIMEDIFF(usage1_thread
, usage2_thread
, stime
),
213 RUSAGE_TIMEDIFF(usage1
, usage2
, stime
),
214 usage2_thread
.ru_majflt
- usage1_thread
.ru_majflt
,
215 usage2
.ru_majflt
- usage1
.ru_majflt
);
217 gBootstrap
->XRE_StartupTimelineRecord(LINKER_INITIALIZED
, t0
);
218 gBootstrap
->XRE_StartupTimelineRecord(LIBRARIES_LOADED
, t1
);
222 static mozglueresult
loadNSSLibs();
224 static mozglueresult
loadSQLiteLibs() {
225 if (sqlite_handle
) return SUCCESS
;
228 if (loadNSSLibs() != SUCCESS
) return FAILURE
;
231 sqlite_handle
= dlopenLibrary("libmozsqlite3.so");
232 if (!sqlite_handle
) {
233 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad",
234 "Couldn't get a handle to libmozsqlite3!");
242 static mozglueresult
loadNSSLibs() {
243 if (nss_handle
&& nspr_handle
&& plc_handle
) return SUCCESS
;
245 nss_handle
= dlopenLibrary("libnss3.so");
247 #ifndef MOZ_FOLD_LIBS
248 nspr_handle
= dlopenLibrary("libnspr4.so");
250 plc_handle
= dlopenLibrary("libplc4.so");
254 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad",
255 "Couldn't get a handle to libnss3!");
259 #ifndef MOZ_FOLD_LIBS
261 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad",
262 "Couldn't get a handle to libnspr4!");
267 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad",
268 "Couldn't get a handle to libplc4!");
276 extern "C" APKOPEN_EXPORT
void MOZ_JNICALL
277 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(
278 JNIEnv
* jenv
, jclass jGeckoAppShellClass
) {
279 EnsureBaseProfilerInitialized();
281 jenv
->GetJavaVM(&sJavaVM
);
283 LoadGeckoLibsResult res
= loadGeckoLibs();
288 const BootstrapError
& errorInfo
= res
.inspectErr();
290 auto msg
= errorInfo
.match(
291 [](const nsresult
& aRv
) {
292 return Smprintf("Error loading Gecko libraries: nsresult 0x%08X",
295 [](const DLErrorType
& aErr
) {
296 return Smprintf("Error loading Gecko libraries: %s", aErr
.get());
299 JNI_Throw(jenv
, "java/lang/Exception", msg
.get());
302 extern "C" APKOPEN_EXPORT
void MOZ_JNICALL
303 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(
304 JNIEnv
* jenv
, jclass jGeckoAppShellClass
) {
305 EnsureBaseProfilerInitialized();
307 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad", "Load sqlite start\n");
308 mozglueresult rv
= loadSQLiteLibs();
310 JNI_Throw(jenv
, "java/lang/Exception", "Error loading sqlite libraries");
312 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad", "Load sqlite done\n");
315 extern "C" APKOPEN_EXPORT
void MOZ_JNICALL
316 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(
317 JNIEnv
* jenv
, jclass jGeckoAppShellClass
) {
318 EnsureBaseProfilerInitialized();
320 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad", "Load nss start\n");
321 mozglueresult rv
= loadNSSLibs();
323 JNI_Throw(jenv
, "java/lang/Exception", "Error loading nss libraries");
325 __android_log_print(ANDROID_LOG_ERROR
, "GeckoLibLoad", "Load nss done\n");
328 static char** CreateArgvFromObjectArray(JNIEnv
* jenv
, jobjectArray jargs
,
330 size_t stringCount
= jenv
->GetArrayLength(jargs
);
333 *length
= stringCount
;
340 char** argv
= new char*[stringCount
+ 1];
342 argv
[stringCount
] = nullptr;
344 for (size_t ix
= 0; ix
< stringCount
; ix
++) {
345 jstring string
= (jstring
)(jenv
->GetObjectArrayElement(jargs
, ix
));
346 const char* rawString
= jenv
->GetStringUTFChars(string
, nullptr);
347 const int strLength
= jenv
->GetStringUTFLength(string
);
348 argv
[ix
] = strndup(rawString
, strLength
);
349 jenv
->ReleaseStringUTFChars(string
, rawString
);
350 jenv
->DeleteLocalRef(string
);
356 static void FreeArgv(char** argv
, int argc
) {
357 for (int ix
= 0; ix
< argc
; ix
++) {
358 // String was allocated with strndup, so need to use free to deallocate.
364 extern "C" APKOPEN_EXPORT
void MOZ_JNICALL
365 Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(
366 JNIEnv
* jenv
, jclass jc
, jobjectArray jargs
, int prefsFd
, int prefMapFd
,
367 int ipcFd
, int crashFd
, bool xpcshell
, jstring outFilePath
) {
368 EnsureBaseProfilerInitialized();
371 char** argv
= CreateArgvFromObjectArray(jenv
, jargs
, &argc
);
374 if (gBootstrap
== nullptr) {
375 FreeArgv(argv
, argc
);
380 ElfLoader::Singleton
.ExpectShutdown(false);
382 const char* outFilePathRaw
= nullptr;
384 MOZ_ASSERT(outFilePath
);
385 outFilePathRaw
= jenv
->GetStringUTFChars(outFilePath
, nullptr);
387 gBootstrap
->GeckoStart(jenv
, argv
, argc
, sAppData
, xpcshell
,
389 if (outFilePathRaw
) {
390 jenv
->ReleaseStringUTFChars(outFilePath
, outFilePathRaw
);
393 ElfLoader::Singleton
.ExpectShutdown(true);
396 gBootstrap
->XRE_SetAndroidChildFds(jenv
,
397 {prefsFd
, prefMapFd
, ipcFd
, crashFd
});
398 gBootstrap
->XRE_SetProcessType(argv
[argc
- 1]);
400 XREChildData childData
;
401 gBootstrap
->XRE_InitChildProcess(argc
- 1, argv
, &childData
);
404 #ifdef MOZ_WIDGET_ANDROID
405 # ifdef MOZ_PROFILE_GENERATE
406 gBootstrap
->XRE_WriteLLVMProfData();
410 FreeArgv(argv
, argc
);
413 extern "C" APKOPEN_EXPORT mozglueresult
ChildProcessInit(int argc
,
415 EnsureBaseProfilerInitialized();
417 if (loadNSSLibs() != SUCCESS
) {
420 if (loadSQLiteLibs() != SUCCESS
) {
423 if (loadGeckoLibs().isErr()) {
427 gBootstrap
->XRE_SetProcessType(argv
[--argc
]);
429 XREChildData childData
;
430 return NS_FAILED(gBootstrap
->XRE_InitChildProcess(argc
, argv
, &childData
));
433 // Does current process name end with ':media'?
434 static bool IsMediaProcess() {
435 pid_t pid
= getpid();
437 SprintfLiteral(str
, "/proc/%d/cmdline", pid
);
438 FILE* f
= fopen(str
, "r");
440 fgets(str
, sizeof(str
), f
);
442 const size_t strLen
= strlen(str
);
443 const char suffix
[] = ":media";
444 const size_t suffixLen
= sizeof(suffix
) - 1;
445 if (strLen
>= suffixLen
&&
446 !strncmp(str
+ strLen
- suffixLen
, suffix
, suffixLen
)) {
453 #ifndef SYS_rt_tgsigqueueinfo
454 # define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
456 /* Copy of http://androidxref.com/7.1.1_r6/xref/bionic/linker/debugger.cpp#262,
457 * with debuggerd related code stripped.
459 * Copyright (C) 2008 The Android Open Source Project
460 * All rights reserved.
462 * Redistribution and use in source and binary forms, with or without
463 * modification, are permitted provided that the following conditions
465 * * Redistributions of source code must retain the above copyright
466 * notice, this list of conditions and the following disclaimer.
467 * * Redistributions in binary form must reproduce the above copyright
468 * notice, this list of conditions and the following disclaimer in
469 * the documentation and/or other materials provided with the
472 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
473 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
474 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
475 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
476 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
477 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
478 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
479 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
480 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
481 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
482 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
485 static void CatchFatalSignals(int num
, siginfo_t
* info
, void* context
) {
486 // It's possible somebody cleared the SA_SIGINFO flag, which would mean
487 // our "info" arg holds an undefined value.
488 struct sigaction action
= {};
489 if ((sigaction(num
, nullptr, &action
) < 0) ||
490 !(action
.sa_flags
& SA_SIGINFO
)) {
494 // We need to return from the signal handler so that debuggerd can dump the
495 // thread that crashed, but returning here does not guarantee that the signal
496 // will be thrown again, even for SIGSEGV and friends, since the signal could
497 // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
498 // preserve the SA_SIGINFO contents.
499 signal(num
, SIG_DFL
);
503 memset(&si
, 0, sizeof(si
));
504 si
.si_code
= SI_USER
;
505 si
.si_pid
= getpid();
506 si
.si_uid
= getuid();
508 } else if (info
->si_code
>= 0 || info
->si_code
== SI_TKILL
) {
509 // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
510 // that contain commit 66dd34a (3.9+). The manpage claims to only allow
511 // negative si_code values that are not SI_TKILL, but 66dd34a changed the
512 // check to allow all si_code values in calls coming from inside the house.
515 int rc
= syscall(SYS_rt_tgsigqueueinfo
, getpid(), gettid(), num
, info
);
517 __android_log_print(ANDROID_LOG_FATAL
, "mozglue",
518 "failed to resend signal during crash: %s",
524 extern "C" APKOPEN_EXPORT
void MOZ_JNICALL
525 Java_org_mozilla_gecko_mozglue_GeckoLoader_suppressCrashDialog(JNIEnv
* jenv
,
527 MOZ_RELEASE_ASSERT(IsMediaProcess(),
528 "Suppress crash dialog only for media process");
529 // Restoring to SIG_DFL will crash on x86/Android M devices (see bug 1374556)
530 // so copy Android code
531 // (http://androidxref.com/7.1.1_r6/xref/bionic/linker/debugger.cpp#302). See
532 // comments above CatchFatalSignals() for copyright notice.
533 struct sigaction action
;
534 memset(&action
, 0, sizeof(action
));
535 sigemptyset(&action
.sa_mask
);
536 action
.sa_sigaction
= &CatchFatalSignals
;
537 action
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
539 // Use the alternate signal stack if available so we can catch stack
541 action
.sa_flags
|= SA_ONSTACK
;
543 sigaction(SIGABRT
, &action
, nullptr);
544 sigaction(SIGBUS
, &action
, nullptr);
545 sigaction(SIGFPE
, &action
, nullptr);
546 sigaction(SIGILL
, &action
, nullptr);
547 sigaction(SIGSEGV
, &action
, nullptr);
548 #if defined(SIGSTKFLT)
549 sigaction(SIGSTKFLT
, &action
, nullptr);
551 sigaction(SIGTRAP
, &action
, nullptr);