summaryrefslogtreecommitdiffstats
path: root/mozglue/android
diff options
context:
space:
mode:
Diffstat (limited to 'mozglue/android')
-rw-r--r--mozglue/android/APKOpen.cpp546
-rw-r--r--mozglue/android/APKOpen.h29
-rw-r--r--mozglue/android/Ashmem.cpp73
-rw-r--r--mozglue/android/Ashmem.h22
-rw-r--r--mozglue/android/NativeCrypto.cpp140
-rw-r--r--mozglue/android/NativeCrypto.h58
-rw-r--r--mozglue/android/SharedMemNatives.cpp80
-rw-r--r--mozglue/android/moz.build71
-rw-r--r--mozglue/android/nsGeckoUtils.cpp152
-rw-r--r--mozglue/android/pbkdf2_sha256.c389
-rw-r--r--mozglue/android/pbkdf2_sha256.h70
11 files changed, 1630 insertions, 0 deletions
diff --git a/mozglue/android/APKOpen.cpp b/mozglue/android/APKOpen.cpp
new file mode 100644
index 0000000000..04d3577029
--- /dev/null
+++ b/mozglue/android/APKOpen.cpp
@@ -0,0 +1,546 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This custom library loading code is only meant to be called
+ * during initialization. As a result, it takes no special
+ * precautions to be threadsafe. Any of the library loading functions
+ * like mozload should not be available to other code.
+ */
+
+#include <jni.h>
+#include <android/log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/limits.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <zlib.h>
+#include "dlfcn.h"
+#include "APKOpen.h"
+#include <sys/time.h>
+#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
+#include "sqlite3.h"
+#include "Linker.h"
+#include "BaseProfiler.h"
+#include "application.ini.h"
+
+#include "mozilla/arm.h"
+#include "mozilla/Bootstrap.h"
+#include "mozilla/Sprintf.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/UniquePtr.h"
+#include "XREChildData.h"
+
+/* Android headers don't define RUSAGE_THREAD */
+#ifndef RUSAGE_THREAD
+# define RUSAGE_THREAD 1
+#endif
+
+#ifndef RELEASE_OR_BETA
+/* Official builds have the debuggable flag set to false, which disables
+ * the backtrace dumper from bionic. However, as it is useful for native
+ * crashes happening before the crash reporter is registered, re-enable
+ * it on non release builds (i.e. nightly and aurora).
+ * Using a constructor so that it is re-enabled as soon as libmozglue.so
+ * is loaded.
+ */
+__attribute__((constructor)) void make_dumpable() { prctl(PR_SET_DUMPABLE, 1); }
+#endif
+
+typedef int mozglueresult;
+
+enum StartupEvent {
+#define mozilla_StartupTimeline_Event(ev, z) ev,
+#include "StartupTimeline.h"
+#undef mozilla_StartupTimeline_Event
+ MAX_STARTUP_EVENT_ID
+};
+
+using namespace mozilla;
+
+void JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Throw\n");
+ jclass cls = jenv->FindClass(classname);
+ if (cls == nullptr) {
+ __android_log_print(
+ ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Couldn't find exception class (or exception pending) %s\n", classname);
+ exit(FAILURE);
+ }
+ int rc = jenv->ThrowNew(cls, msg);
+ if (rc < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Error throwing exception %s\n", msg);
+ exit(FAILURE);
+ }
+ jenv->DeleteLocalRef(cls);
+}
+
+namespace {
+JavaVM* sJavaVM;
+}
+
+void abortThroughJava(const char* msg) {
+ struct sigaction sigact = {};
+ if (__wrap_sigaction(SIGSEGV, nullptr, &sigact)) {
+ return; // sigaction call failed.
+ }
+
+ Dl_info info = {};
+ if ((sigact.sa_flags & SA_SIGINFO) &&
+ __wrap_dladdr(reinterpret_cast<void*>(sigact.sa_sigaction), &info) &&
+ info.dli_fname && strstr(info.dli_fname, "libxul.so")) {
+ return; // Existing signal handler is in libxul (i.e. we have crash
+ // reporter).
+ }
+
+ JNIEnv* env = nullptr;
+ if (!sJavaVM ||
+ sJavaVM->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ return;
+ }
+
+ if (!env || env->PushLocalFrame(2) != JNI_OK) {
+ return;
+ }
+
+ jclass loader = env->FindClass("org/mozilla/gecko/mozglue/GeckoLoader");
+ if (!loader) {
+ return;
+ }
+
+ jmethodID method =
+ env->GetStaticMethodID(loader, "abort", "(Ljava/lang/String;)V");
+ jstring str = env->NewStringUTF(msg);
+
+ if (method && str) {
+ env->CallStaticVoidMethod(loader, method, str);
+ }
+
+ env->PopLocalFrame(nullptr);
+}
+
+Bootstrap::UniquePtr gBootstrap;
+#ifndef MOZ_FOLD_LIBS
+static void* sqlite_handle = nullptr;
+static void* nspr_handle = nullptr;
+static void* plc_handle = nullptr;
+#else
+# define sqlite_handle nss_handle
+# define nspr_handle nss_handle
+# define plc_handle nss_handle
+#endif
+static void* nss_handle = nullptr;
+
+static UniquePtr<char[]> getUnpackedLibraryName(const char* libraryName) {
+ static const char* libdir = getenv("MOZ_ANDROID_LIBDIR");
+
+ size_t len = strlen(libdir) + 1 /* path separator */ + strlen(libraryName) +
+ 1; /* null terminator */
+ auto file = MakeUnique<char[]>(len);
+ snprintf(file.get(), len, "%s/%s", libdir, libraryName);
+ return file;
+}
+
+static void* dlopenLibrary(const char* libraryName) {
+ return __wrap_dlopen(getUnpackedLibraryName(libraryName).get(),
+ RTLD_GLOBAL | RTLD_LAZY);
+}
+
+static void EnsureBaseProfilerInitialized() {
+ // There is no single entry-point into C++ code on Android.
+ // Instead, GeckoThread and GeckoLibLoader call various functions to load
+ // libraries one-by-one.
+ // We want to capture all that library loading in the profiler, so we need to
+ // kick off the base profiler at the beginning of whichever function is called
+ // first.
+ // We currently assume that all these functions are called on the same thread.
+ static bool sInitialized = false;
+ if (sInitialized) {
+ return;
+ }
+
+#ifdef MOZ_GECKO_PROFILER
+ // The stack depth we observe here will be determined by the stack of
+ // whichever caller enters this code first. In practice this means that we may
+ // miss some root-most frames, which hopefully shouldn't ruin profiling.
+ int stackBase = 5;
+ mozilla::baseprofiler::profiler_init(&stackBase);
+#endif
+ sInitialized = true;
+}
+
+static mozglueresult loadGeckoLibs() {
+ TimeStamp t0 = TimeStamp::Now();
+ struct rusage usage1_thread, usage1;
+ getrusage(RUSAGE_THREAD, &usage1_thread);
+ getrusage(RUSAGE_SELF, &usage1);
+
+ static const char* libxul = getenv("MOZ_ANDROID_LIBDIR_OVERRIDE");
+ if (libxul) {
+ gBootstrap = GetBootstrap(libxul, LibLoadingStrategy::ReadAhead);
+ } else {
+ gBootstrap = GetBootstrap(getUnpackedLibraryName("libxul.so").get(),
+ LibLoadingStrategy::ReadAhead);
+ }
+ if (!gBootstrap) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Couldn't get a handle to libxul!");
+ return FAILURE;
+ }
+
+ TimeStamp t1 = TimeStamp::Now();
+ struct rusage usage2_thread, usage2;
+ getrusage(RUSAGE_THREAD, &usage2_thread);
+ getrusage(RUSAGE_SELF, &usage2);
+
+#define RUSAGE_TIMEDIFF(u1, u2, field) \
+ ((u2.ru_##field.tv_sec - u1.ru_##field.tv_sec) * 1000 + \
+ (u2.ru_##field.tv_usec - u1.ru_##field.tv_usec) / 1000)
+
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Loaded libs in %fms total, %ldms(%ldms) user, "
+ "%ldms(%ldms) system, %ld(%ld) faults",
+ (t1 - t0).ToMilliseconds(),
+ RUSAGE_TIMEDIFF(usage1_thread, usage2_thread, utime),
+ RUSAGE_TIMEDIFF(usage1, usage2, utime),
+ RUSAGE_TIMEDIFF(usage1_thread, usage2_thread, stime),
+ RUSAGE_TIMEDIFF(usage1, usage2, stime),
+ usage2_thread.ru_majflt - usage1_thread.ru_majflt,
+ usage2.ru_majflt - usage1.ru_majflt);
+
+ gBootstrap->XRE_StartupTimelineRecord(LINKER_INITIALIZED, t0);
+ gBootstrap->XRE_StartupTimelineRecord(LIBRARIES_LOADED, t1);
+ return SUCCESS;
+}
+
+static mozglueresult loadNSSLibs();
+
+static mozglueresult loadSQLiteLibs() {
+ if (sqlite_handle) return SUCCESS;
+
+#ifdef MOZ_FOLD_LIBS
+ if (loadNSSLibs() != SUCCESS) return FAILURE;
+#else
+
+ sqlite_handle = dlopenLibrary("libmozsqlite3.so");
+ if (!sqlite_handle) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Couldn't get a handle to libmozsqlite3!");
+ return FAILURE;
+ }
+#endif
+
+ return SUCCESS;
+}
+
+static mozglueresult loadNSSLibs() {
+ if (nss_handle && nspr_handle && plc_handle) return SUCCESS;
+
+ nss_handle = dlopenLibrary("libnss3.so");
+
+#ifndef MOZ_FOLD_LIBS
+ nspr_handle = dlopenLibrary("libnspr4.so");
+
+ plc_handle = dlopenLibrary("libplc4.so");
+#endif
+
+ if (!nss_handle) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Couldn't get a handle to libnss3!");
+ return FAILURE;
+ }
+
+#ifndef MOZ_FOLD_LIBS
+ if (!nspr_handle) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Couldn't get a handle to libnspr4!");
+ return FAILURE;
+ }
+
+ if (!plc_handle) {
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad",
+ "Couldn't get a handle to libplc4!");
+ return FAILURE;
+ }
+#endif
+
+ return SUCCESS;
+}
+
+extern "C" APKOPEN_EXPORT void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(
+ JNIEnv* jenv, jclass jGeckoAppShellClass) {
+ EnsureBaseProfilerInitialized();
+
+ jenv->GetJavaVM(&sJavaVM);
+
+ int res = loadGeckoLibs();
+ if (res != SUCCESS) {
+ JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries");
+ }
+}
+
+extern "C" APKOPEN_EXPORT void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(
+ JNIEnv* jenv, jclass jGeckoAppShellClass) {
+ EnsureBaseProfilerInitialized();
+
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite start\n");
+ mozglueresult rv = loadSQLiteLibs();
+ if (rv != SUCCESS) {
+ JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries");
+ }
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n");
+}
+
+extern "C" APKOPEN_EXPORT void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(
+ JNIEnv* jenv, jclass jGeckoAppShellClass) {
+ EnsureBaseProfilerInitialized();
+
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss start\n");
+ mozglueresult rv = loadNSSLibs();
+ if (rv != SUCCESS) {
+ JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries");
+ }
+ __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n");
+}
+
+static char** CreateArgvFromObjectArray(JNIEnv* jenv, jobjectArray jargs,
+ int* length) {
+ size_t stringCount = jenv->GetArrayLength(jargs);
+
+ if (length) {
+ *length = stringCount;
+ }
+
+ if (!stringCount) {
+ return nullptr;
+ }
+
+ char** argv = new char*[stringCount + 1];
+
+ argv[stringCount] = nullptr;
+
+ for (size_t ix = 0; ix < stringCount; ix++) {
+ jstring string = (jstring)(jenv->GetObjectArrayElement(jargs, ix));
+ const char* rawString = jenv->GetStringUTFChars(string, nullptr);
+ const int strLength = jenv->GetStringUTFLength(string);
+ argv[ix] = strndup(rawString, strLength);
+ jenv->ReleaseStringUTFChars(string, rawString);
+ jenv->DeleteLocalRef(string);
+ }
+
+ return argv;
+}
+
+static void FreeArgv(char** argv, int argc) {
+ for (int ix = 0; ix < argc; ix++) {
+ // String was allocated with strndup, so need to use free to deallocate.
+ free(argv[ix]);
+ }
+ delete[](argv);
+}
+
+extern "C" APKOPEN_EXPORT void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv* jenv, jclass jc,
+ jobjectArray jargs,
+ int prefsFd, int prefMapFd,
+ int ipcFd, int crashFd,
+ int crashAnnotationFd) {
+ EnsureBaseProfilerInitialized();
+
+ int argc = 0;
+ char** argv = CreateArgvFromObjectArray(jenv, jargs, &argc);
+
+ if (ipcFd < 0) {
+ if (gBootstrap == nullptr) {
+ FreeArgv(argv, argc);
+ return;
+ }
+
+#ifdef MOZ_LINKER
+ ElfLoader::Singleton.ExpectShutdown(false);
+#endif
+ gBootstrap->GeckoStart(jenv, argv, argc, sAppData);
+#ifdef MOZ_LINKER
+ ElfLoader::Singleton.ExpectShutdown(true);
+#endif
+ } else {
+ gBootstrap->XRE_SetAndroidChildFds(
+ jenv, {prefsFd, prefMapFd, ipcFd, crashFd, crashAnnotationFd});
+ gBootstrap->XRE_SetProcessType(argv[argc - 1]);
+
+ XREChildData childData;
+ gBootstrap->XRE_InitChildProcess(argc - 1, argv, &childData);
+ }
+
+#ifdef MOZ_WIDGET_ANDROID
+# ifdef MOZ_PROFILE_GENERATE
+ gBootstrap->XRE_WriteLLVMProfData();
+# endif
+#endif
+ gBootstrap.reset();
+ FreeArgv(argv, argc);
+}
+
+extern "C" APKOPEN_EXPORT mozglueresult ChildProcessInit(int argc,
+ char* argv[]) {
+ EnsureBaseProfilerInitialized();
+
+ if (loadNSSLibs() != SUCCESS) {
+ return FAILURE;
+ }
+ if (loadSQLiteLibs() != SUCCESS) {
+ return FAILURE;
+ }
+ if (loadGeckoLibs() != SUCCESS) {
+ return FAILURE;
+ }
+
+ gBootstrap->XRE_SetProcessType(argv[--argc]);
+
+ XREChildData childData;
+ return NS_FAILED(gBootstrap->XRE_InitChildProcess(argc, argv, &childData));
+}
+
+extern "C" APKOPEN_EXPORT jboolean MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_neonCompatible(JNIEnv* jenv,
+ jclass jc) {
+#ifdef __ARM_EABI__
+ return mozilla::supports_neon();
+#else
+ return true;
+#endif // __ARM_EABI__
+}
+
+// Does current process name end with ':media'?
+static bool IsMediaProcess() {
+ pid_t pid = getpid();
+ char str[256];
+ SprintfLiteral(str, "/proc/%d/cmdline", pid);
+ FILE* f = fopen(str, "r");
+ if (f) {
+ fgets(str, sizeof(str), f);
+ fclose(f);
+ const size_t strLen = strlen(str);
+ const char suffix[] = ":media";
+ const size_t suffixLen = sizeof(suffix) - 1;
+ if (strLen >= suffixLen &&
+ !strncmp(str + strLen - suffixLen, suffix, suffixLen)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifndef SYS_rt_tgsigqueueinfo
+# define SYS_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
+#endif
+/* Copy of http://androidxref.com/7.1.1_r6/xref/bionic/linker/debugger.cpp#262,
+ * with debuggerd related code stripped.
+ *
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+static void CatchFatalSignals(int num, siginfo_t* info, void* context) {
+ // It's possible somebody cleared the SA_SIGINFO flag, which would mean
+ // our "info" arg holds an undefined value.
+ struct sigaction action = {};
+ if ((sigaction(num, nullptr, &action) < 0) ||
+ !(action.sa_flags & SA_SIGINFO)) {
+ info = nullptr;
+ }
+
+ // We need to return from the signal handler so that debuggerd can dump the
+ // thread that crashed, but returning here does not guarantee that the signal
+ // will be thrown again, even for SIGSEGV and friends, since the signal could
+ // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
+ // preserve the SA_SIGINFO contents.
+ signal(num, SIG_DFL);
+
+ struct siginfo si;
+ if (!info) {
+ memset(&si, 0, sizeof(si));
+ si.si_code = SI_USER;
+ si.si_pid = getpid();
+ si.si_uid = getuid();
+ info = &si;
+ } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
+ // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
+ // that contain commit 66dd34a (3.9+). The manpage claims to only allow
+ // negative si_code values that are not SI_TKILL, but 66dd34a changed the
+ // check to allow all si_code values in calls coming from inside the house.
+ }
+
+ int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), num, info);
+ if (rc != 0) {
+ __android_log_print(ANDROID_LOG_FATAL, "mozglue",
+ "failed to resend signal during crash: %s",
+ strerror(errno));
+ _exit(0);
+ }
+}
+
+extern "C" APKOPEN_EXPORT void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_suppressCrashDialog(JNIEnv* jenv,
+ jclass jc) {
+ MOZ_RELEASE_ASSERT(IsMediaProcess(),
+ "Suppress crash dialog only for media process");
+ // Restoring to SIG_DFL will crash on x86/Android M devices (see bug 1374556)
+ // so copy Android code
+ // (http://androidxref.com/7.1.1_r6/xref/bionic/linker/debugger.cpp#302). See
+ // comments above CatchFatalSignals() for copyright notice.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = &CatchFatalSignals;
+ action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+ // Use the alternate signal stack if available so we can catch stack
+ // overflows.
+ action.sa_flags |= SA_ONSTACK;
+
+ sigaction(SIGABRT, &action, nullptr);
+ sigaction(SIGBUS, &action, nullptr);
+ sigaction(SIGFPE, &action, nullptr);
+ sigaction(SIGILL, &action, nullptr);
+ sigaction(SIGSEGV, &action, nullptr);
+#if defined(SIGSTKFLT)
+ sigaction(SIGSTKFLT, &action, nullptr);
+#endif
+ sigaction(SIGTRAP, &action, nullptr);
+}
diff --git a/mozglue/android/APKOpen.h b/mozglue/android/APKOpen.h
new file mode 100644
index 0000000000..f3666bf028
--- /dev/null
+++ b/mozglue/android/APKOpen.h
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef APKOpen_h
+#define APKOpen_h
+
+#include <jni.h>
+
+#ifndef APKOPEN_EXPORT
+# define APKOPEN_EXPORT __attribute__((visibility("default")))
+#endif
+
+APKOPEN_EXPORT void abortThroughJava(const char* msg);
+
+static const int SUCCESS = 0;
+static const int FAILURE = 1;
+void JNI_Throw(JNIEnv* jenv, const char* classname, const char* msg);
+
+// Bug 1207642 - Work around Dalvik bug by realigning stack on JNI entry
+#ifndef MOZ_JNICALL
+# ifdef __i386__
+# define MOZ_JNICALL JNICALL __attribute__((force_align_arg_pointer))
+# else
+# define MOZ_JNICALL JNICALL
+# endif
+#endif
+
+#endif /* APKOpen_h */
diff --git a/mozglue/android/Ashmem.cpp b/mozglue/android/Ashmem.cpp
new file mode 100644
index 0000000000..9c93fe2b10
--- /dev/null
+++ b/mozglue/android/Ashmem.cpp
@@ -0,0 +1,73 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <cstring>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <linux/ashmem.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "Ashmem.h"
+
+namespace mozilla {
+namespace android {
+
+static void* libhandle() {
+ static void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
+ return handle;
+}
+
+int ashmem_create(const char* name, size_t size) {
+ static auto fCreate =
+ (int (*)(const char*, size_t))dlsym(libhandle(), "ASharedMemory_create");
+
+ if (fCreate) {
+ return fCreate(name, size);
+ }
+
+ int fd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600);
+ if (fd < 0) {
+ return fd;
+ }
+
+ if (name) {
+ char str[ASHMEM_NAME_LEN];
+ strlcpy(str, name, sizeof(str));
+ ioctl(fd, ASHMEM_SET_NAME, str);
+ }
+
+ if (ioctl(fd, ASHMEM_SET_SIZE, size) != 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+size_t ashmem_getSize(int fd) {
+ static auto fGetSize =
+ (size_t(*)(int))dlsym(libhandle(), "ASharedMemory_getSize");
+ if (fGetSize) {
+ return fGetSize(fd);
+ }
+
+ return (size_t)ioctl(fd, ASHMEM_GET_SIZE, nullptr);
+}
+
+int ashmem_setProt(int fd, int prot) {
+ static auto fSetProt =
+ (int (*)(int, int))dlsym(libhandle(), "ASharedMemory_setProt");
+ if (fSetProt) {
+ return fSetProt(fd, prot);
+ }
+
+ return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
+}
+
+} // namespace android
+} // namespace mozilla
diff --git a/mozglue/android/Ashmem.h b/mozglue/android/Ashmem.h
new file mode 100644
index 0000000000..9779f71ba0
--- /dev/null
+++ b/mozglue/android/Ashmem.h
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef Ashmem_h__
+#define Ashmem_h__
+
+#include <linux/ashmem.h>
+
+namespace mozilla {
+namespace android {
+
+// Wrappers for the ASharedMemory function in the NDK
+// https://developer.android.com/ndk/reference/group/memory
+MFBT_API int ashmem_create(const char* name, size_t size);
+MFBT_API size_t ashmem_getSize(int fd);
+MFBT_API int ashmem_setProt(int fd, int prot);
+
+} // namespace android
+} // namespace mozilla
+
+#endif // Ashmem_h__
diff --git a/mozglue/android/NativeCrypto.cpp b/mozglue/android/NativeCrypto.cpp
new file mode 100644
index 0000000000..f24f6eb55c
--- /dev/null
+++ b/mozglue/android/NativeCrypto.cpp
@@ -0,0 +1,140 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "NativeCrypto.h"
+#include "APKOpen.h"
+
+#include <jni.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "mozilla/SHA1.h"
+#include "pbkdf2_sha256.h"
+
+/**
+ * Helper function to invoke native PBKDF2 function with JNI
+ * arguments.
+ */
+extern "C" JNIEXPORT jbyteArray MOZ_JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_pbkdf2SHA256(
+ JNIEnv* env, jclass jc, jbyteArray jpassword, jbyteArray jsalt, jint c,
+ jint dkLen) {
+ if (dkLen < 0) {
+ env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
+ "dkLen should not be less than 0");
+ return nullptr;
+ }
+
+ jbyte* password = env->GetByteArrayElements(jpassword, nullptr);
+ size_t passwordLen = env->GetArrayLength(jpassword);
+
+ jbyte* salt = env->GetByteArrayElements(jsalt, nullptr);
+ size_t saltLen = env->GetArrayLength(jsalt);
+
+ uint8_t hashResult[dkLen];
+ PBKDF2_SHA256((uint8_t*)password, passwordLen, (uint8_t*)salt, saltLen,
+ (uint64_t)c, hashResult, (size_t)dkLen);
+
+ env->ReleaseByteArrayElements(jpassword, password, JNI_ABORT);
+ env->ReleaseByteArrayElements(jsalt, salt, JNI_ABORT);
+
+ jbyteArray out = env->NewByteArray(dkLen);
+ if (out == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(out, 0, dkLen, (jbyte*)hashResult);
+
+ return out;
+}
+
+using namespace mozilla;
+
+/**
+ * Helper function to invoke native SHA-1 function with JNI arguments.
+ */
+extern "C" JNIEXPORT jbyteArray MOZ_JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha1(
+ JNIEnv* env, jclass jc, jbyteArray jstr) {
+ jbyte* str = env->GetByteArrayElements(jstr, nullptr);
+ size_t strLen = env->GetArrayLength(jstr);
+
+ SHA1Sum sha1;
+ SHA1Sum::Hash hashResult;
+ sha1.update((void*)str, (uint32_t)strLen);
+ sha1.finish(hashResult);
+
+ env->ReleaseByteArrayElements(jstr, str, JNI_ABORT);
+
+ jbyteArray out = env->NewByteArray(SHA1Sum::kHashSize);
+ if (out == nullptr) {
+ return nullptr;
+ }
+ env->SetByteArrayRegion(out, 0, SHA1Sum::kHashSize, (jbyte*)hashResult);
+
+ return out;
+}
+
+/**
+ * Helper function to invoke native SHA-256 init with JNI arguments.
+ */
+extern "C" JNIEXPORT jbyteArray MOZ_JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256init(
+ JNIEnv* env, jclass jc) {
+ jbyteArray out = env->NewByteArray(sizeof(SHA256_CTX));
+ if (nullptr == out) {
+ return nullptr;
+ }
+
+ SHA256_CTX* shaContext = (SHA256_CTX*)env->GetByteArrayElements(out, nullptr);
+ SHA256_Init(shaContext);
+
+ env->ReleaseByteArrayElements(out, (jbyte*)shaContext, 0);
+
+ return out;
+}
+
+/**
+ * Helper function to invoke native SHA-256 update with JNI arguments.
+ */
+extern "C" JNIEXPORT void MOZ_JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256update(
+ JNIEnv* env, jclass jc, jbyteArray jctx, jbyteArray jstr, jint len) {
+ jbyte* str = env->GetByteArrayElements(jstr, nullptr);
+
+ SHA256_CTX* shaContext =
+ (SHA256_CTX*)env->GetByteArrayElements(jctx, nullptr);
+
+ SHA256_Update(shaContext, (void*)str, (size_t)len);
+
+ env->ReleaseByteArrayElements(jstr, str, JNI_ABORT);
+ env->ReleaseByteArrayElements(jctx, (jbyte*)shaContext, 0);
+
+ return;
+}
+
+/**
+ * Helper function to invoke native SHA-256 finalize with JNI arguments.
+ */
+extern "C" JNIEXPORT jbyteArray MOZ_JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256finalize(
+ JNIEnv* env, jclass jc, jbyteArray jctx) {
+ SHA256_CTX* shaContext =
+ (SHA256_CTX*)env->GetByteArrayElements(jctx, nullptr);
+
+ unsigned char* digest = new unsigned char[32];
+ SHA256_Final(digest, shaContext);
+
+ env->ReleaseByteArrayElements(jctx, (jbyte*)shaContext, JNI_ABORT);
+
+ jbyteArray out = env->NewByteArray(32);
+ if (nullptr != out) {
+ env->SetByteArrayRegion(out, 0, 32, (jbyte*)digest);
+ }
+
+ delete[] digest;
+
+ return out;
+}
diff --git a/mozglue/android/NativeCrypto.h b/mozglue/android/NativeCrypto.h
new file mode 100644
index 0000000000..e06145ef6b
--- /dev/null
+++ b/mozglue/android/NativeCrypto.h
@@ -0,0 +1,58 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_mozilla_gecko_background_nativecode_NativeCrypto */
+
+#ifndef _Included_org_mozilla_gecko_background_nativecode_NativeCrypto
+# define _Included_org_mozilla_gecko_background_nativecode_NativeCrypto
+# ifdef __cplusplus
+extern "C" {
+# endif
+/*
+ * Class: org_mozilla_gecko_background_nativecode_NativeCrypto
+ * Method: pbkdf2SHA256
+ * Signature: ([B[BII)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_pbkdf2SHA256(
+ JNIEnv*, jclass, jbyteArray, jbyteArray, jint, jint);
+
+/*
+ * Class: org_mozilla_gecko_background_nativecode_NativeCrypto
+ * Method: sha1
+ * Signature: ([B)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha1(JNIEnv*, jclass,
+ jbyteArray);
+
+/*
+ * Class: org_mozilla_gecko_background_nativecode_NativeCrypto
+ * Method: sha256init
+ * Signature: ()[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256init(JNIEnv*,
+ jclass);
+
+/*
+ * Class: org_mozilla_gecko_background_nativecode_NativeCrypto
+ * Method: sha256update
+ * Signature: ([B[B)V
+ */
+JNIEXPORT void JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256update(
+ JNIEnv*, jclass, jbyteArray, jbyteArray, jint);
+
+/*
+ * Class: org_mozilla_gecko_background_nativecode_NativeCrypto
+ * Method: sha256finalize
+ * Signature: ([B)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_org_mozilla_gecko_background_nativecode_NativeCrypto_sha256finalize(
+ JNIEnv*, jclass, jbyteArray);
+
+# ifdef __cplusplus
+}
+# endif
+#endif
diff --git a/mozglue/android/SharedMemNatives.cpp b/mozglue/android/SharedMemNatives.cpp
new file mode 100644
index 0000000000..f38a2274b3
--- /dev/null
+++ b/mozglue/android/SharedMemNatives.cpp
@@ -0,0 +1,80 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <errno.h>
+#include <jni.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include "mozilla/Sprintf.h"
+
+extern "C" {
+
+JNIEXPORT
+void JNICALL
+Java_org_mozilla_gecko_media_SampleBuffer_nativeReadFromDirectBuffer(
+ JNIEnv* jenv, jclass, jobject src, jlong dest, jint offset, jint size) {
+ uint8_t* from = static_cast<uint8_t*>(jenv->GetDirectBufferAddress(src));
+ if (from == nullptr) {
+ jenv->ThrowNew(jenv->FindClass("java/lang/NullPointerException"),
+ "Null direct buffer");
+ return;
+ }
+
+ void* to = reinterpret_cast<void*>(dest);
+ if (to == nullptr) {
+ jenv->ThrowNew(jenv->FindClass("java/lang/NullPointerException"),
+ "Null shared memory buffer");
+ return;
+ }
+
+ memcpy(to, from + offset, size);
+}
+
+JNIEXPORT
+void JNICALL
+Java_org_mozilla_gecko_media_SampleBuffer_nativeWriteToDirectBuffer(
+ JNIEnv* jenv, jclass, jlong src, jobject dest, jint offset, jint size) {
+ uint8_t* from = reinterpret_cast<uint8_t*>(src);
+ if (from == nullptr) {
+ jenv->ThrowNew(jenv->FindClass("java/lang/NullPointerException"),
+ "Null shared memory buffer");
+ return;
+ }
+
+ void* to = jenv->GetDirectBufferAddress(dest);
+ if (to == nullptr) {
+ jenv->ThrowNew(jenv->FindClass("java/lang/NullPointerException"),
+ "Null direct buffer");
+ return;
+ }
+
+ memcpy(to, from + offset, size);
+}
+
+JNIEXPORT
+jlong JNICALL Java_org_mozilla_gecko_mozglue_SharedMemory_map(JNIEnv* env,
+ jobject jobj,
+ jint fd,
+ jint length) {
+ void* address = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (address == MAP_FAILED) {
+ char msg[128];
+ SprintfLiteral(msg, "mmap failed. errno=%d", errno);
+ env->ThrowNew(env->FindClass("java/lang/NullPointerException"), msg);
+ return 0;
+ }
+ return jlong(address);
+}
+
+JNIEXPORT
+void JNICALL Java_org_mozilla_gecko_mozglue_SharedMemory_unmap(JNIEnv* env,
+ jobject jobj,
+ jlong address,
+ jint size) {
+ munmap((void*)address, (size_t)size);
+}
+}
diff --git a/mozglue/android/moz.build b/mozglue/android/moz.build
new file mode 100644
index 0000000000..5d72c135c0
--- /dev/null
+++ b/mozglue/android/moz.build
@@ -0,0 +1,71 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS += [
+ "APKOpen.h",
+]
+
+EXPORTS.mozilla += ["Ashmem.h"]
+
+SOURCES += [
+ "APKOpen.cpp",
+ "Ashmem.cpp",
+ "NativeCrypto.cpp",
+ "nsGeckoUtils.cpp",
+ "pbkdf2_sha256.c",
+ "SharedMemNatives.cpp",
+]
+
+if CONFIG["MOZ_CRASHREPORTER"]:
+ USE_LIBS += [
+ "minidump-analyzer",
+ ]
+
+ LOCAL_INCLUDES += [
+ "/toolkit/crashreporter/minidump-analyzer",
+ ]
+
+FINAL_LIBRARY = "mozglue"
+
+for var in ("ANDROID_PACKAGE_NAME", "ANDROID_CPU_ARCH"):
+ DEFINES[var] = '"%s"' % CONFIG[var]
+
+if CONFIG["MOZ_FOLD_LIBS"]:
+ DEFINES["MOZ_FOLD_LIBS"] = True
+
+LOCAL_INCLUDES += [
+ "!/build",
+ "../linker",
+ "/ipc/chromium/src",
+ "/nsprpub/lib/ds",
+ "/nsprpub/lib/libc/include",
+ "/nsprpub/pr/include",
+ "/security/nss/lib/base",
+ "/security/nss/lib/certdb",
+ "/security/nss/lib/cryptohi",
+ "/security/nss/lib/dev",
+ "/security/nss/lib/freebl",
+ "/security/nss/lib/nss",
+ "/security/nss/lib/pk11wrap",
+ "/security/nss/lib/pkcs7",
+ "/security/nss/lib/pki",
+ "/security/nss/lib/smime",
+ "/security/nss/lib/softoken",
+ "/security/nss/lib/ssl",
+ "/security/nss/lib/util",
+ "/third_party/sqlite3/src",
+ "/toolkit/components/startup",
+ "/xpcom/build",
+]
+
+if CONFIG["CC_TYPE"] in ("clang", "gcc"):
+ CXXFLAGS += ["-Wno-error=shadow"]
+
+DEFINES["XPCOM_GLUE"] = True
+
+USE_LIBS += [
+ "xpcomglue",
+]
diff --git a/mozglue/android/nsGeckoUtils.cpp b/mozglue/android/nsGeckoUtils.cpp
new file mode 100644
index 0000000000..d6fbf5c0d7
--- /dev/null
+++ b/mozglue/android/nsGeckoUtils.cpp
@@ -0,0 +1,152 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <jni.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include "APKOpen.h"
+#include "Zip.h"
+#include "mozilla/RefPtr.h"
+
+#ifdef MOZ_CRASHREPORTER
+# include "minidump-analyzer.h"
+#endif
+
+extern "C" __attribute__((visibility("default"))) void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_putenv(JNIEnv* jenv, jclass,
+ jstring map) {
+ const char* str;
+ // XXX: java doesn't give us true UTF8, we should figure out something
+ // better to do here
+ str = jenv->GetStringUTFChars(map, nullptr);
+ if (str == nullptr) return;
+ putenv(strdup(str));
+ jenv->ReleaseStringUTFChars(map, str);
+}
+
+extern "C" APKOPEN_EXPORT jboolean MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_GeckoLoader_verifyCRCs(JNIEnv* jenv, jclass,
+ jstring jApkName) {
+ const char* str;
+ // XXX: java doesn't give us true UTF8, we should figure out something
+ // better to do here
+ str = jenv->GetStringUTFChars(jApkName, nullptr);
+ if (str == nullptr) {
+ return false;
+ }
+
+ RefPtr<Zip> zip = Zip::Create(str);
+ const bool valid = zip->VerifyCRCs();
+ jenv->ReleaseStringUTFChars(jApkName, str);
+ return jboolean(valid);
+}
+
+extern "C" __attribute__((visibility("default"))) jobject MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeAllocateDirectBuffer(
+ JNIEnv* jenv, jclass, jlong size) {
+ jobject buffer = nullptr;
+ void* mem = malloc(size);
+ if (mem) {
+ buffer = jenv->NewDirectByteBuffer(mem, size);
+ if (!buffer) free(mem);
+ }
+ return buffer;
+}
+
+extern "C" __attribute__((visibility("default"))) void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_DirectBufferAllocator_nativeFreeDirectBuffer(
+ JNIEnv* jenv, jclass, jobject buf) {
+ free(jenv->GetDirectBufferAddress(buf));
+}
+
+extern "C" __attribute__((visibility("default"))) jlong MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_NativeZip_getZip(JNIEnv* jenv, jclass,
+ jstring path) {
+ const char* str;
+ str = jenv->GetStringUTFChars(path, nullptr);
+ if (!str || !*str) {
+ if (str) jenv->ReleaseStringUTFChars(path, str);
+ JNI_Throw(jenv, "java/lang/IllegalArgumentException", "Invalid path");
+ return 0;
+ }
+ RefPtr<Zip> zip = ZipCollection::GetZip(str);
+ jenv->ReleaseStringUTFChars(path, str);
+ if (!zip) {
+ JNI_Throw(jenv, "java/lang/IllegalArgumentException",
+ "Invalid path or invalid zip");
+ return 0;
+ }
+ return reinterpret_cast<jlong>(zip.forget().take());
+}
+
+extern "C" __attribute__((visibility("default"))) jlong MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_NativeZip_getZipFromByteBuffer(JNIEnv* jenv,
+ jclass,
+ jobject buffer) {
+ void* buf = jenv->GetDirectBufferAddress(buffer);
+ size_t size = jenv->GetDirectBufferCapacity(buffer);
+ RefPtr<Zip> zip = Zip::Create(buf, size);
+ if (!zip) {
+ JNI_Throw(jenv, "java/lang/IllegalArgumentException", "Invalid zip");
+ return 0;
+ }
+ return reinterpret_cast<jlong>(zip.forget().take());
+}
+
+extern "C" __attribute__((visibility("default"))) void MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_NativeZip__1release(JNIEnv* jenv, jclass,
+ jlong obj) {
+ Zip* zip = (Zip*)obj;
+ zip->Release();
+}
+
+extern "C" __attribute__((visibility("default"))) jobject MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_NativeZip__1getInputStream(JNIEnv* jenv,
+ jobject jzip,
+ jlong obj,
+ jstring path) {
+ Zip* zip = (Zip*)obj;
+ const char* str;
+ str = jenv->GetStringUTFChars(path, nullptr);
+
+ Zip::Stream stream;
+ bool res = zip->GetStream(str, &stream);
+ jenv->ReleaseStringUTFChars(path, str);
+ if (!res) {
+ return nullptr;
+ }
+ jobject buf = jenv->NewDirectByteBuffer(const_cast<void*>(stream.GetBuffer()),
+ stream.GetSize());
+ if (!buf) {
+ JNI_Throw(jenv, "java/lang/RuntimeException",
+ "Failed to create ByteBuffer");
+ return nullptr;
+ }
+ jclass nativeZip = jenv->GetObjectClass(jzip);
+ jmethodID method =
+ jenv->GetMethodID(nativeZip, "createInputStream",
+ "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;");
+ // Since this function is only expected to be called from Java, it is safe
+ // to skip exception checking for the method call below, as long as no
+ // other Native -> Java call doesn't happen before returning to Java.
+ return jenv->CallObjectMethod(jzip, method, buf, (jint)stream.GetType());
+}
+
+#ifdef MOZ_CRASHREPORTER
+
+extern "C" __attribute__((visibility("default"))) jboolean MOZ_JNICALL
+Java_org_mozilla_gecko_mozglue_MinidumpAnalyzer_GenerateStacks(
+ JNIEnv* jenv, jclass, jstring minidumpPath, jboolean fullStacks) {
+ const char* str;
+ str = jenv->GetStringUTFChars(minidumpPath, nullptr);
+
+ bool res = CrashReporter::GenerateStacks(str, fullStacks);
+
+ jenv->ReleaseStringUTFChars(minidumpPath, str);
+ return res;
+}
+
+#endif // MOZ_CRASHREPORTER
diff --git a/mozglue/android/pbkdf2_sha256.c b/mozglue/android/pbkdf2_sha256.c
new file mode 100644
index 0000000000..119d245476
--- /dev/null
+++ b/mozglue/android/pbkdf2_sha256.c
@@ -0,0 +1,389 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include <sys/endian.h>
+
+#include "pbkdf2_sha256.h"
+
+static inline uint32_t be32dec(const void* pp) {
+ const uint8_t* p = (uint8_t const*)pp;
+
+ return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
+ ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
+}
+
+static inline void be32enc(void* pp, uint32_t x) {
+ uint8_t* p = (uint8_t*)pp;
+
+ p[3] = x & 0xff;
+ p[2] = (x >> 8) & 0xff;
+ p[1] = (x >> 16) & 0xff;
+ p[0] = (x >> 24) & 0xff;
+}
+
+/*
+ * Encode a length len/4 vector of (uint32_t) into a length len vector of
+ * (unsigned char) in big-endian form. Assumes len is a multiple of 4.
+ */
+static void be32enc_vect(unsigned char* dst, const uint32_t* src, size_t len) {
+ size_t i;
+
+ for (i = 0; i < len / 4; i++) be32enc(dst + i * 4, src[i]);
+}
+
+/*
+ * Decode a big-endian length len vector of (unsigned char) into a length
+ * len/4 vector of (uint32_t). Assumes len is a multiple of 4.
+ */
+static void be32dec_vect(uint32_t* dst, const unsigned char* src, size_t len) {
+ size_t i;
+
+ for (i = 0; i < len / 4; i++) dst[i] = be32dec(src + i * 4);
+}
+
+/* Elementary functions used by SHA256 */
+#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
+#define Maj(x, y, z) ((x & (y | z)) | (y & z))
+#define SHR(x, n) (x >> n)
+#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
+#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
+#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
+
+/* SHA256 round function */
+#define RND(a, b, c, d, e, f, g, h, k) \
+ t0 = h + S1(e) + Ch(e, f, g) + k; \
+ t1 = S0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+/* Adjusted round function for rotating state */
+#define RNDr(S, W, i, k) \
+ RND(S[(64 - i) % 8], S[(65 - i) % 8], S[(66 - i) % 8], S[(67 - i) % 8], \
+ S[(68 - i) % 8], S[(69 - i) % 8], S[(70 - i) % 8], S[(71 - i) % 8], \
+ W[i] + k)
+
+/*
+ * SHA256 block compression function. The 256-bit state is transformed via
+ * the 512-bit input block to produce a new state.
+ */
+static void SHA256_Transform(uint32_t* state, const unsigned char block[64]) {
+ uint32_t W[64];
+ uint32_t S[8];
+ uint32_t t0, t1;
+ int i;
+
+ /* 1. Prepare message schedule W. */
+ be32dec_vect(W, block, 64);
+ for (i = 16; i < 64; i++)
+ W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
+
+ /* 2. Initialize working variables. */
+ memcpy(S, state, 32);
+
+ /* 3. Mix. */
+ RNDr(S, W, 0, 0x428a2f98);
+ RNDr(S, W, 1, 0x71374491);
+ RNDr(S, W, 2, 0xb5c0fbcf);
+ RNDr(S, W, 3, 0xe9b5dba5);
+ RNDr(S, W, 4, 0x3956c25b);
+ RNDr(S, W, 5, 0x59f111f1);
+ RNDr(S, W, 6, 0x923f82a4);
+ RNDr(S, W, 7, 0xab1c5ed5);
+ RNDr(S, W, 8, 0xd807aa98);
+ RNDr(S, W, 9, 0x12835b01);
+ RNDr(S, W, 10, 0x243185be);
+ RNDr(S, W, 11, 0x550c7dc3);
+ RNDr(S, W, 12, 0x72be5d74);
+ RNDr(S, W, 13, 0x80deb1fe);
+ RNDr(S, W, 14, 0x9bdc06a7);
+ RNDr(S, W, 15, 0xc19bf174);
+ RNDr(S, W, 16, 0xe49b69c1);
+ RNDr(S, W, 17, 0xefbe4786);
+ RNDr(S, W, 18, 0x0fc19dc6);
+ RNDr(S, W, 19, 0x240ca1cc);
+ RNDr(S, W, 20, 0x2de92c6f);
+ RNDr(S, W, 21, 0x4a7484aa);
+ RNDr(S, W, 22, 0x5cb0a9dc);
+ RNDr(S, W, 23, 0x76f988da);
+ RNDr(S, W, 24, 0x983e5152);
+ RNDr(S, W, 25, 0xa831c66d);
+ RNDr(S, W, 26, 0xb00327c8);
+ RNDr(S, W, 27, 0xbf597fc7);
+ RNDr(S, W, 28, 0xc6e00bf3);
+ RNDr(S, W, 29, 0xd5a79147);
+ RNDr(S, W, 30, 0x06ca6351);
+ RNDr(S, W, 31, 0x14292967);
+ RNDr(S, W, 32, 0x27b70a85);
+ RNDr(S, W, 33, 0x2e1b2138);
+ RNDr(S, W, 34, 0x4d2c6dfc);
+ RNDr(S, W, 35, 0x53380d13);
+ RNDr(S, W, 36, 0x650a7354);
+ RNDr(S, W, 37, 0x766a0abb);
+ RNDr(S, W, 38, 0x81c2c92e);
+ RNDr(S, W, 39, 0x92722c85);
+ RNDr(S, W, 40, 0xa2bfe8a1);
+ RNDr(S, W, 41, 0xa81a664b);
+ RNDr(S, W, 42, 0xc24b8b70);
+ RNDr(S, W, 43, 0xc76c51a3);
+ RNDr(S, W, 44, 0xd192e819);
+ RNDr(S, W, 45, 0xd6990624);
+ RNDr(S, W, 46, 0xf40e3585);
+ RNDr(S, W, 47, 0x106aa070);
+ RNDr(S, W, 48, 0x19a4c116);
+ RNDr(S, W, 49, 0x1e376c08);
+ RNDr(S, W, 50, 0x2748774c);
+ RNDr(S, W, 51, 0x34b0bcb5);
+ RNDr(S, W, 52, 0x391c0cb3);
+ RNDr(S, W, 53, 0x4ed8aa4a);
+ RNDr(S, W, 54, 0x5b9cca4f);
+ RNDr(S, W, 55, 0x682e6ff3);
+ RNDr(S, W, 56, 0x748f82ee);
+ RNDr(S, W, 57, 0x78a5636f);
+ RNDr(S, W, 58, 0x84c87814);
+ RNDr(S, W, 59, 0x8cc70208);
+ RNDr(S, W, 60, 0x90befffa);
+ RNDr(S, W, 61, 0xa4506ceb);
+ RNDr(S, W, 62, 0xbef9a3f7);
+ RNDr(S, W, 63, 0xc67178f2);
+
+ /* 4. Mix local working variables into global state. */
+ for (i = 0; i < 8; i++) state[i] += S[i];
+
+ /* Clean the stack. */
+ memset(W, 0, 256);
+ memset(S, 0, 32);
+ t0 = t1 = 0;
+}
+
+static unsigned char PAD[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+/* Add padding and terminating bit-count. */
+static void SHA256_Pad(SHA256_CTX* ctx) {
+ unsigned char len[8];
+ uint32_t r, plen;
+
+ /*
+ * Convert length to a vector of bytes -- we do this now rather
+ * than later because the length will change after we pad.
+ */
+ be32enc_vect(len, ctx->count, 8);
+
+ /* Add 1--64 bytes so that the resulting length is 56 mod 64. */
+ r = (ctx->count[1] >> 3) & 0x3f;
+ plen = (r < 56) ? (56 - r) : (120 - r);
+ SHA256_Update(ctx, PAD, (size_t)plen);
+
+ /* Add the terminating bit-count. */
+ SHA256_Update(ctx, len, 8);
+}
+
+/* SHA-256 initialization. Begins a SHA-256 operation. */
+void SHA256_Init(SHA256_CTX* ctx) {
+ /* Zero bits processed so far. */
+ ctx->count[0] = ctx->count[1] = 0;
+
+ /* Magic initialization constants. */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+}
+
+/* Add bytes into the hash. */
+void SHA256_Update(SHA256_CTX* ctx, const void* in, size_t len) {
+ uint32_t bitlen[2];
+ uint32_t r;
+ const unsigned char* src = in;
+
+ /* Number of bytes left in the buffer from previous updates. */
+ r = (ctx->count[1] >> 3) & 0x3f;
+
+ /* Convert the length into a number of bits. */
+ bitlen[1] = ((uint32_t)len) << 3;
+ bitlen[0] = (uint32_t)(len >> 29);
+
+ /* Update number of bits. */
+ if ((ctx->count[1] += bitlen[1]) < bitlen[1]) ctx->count[0]++;
+ ctx->count[0] += bitlen[0];
+
+ /* Handle the case where we don't need to perform any transforms. */
+ if (len < 64 - r) {
+ memcpy(&ctx->buf[r], src, len);
+ return;
+ }
+
+ /* Finish the current block. */
+ memcpy(&ctx->buf[r], src, 64 - r);
+ SHA256_Transform(ctx->state, ctx->buf);
+ src += 64 - r;
+ len -= 64 - r;
+
+ /* Perform complete blocks. */
+ while (len >= 64) {
+ SHA256_Transform(ctx->state, src);
+ src += 64;
+ len -= 64;
+ }
+
+ /* Copy left over data into buffer. */
+ memcpy(ctx->buf, src, len);
+}
+
+/*
+ * SHA-256 finalization. Pads the input data, exports the hash value,
+ * and clears the context state.
+ */
+void SHA256_Final(unsigned char digest[32], SHA256_CTX* ctx) {
+ /* Add padding. */
+ SHA256_Pad(ctx);
+
+ /* Write the hash. */
+ be32enc_vect(digest, ctx->state, 32);
+
+ /* Clear the context state. */
+ memset((void*)ctx, 0, sizeof(*ctx));
+}
+
+/* Initialize an HMAC-SHA256 operation with the given key. */
+void HMAC_SHA256_Init(HMAC_SHA256_CTX* ctx, const void* _K, size_t Klen) {
+ unsigned char pad[64];
+ unsigned char khash[32];
+ const unsigned char* K = _K;
+ size_t i;
+
+ /* If Klen > 64, the key is really SHA256(K). */
+ if (Klen > 64) {
+ SHA256_Init(&ctx->ictx);
+ SHA256_Update(&ctx->ictx, K, Klen);
+ SHA256_Final(khash, &ctx->ictx);
+ K = khash;
+ Klen = 32;
+ }
+
+ /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
+ SHA256_Init(&ctx->ictx);
+ memset(pad, 0x36, 64);
+ for (i = 0; i < Klen; i++) pad[i] ^= K[i];
+ SHA256_Update(&ctx->ictx, pad, 64);
+
+ /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
+ SHA256_Init(&ctx->octx);
+ memset(pad, 0x5c, 64);
+ for (i = 0; i < Klen; i++) pad[i] ^= K[i];
+ SHA256_Update(&ctx->octx, pad, 64);
+
+ /* Clean the stack. */
+ memset(khash, 0, 32);
+}
+
+/* Add bytes to the HMAC-SHA256 operation. */
+void HMAC_SHA256_Update(HMAC_SHA256_CTX* ctx, const void* in, size_t len) {
+ /* Feed data to the inner SHA256 operation. */
+ SHA256_Update(&ctx->ictx, in, len);
+}
+
+/* Finish an HMAC-SHA256 operation. */
+void HMAC_SHA256_Final(unsigned char digest[32], HMAC_SHA256_CTX* ctx) {
+ unsigned char ihash[32];
+
+ /* Finish the inner SHA256 operation. */
+ SHA256_Final(ihash, &ctx->ictx);
+
+ /* Feed the inner hash to the outer SHA256 operation. */
+ SHA256_Update(&ctx->octx, ihash, 32);
+
+ /* Finish the outer SHA256 operation. */
+ SHA256_Final(digest, &ctx->octx);
+
+ /* Clean the stack. */
+ memset(ihash, 0, 32);
+}
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void PBKDF2_SHA256(const uint8_t* passwd, size_t passwdlen, const uint8_t* salt,
+ size_t saltlen, uint64_t c, uint8_t* buf, size_t dkLen) {
+ HMAC_SHA256_CTX PShctx, hctx;
+ size_t i;
+ uint8_t ivec[4];
+ uint8_t U[32];
+ uint8_t T[32];
+ uint64_t j;
+ int k;
+ size_t clen;
+
+ /* Compute HMAC state after processing P and S. */
+ HMAC_SHA256_Init(&PShctx, passwd, passwdlen);
+ HMAC_SHA256_Update(&PShctx, salt, saltlen);
+
+ /* Iterate through the blocks. */
+ for (i = 0; i * 32 < dkLen; i++) {
+ /* Generate INT(i + 1). */
+ be32enc(ivec, (uint32_t)(i + 1));
+
+ /* Compute U_1 = PRF(P, S || INT(i)). */
+ memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
+ HMAC_SHA256_Update(&hctx, ivec, 4);
+ HMAC_SHA256_Final(U, &hctx);
+
+ /* T_i = U_1 ... */
+ memcpy(T, U, 32);
+
+ for (j = 2; j <= c; j++) {
+ /* Compute U_j. */
+ HMAC_SHA256_Init(&hctx, passwd, passwdlen);
+ HMAC_SHA256_Update(&hctx, U, 32);
+ HMAC_SHA256_Final(U, &hctx);
+
+ /* ... xor U_j ... */
+ for (k = 0; k < 32; k++) T[k] ^= U[k];
+ }
+
+ /* Copy as many bytes as necessary into buf. */
+ clen = dkLen - i * 32;
+ if (clen > 32) clen = 32;
+ memcpy(&buf[i * 32], T, clen);
+ }
+
+ /* Clean PShctx, since we never called _Final on it. */
+ memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX));
+}
diff --git a/mozglue/android/pbkdf2_sha256.h b/mozglue/android/pbkdf2_sha256.h
new file mode 100644
index 0000000000..80223ffcd5
--- /dev/null
+++ b/mozglue/android/pbkdf2_sha256.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright 2005,2007,2009 Colin Percival
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libmd/sha256.h,v 1.2 2006/01/17 15:35:56 phk Exp $
+ */
+
+#ifndef _SHA256_H_
+#define _SHA256_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+typedef struct SHA256Context {
+ uint32_t state[8];
+ uint32_t count[2];
+ unsigned char buf[64];
+} SHA256_CTX;
+
+typedef struct HMAC_SHA256Context {
+ SHA256_CTX ictx;
+ SHA256_CTX octx;
+} HMAC_SHA256_CTX;
+
+void SHA256_Init(SHA256_CTX*);
+void SHA256_Update(SHA256_CTX*, const void*, size_t);
+void SHA256_Final(unsigned char[32], SHA256_CTX*);
+void HMAC_SHA256_Init(HMAC_SHA256_CTX*, const void*, size_t);
+void HMAC_SHA256_Update(HMAC_SHA256_CTX*, const void*, size_t);
+void HMAC_SHA256_Final(unsigned char[32], HMAC_SHA256_CTX*);
+
+/**
+ * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
+ * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
+ * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
+ */
+void PBKDF2_SHA256(const uint8_t*, size_t, const uint8_t*, size_t, uint64_t,
+ uint8_t*, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_SHA256_H_ */