mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 08:18:41 +09:00
Issue #1053 - Remove android support from mozglue
Yes, I checked for unsaved files this time...
This commit is contained in:
parent
bb8b180863
commit
a890ecd06f
26 changed files with 19 additions and 2748 deletions
|
|
@ -1,465 +0,0 @@
|
|||
/* 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/resource.h>
|
||||
#include <sys/prctl.h>
|
||||
#include "sqlite3.h"
|
||||
#include "SQLiteBridge.h"
|
||||
#include "NSSBridge.h"
|
||||
#include "ElfLoader.h"
|
||||
#include "application.ini.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
|
||||
|
||||
extern "C" {
|
||||
/*
|
||||
* To work around http://code.google.com/p/android/issues/detail?id=23203
|
||||
* we don't link with the crt objects. In some configurations, this means
|
||||
* a lack of the __dso_handle symbol because it is defined there, and
|
||||
* depending on the android platform and ndk versions used, it may or may
|
||||
* not be defined in libc.so. In the latter case, we fail to link. Defining
|
||||
* it here as weak makes us provide the symbol when it's not provided by
|
||||
* the crt objects, making the change transparent for future NDKs that
|
||||
* would fix the original problem. On older NDKs, it is not a problem
|
||||
* either because the way __dso_handle was used was already broken (and
|
||||
* the custom linker works around it).
|
||||
*/
|
||||
NS_EXPORT __attribute__((weak)) void *__dso_handle;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
static const int MAX_MAPPING_INFO = 32;
|
||||
static mapping_info lib_mapping[MAX_MAPPING_INFO];
|
||||
|
||||
NS_EXPORT const struct mapping_info *
|
||||
getLibraryMapping()
|
||||
{
|
||||
return lib_mapping;
|
||||
}
|
||||
|
||||
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;
|
||||
pthread_t sJavaUiThread;
|
||||
}
|
||||
|
||||
void
|
||||
abortThroughJava(const char* msg)
|
||||
{
|
||||
struct sigaction sigact = {};
|
||||
if (SEGVHandler::__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);
|
||||
}
|
||||
|
||||
NS_EXPORT pthread_t
|
||||
getJavaUiThread()
|
||||
{
|
||||
return sJavaUiThread;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_GeckoThread_registerUiThread(JNIEnv*, jclass)
|
||||
{
|
||||
sJavaUiThread = pthread_self();
|
||||
}
|
||||
|
||||
static void * xul_handle = nullptr;
|
||||
#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;
|
||||
|
||||
template <typename T> inline void
|
||||
xul_dlsym(const char *symbolName, T *value)
|
||||
{
|
||||
*value = (T) (uintptr_t) __wrap_dlsym(xul_handle, symbolName);
|
||||
}
|
||||
|
||||
static int mapping_count = 0;
|
||||
|
||||
extern "C" void
|
||||
report_mapping(char *name, void *base, uint32_t len, uint32_t offset)
|
||||
{
|
||||
if (mapping_count >= MAX_MAPPING_INFO)
|
||||
return;
|
||||
|
||||
struct mapping_info *info = &lib_mapping[mapping_count++];
|
||||
info->name = strdup(name);
|
||||
info->base = (uintptr_t)base;
|
||||
info->len = len;
|
||||
info->offset = offset;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
delete_mapping(const char *name)
|
||||
{
|
||||
for (int pos = 0; pos < mapping_count; ++pos) {
|
||||
struct mapping_info *info = &lib_mapping[pos];
|
||||
if (!strcmp(info->name, name)) {
|
||||
struct mapping_info *last = &lib_mapping[mapping_count - 1];
|
||||
free(info->name);
|
||||
*info = *last;
|
||||
--mapping_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void*
|
||||
dlopenAPKLibrary(const char* apkName, const char* libraryName)
|
||||
{
|
||||
#define APK_ASSETS_PATH "!/assets/" ANDROID_CPU_ARCH "/"
|
||||
size_t filenameLength = strlen(apkName) +
|
||||
sizeof(APK_ASSETS_PATH) + // includes \0 terminator
|
||||
strlen(libraryName);
|
||||
auto file = MakeUnique<char[]>(filenameLength);
|
||||
snprintf(file.get(), filenameLength, "%s" APK_ASSETS_PATH "%s",
|
||||
apkName, libraryName);
|
||||
return __wrap_dlopen(file.get(), RTLD_GLOBAL | RTLD_LAZY);
|
||||
#undef APK_ASSETS_PATH
|
||||
}
|
||||
static mozglueresult
|
||||
loadGeckoLibs(const char *apkName)
|
||||
{
|
||||
TimeStamp t0 = TimeStamp::Now();
|
||||
struct rusage usage1_thread, usage1;
|
||||
getrusage(RUSAGE_THREAD, &usage1_thread);
|
||||
getrusage(RUSAGE_SELF, &usage1);
|
||||
|
||||
xul_handle = dlopenAPKLibrary(apkName, "libxul.so");
|
||||
if (!xul_handle) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libxul!");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
void (*XRE_StartupTimelineRecord)(int, TimeStamp);
|
||||
xul_dlsym("XRE_StartupTimelineRecord", &XRE_StartupTimelineRecord);
|
||||
|
||||
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);
|
||||
|
||||
XRE_StartupTimelineRecord(LINKER_INITIALIZED, t0);
|
||||
XRE_StartupTimelineRecord(LIBRARIES_LOADED, t1);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static mozglueresult loadNSSLibs(const char *apkName);
|
||||
|
||||
static mozglueresult
|
||||
loadSQLiteLibs(const char *apkName)
|
||||
{
|
||||
if (sqlite_handle)
|
||||
return SUCCESS;
|
||||
|
||||
#ifdef MOZ_FOLD_LIBS
|
||||
if (loadNSSLibs(apkName) != SUCCESS)
|
||||
return FAILURE;
|
||||
#else
|
||||
|
||||
sqlite_handle = dlopenAPKLibrary(apkName, "libmozsqlite3.so");
|
||||
if (!sqlite_handle) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libmozsqlite3!");
|
||||
return FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
setup_sqlite_functions(sqlite_handle);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static mozglueresult
|
||||
loadNSSLibs(const char *apkName)
|
||||
{
|
||||
if (nss_handle && nspr_handle && plc_handle)
|
||||
return SUCCESS;
|
||||
|
||||
nss_handle = dlopenAPKLibrary(apkName, "libnss3.so");
|
||||
|
||||
#ifndef MOZ_FOLD_LIBS
|
||||
nspr_handle = dlopenAPKLibrary(apkName, "libnspr4.so");
|
||||
|
||||
plc_handle = dlopenAPKLibrary(apkName, "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 setup_nss_functions(nss_handle, nspr_handle, plc_handle);
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_mozglue_GeckoLoader_extractGeckoLibsNative(
|
||||
JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
|
||||
{
|
||||
MOZ_ALWAYS_TRUE(!jenv->GetJavaVM(&sJavaVM));
|
||||
|
||||
const char* apkName = jenv->GetStringUTFChars(jApkName, nullptr);
|
||||
if (apkName == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract and cache native lib to allow for efficient startup from cache.
|
||||
void* handle = dlopenAPKLibrary(apkName, "libxul.so");
|
||||
if (handle) {
|
||||
__android_log_print(ANDROID_LOG_INFO, "GeckoLibLoad",
|
||||
"Extracted and cached libxul.so.");
|
||||
// We have extracted and cached the lib, we can close it now.
|
||||
__wrap_dlclose(handle);
|
||||
} else {
|
||||
JNI_Throw(jenv, "java/lang/Exception", "Error extracting gecko libraries");
|
||||
}
|
||||
|
||||
jenv->ReleaseStringUTFChars(jApkName, apkName);
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
|
||||
{
|
||||
jenv->GetJavaVM(&sJavaVM);
|
||||
|
||||
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;
|
||||
|
||||
int res = loadGeckoLibs(str);
|
||||
if (res != SUCCESS) {
|
||||
JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries");
|
||||
}
|
||||
jenv->ReleaseStringUTFChars(jApkName, str);
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, 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;
|
||||
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite start\n");
|
||||
mozglueresult rv = loadSQLiteLibs(str);
|
||||
if (rv != SUCCESS) {
|
||||
JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries");
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n");
|
||||
jenv->ReleaseStringUTFChars(jApkName, str);
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, 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;
|
||||
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss start\n");
|
||||
mozglueresult rv = loadNSSLibs(str);
|
||||
if (rv != SUCCESS) {
|
||||
JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries");
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n");
|
||||
jenv->ReleaseStringUTFChars(jApkName, str);
|
||||
}
|
||||
|
||||
typedef void (*GeckoStart_t)(JNIEnv*, char*, const nsXREAppData*);
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs)
|
||||
{
|
||||
GeckoStart_t GeckoStart;
|
||||
xul_dlsym("GeckoStart", &GeckoStart);
|
||||
if (GeckoStart == nullptr)
|
||||
return;
|
||||
// XXX: java doesn't give us true UTF8, we should figure out something
|
||||
// better to do here
|
||||
int len = jenv->GetStringUTFLength(jargs);
|
||||
// GeckoStart needs to write in the args buffer, so we need a copy.
|
||||
char *args = (char *) malloc(len + 1);
|
||||
jenv->GetStringUTFRegion(jargs, 0, len, args);
|
||||
args[len] = '\0';
|
||||
ElfLoader::Singleton.ExpectShutdown(false);
|
||||
GeckoStart(jenv, args, &sAppData);
|
||||
ElfLoader::Singleton.ExpectShutdown(true);
|
||||
free(args);
|
||||
}
|
||||
|
||||
typedef int GeckoProcessType;
|
||||
|
||||
extern "C" NS_EXPORT mozglueresult
|
||||
ChildProcessInit(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < (argc - 1); i++) {
|
||||
if (strcmp(argv[i], "-greomni"))
|
||||
continue;
|
||||
|
||||
i = i + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (loadNSSLibs(argv[i]) != SUCCESS) {
|
||||
return FAILURE;
|
||||
}
|
||||
if (loadSQLiteLibs(argv[i]) != SUCCESS) {
|
||||
return FAILURE;
|
||||
}
|
||||
if (loadGeckoLibs(argv[i]) != SUCCESS) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
void (*fXRE_SetProcessType)(char*);
|
||||
xul_dlsym("XRE_SetProcessType", &fXRE_SetProcessType);
|
||||
|
||||
mozglueresult (*fXRE_InitChildProcess)(int, char**, void*);
|
||||
xul_dlsym("XRE_InitChildProcess", &fXRE_InitChildProcess);
|
||||
|
||||
fXRE_SetProcessType(argv[--argc]);
|
||||
|
||||
XREChildData childData;
|
||||
return fXRE_InitChildProcess(argc, argv, &childData);
|
||||
}
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/* 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>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifndef NS_EXPORT
|
||||
#define NS_EXPORT __attribute__ ((visibility("default")))
|
||||
#endif
|
||||
|
||||
struct mapping_info {
|
||||
char * name;
|
||||
uintptr_t base;
|
||||
size_t len;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
NS_EXPORT const struct mapping_info * getLibraryMapping();
|
||||
NS_EXPORT void abortThroughJava(const char* msg);
|
||||
NS_EXPORT pthread_t getJavaUiThread();
|
||||
|
||||
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 */
|
||||
|
|
@ -1,285 +0,0 @@
|
|||
/* 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 <stdlib.h>
|
||||
#include "dlfcn.h"
|
||||
#include "NSSBridge.h"
|
||||
#include "APKOpen.h"
|
||||
#ifdef ANDROID
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#include "ElfLoader.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
|
||||
#else
|
||||
#define LOG(x...)
|
||||
#endif
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
#define NSS_WRAPPER_INT(name) name ## _t f_ ## name;
|
||||
NSS_WRAPPER_INT(NSS_Initialize)
|
||||
NSS_WRAPPER_INT(NSS_Shutdown)
|
||||
NSS_WRAPPER_INT(SECITEM_ZfreeItem)
|
||||
NSS_WRAPPER_INT(PK11SDR_Encrypt)
|
||||
NSS_WRAPPER_INT(PK11SDR_Decrypt)
|
||||
NSS_WRAPPER_INT(PK11_GetInternalKeySlot)
|
||||
NSS_WRAPPER_INT(PK11_NeedUserInit)
|
||||
NSS_WRAPPER_INT(PK11_InitPin)
|
||||
NSS_WRAPPER_INT(PR_ErrorToString)
|
||||
NSS_WRAPPER_INT(PR_GetError)
|
||||
NSS_WRAPPER_INT(PR_Free)
|
||||
NSS_WRAPPER_INT(PL_Base64Encode)
|
||||
NSS_WRAPPER_INT(PL_Base64Decode)
|
||||
NSS_WRAPPER_INT(PL_strfree)
|
||||
|
||||
SECStatus doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool doEncrypt);
|
||||
SECStatus encode(const uint8_t* data, uint32_t srclen, char** result);
|
||||
SECStatus decode(const char* data, uint8_t** result, uint32_t* length);
|
||||
|
||||
int
|
||||
setup_nss_functions(void *nss_handle,
|
||||
void *nspr_handle,
|
||||
void *plc_handle)
|
||||
{
|
||||
if (nss_handle == nullptr || nspr_handle == nullptr || plc_handle == nullptr) {
|
||||
LOG("Missing handle\n");
|
||||
return FAILURE;
|
||||
}
|
||||
#define GETFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(nss_handle, #name); \
|
||||
if (!f_ ##name) { __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); return FAILURE; }
|
||||
GETFUNC(NSS_Initialize);
|
||||
GETFUNC(NSS_Shutdown);
|
||||
GETFUNC(PK11SDR_Encrypt);
|
||||
GETFUNC(PK11SDR_Decrypt);
|
||||
GETFUNC(PK11_GetInternalKeySlot);
|
||||
GETFUNC(PK11_NeedUserInit);
|
||||
GETFUNC(PK11_InitPin);
|
||||
GETFUNC(SECITEM_ZfreeItem);
|
||||
#undef GETFUNC
|
||||
#define NSPRFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(nspr_handle, #name); \
|
||||
if (!f_ ##name) { __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); return FAILURE; }
|
||||
NSPRFUNC(PR_ErrorToString);
|
||||
NSPRFUNC(PR_GetError);
|
||||
NSPRFUNC(PR_Free);
|
||||
#undef NSPRFUNC
|
||||
#define PLCFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(plc_handle, #name); \
|
||||
if (!f_ ##name) { __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "missing %s", #name); return FAILURE; }
|
||||
PLCFUNC(PL_Base64Encode);
|
||||
PLCFUNC(PL_Base64Decode);
|
||||
PLCFUNC(PL_strfree);
|
||||
#undef PLCFUNC
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/* Throws the current NSS error. */
|
||||
static void
|
||||
throwError(JNIEnv* jenv, const char * funcString) {
|
||||
char *msg;
|
||||
|
||||
PRErrorCode perr = f_PR_GetError();
|
||||
char * errString = f_PR_ErrorToString(perr, 0);
|
||||
asprintf(&msg, "%s returned error %d: %s\n", funcString, perr, errString);
|
||||
LOG("Throwing error: %s\n", msg);
|
||||
|
||||
JNI_Throw(jenv, "java/lang/Exception", msg);
|
||||
free(msg);
|
||||
LOG("Error thrown\n");
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jstring MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_NSSBridge_nativeEncrypt(JNIEnv* jenv, jclass,
|
||||
jstring jPath,
|
||||
jstring jValue)
|
||||
{
|
||||
jstring ret = jenv->NewStringUTF("");
|
||||
|
||||
const char* path;
|
||||
path = jenv->GetStringUTFChars(jPath, nullptr);
|
||||
|
||||
const char* value;
|
||||
value = jenv->GetStringUTFChars(jValue, nullptr);
|
||||
|
||||
char* result;
|
||||
SECStatus rv = doCrypto(jenv, path, value, &result, true);
|
||||
if (rv == SECSuccess) {
|
||||
ret = jenv->NewStringUTF(result);
|
||||
free(result);
|
||||
}
|
||||
|
||||
jenv->ReleaseStringUTFChars(jValue, value);
|
||||
jenv->ReleaseStringUTFChars(jPath, path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jstring MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_NSSBridge_nativeDecrypt(JNIEnv* jenv, jclass,
|
||||
jstring jPath,
|
||||
jstring jValue)
|
||||
{
|
||||
jstring ret = jenv->NewStringUTF("");
|
||||
|
||||
const char* path;
|
||||
path = jenv->GetStringUTFChars(jPath, nullptr);
|
||||
|
||||
const char* value;
|
||||
value = jenv->GetStringUTFChars(jValue, nullptr);
|
||||
|
||||
char* result;
|
||||
SECStatus rv = doCrypto(jenv, path, value, &result, false);
|
||||
if (rv == SECSuccess) {
|
||||
ret = jenv->NewStringUTF(result);
|
||||
free(result);
|
||||
}
|
||||
|
||||
jenv->ReleaseStringUTFChars(jValue, value);
|
||||
jenv->ReleaseStringUTFChars(jPath, path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Encrypts or decrypts a string. result should be freed with free() when done */
|
||||
SECStatus
|
||||
doCrypto(JNIEnv* jenv, const char *path, const char *value, char** result, bool encrypt)
|
||||
{
|
||||
SECStatus rv;
|
||||
PK11SlotInfo *slot;
|
||||
if (!initialized) {
|
||||
LOG("Initialize crypto in %s\n", path);
|
||||
rv = f_NSS_Initialize(path, "", "", "secmod.db", NSS_INIT_NOROOTINIT);
|
||||
if (rv != SECSuccess) {
|
||||
throwError(jenv, "NSS_Initialize");
|
||||
return rv;
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
slot = f_PK11_GetInternalKeySlot();
|
||||
if (!slot) {
|
||||
throwError(jenv, "PK11_GetInternalKeySlot");
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (f_PK11_NeedUserInit(slot)) {
|
||||
LOG("Initializing key3.db with default blank password.\n");
|
||||
rv = f_PK11_InitPin(slot, nullptr, nullptr);
|
||||
if (rv != SECSuccess) {
|
||||
throwError(jenv, "PK11_InitPin");
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
SECItem request;
|
||||
SECItem reply;
|
||||
|
||||
reply.data = 0;
|
||||
reply.len = 0;
|
||||
|
||||
if (encrypt) {
|
||||
// This can print sensitive data. Uncomment if you need it.
|
||||
// LOG("Encrypting: %s\n", value);
|
||||
request.data = (unsigned char*)value;
|
||||
request.len = strlen(value);
|
||||
|
||||
SECItem keyid;
|
||||
keyid.data = 0;
|
||||
keyid.len = 0;
|
||||
rv = f_PK11SDR_Encrypt(&keyid, &request, &reply, nullptr);
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
rv = encode(reply.data, reply.len, result);
|
||||
if (rv == SECSuccess) {
|
||||
LOG("Encrypted: %s\n", *result);
|
||||
} else {
|
||||
throwError(jenv, "encode");
|
||||
}
|
||||
} else {
|
||||
throwError(jenv, "PK11SDR_Encrypt");
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG("Decoding: %s\n", value);
|
||||
rv = decode(value, &request.data, &request.len);
|
||||
if (rv != SECSuccess) {
|
||||
throwError(jenv, "decode");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = f_PK11SDR_Decrypt(&request, &reply, nullptr);
|
||||
|
||||
if (rv == SECSuccess) {
|
||||
*result = static_cast<char*>(malloc(reply.len + 1));
|
||||
strncpy(*result, reinterpret_cast<char*>(reply.data), reply.len);
|
||||
(*result)[reply.len] = '\0';
|
||||
|
||||
// This can print sensitive data. Uncomment if you need it.
|
||||
// LOG("Decoded %i letters: %s\n", reply.len, *result);
|
||||
} else {
|
||||
throwError(jenv, "PK11SDR_Decrypt");
|
||||
}
|
||||
free(request.data);
|
||||
}
|
||||
|
||||
f_SECITEM_ZfreeItem(&reply, false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Base64 encodes the data passed in. The caller must deallocate _retval using free();
|
||||
*/
|
||||
SECStatus
|
||||
encode(const uint8_t* data, uint32_t srclen, char** result)
|
||||
{
|
||||
if (srclen > (PR_UINT32_MAX / 4) * 3) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
const uint32_t dstlen = ((srclen + 2) / 3) * 4;
|
||||
char* const buffer = static_cast<char*>(malloc(dstlen + 1));
|
||||
|
||||
if (!buffer || !f_PL_Base64Encode(reinterpret_cast<const char*>(data), srclen, buffer)) {
|
||||
free(buffer);
|
||||
*result = nullptr;
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
buffer[dstlen] = '\0';
|
||||
*result = buffer;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* Base64 decodes the data passed in. The caller must deallocate result using free();
|
||||
*/
|
||||
SECStatus
|
||||
decode(const char* data, uint8_t** result, uint32_t* length)
|
||||
{
|
||||
uint32_t srclen = strlen(data);
|
||||
while (srclen && data[srclen - 1] == '=') {
|
||||
srclen--;
|
||||
}
|
||||
|
||||
// Avoid overflow when calculating result length.
|
||||
const uint32_t dstlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
|
||||
// At most 2 extra bytes due to padding in input.
|
||||
uint8_t* const buffer = static_cast<uint8_t*>(malloc(dstlen + 2));
|
||||
|
||||
if (!buffer || !f_PL_Base64Decode(data, srclen, reinterpret_cast<char*>(buffer))) {
|
||||
free(buffer);
|
||||
*result = nullptr;
|
||||
*length = 0;
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
buffer[dstlen] = '\0';
|
||||
*result = buffer;
|
||||
*length = dstlen;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/* 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 NSSBridge_h
|
||||
#define NSSBridge_h
|
||||
|
||||
#include "nss.h"
|
||||
#include "pk11func.h"
|
||||
#include "pk11sdr.h"
|
||||
#include "seccomon.h"
|
||||
#include "secitem.h"
|
||||
#include "secmodt.h"
|
||||
|
||||
#include "prerror.h"
|
||||
#include "plstr.h"
|
||||
#include "prmem.h"
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
int setup_nss_functions(void *nss_handle, void *nssutil_handle, void *plc_handle);
|
||||
|
||||
#define NSS_WRAPPER(name, return_type, args...) \
|
||||
typedef return_type (*name ## _t)(args); \
|
||||
extern name ## _t f_ ## name;
|
||||
|
||||
NSS_WRAPPER(NSS_Initialize, SECStatus, const char*, const char*, const char*, const char*, uint32_t)
|
||||
NSS_WRAPPER(NSS_Shutdown, void, void)
|
||||
NSS_WRAPPER(PK11SDR_Encrypt, SECStatus, SECItem *, SECItem *, SECItem *, void *)
|
||||
NSS_WRAPPER(PK11SDR_Decrypt, SECStatus, SECItem *, SECItem *, void *)
|
||||
NSS_WRAPPER(SECITEM_ZfreeItem, void, SECItem*, PRBool)
|
||||
NSS_WRAPPER(PR_ErrorToString, char *, PRErrorCode, PRLanguageCode)
|
||||
NSS_WRAPPER(PR_GetError, PRErrorCode, void)
|
||||
NSS_WRAPPER(PR_Free, PRErrorCode, char *)
|
||||
NSS_WRAPPER(PL_Base64Encode, char*, const char*, uint32_t, char*)
|
||||
NSS_WRAPPER(PL_Base64Decode, char*, const char*, uint32_t, char*)
|
||||
NSS_WRAPPER(PL_strfree, void, char*)
|
||||
NSS_WRAPPER(PK11_GetInternalKeySlot, PK11SlotInfo *, void)
|
||||
NSS_WRAPPER(PK11_NeedUserInit, PRBool, PK11SlotInfo *)
|
||||
NSS_WRAPPER(PK11_InitPin, SECStatus, PK11SlotInfo*, const char*, const char*)
|
||||
|
||||
#endif /* NSS_h */
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
/* 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;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/* 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
|
||||
|
|
@ -1,413 +0,0 @@
|
|||
/* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include "dlfcn.h"
|
||||
#include "APKOpen.h"
|
||||
#include "ElfLoader.h"
|
||||
#include "SQLiteBridge.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
|
||||
#else
|
||||
#define LOG(x...)
|
||||
#endif
|
||||
|
||||
#define SQLITE_WRAPPER_INT(name) name ## _t f_ ## name;
|
||||
|
||||
SQLITE_WRAPPER_INT(sqlite3_open)
|
||||
SQLITE_WRAPPER_INT(sqlite3_errmsg)
|
||||
SQLITE_WRAPPER_INT(sqlite3_prepare_v2)
|
||||
SQLITE_WRAPPER_INT(sqlite3_bind_parameter_count)
|
||||
SQLITE_WRAPPER_INT(sqlite3_bind_null)
|
||||
SQLITE_WRAPPER_INT(sqlite3_bind_text)
|
||||
SQLITE_WRAPPER_INT(sqlite3_step)
|
||||
SQLITE_WRAPPER_INT(sqlite3_column_count)
|
||||
SQLITE_WRAPPER_INT(sqlite3_finalize)
|
||||
SQLITE_WRAPPER_INT(sqlite3_close)
|
||||
SQLITE_WRAPPER_INT(sqlite3_column_name)
|
||||
SQLITE_WRAPPER_INT(sqlite3_column_type)
|
||||
SQLITE_WRAPPER_INT(sqlite3_column_blob)
|
||||
SQLITE_WRAPPER_INT(sqlite3_column_bytes)
|
||||
SQLITE_WRAPPER_INT(sqlite3_column_text)
|
||||
SQLITE_WRAPPER_INT(sqlite3_changes)
|
||||
SQLITE_WRAPPER_INT(sqlite3_last_insert_rowid)
|
||||
|
||||
void setup_sqlite_functions(void *sqlite_handle)
|
||||
{
|
||||
#define GETFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(sqlite_handle, #name)
|
||||
GETFUNC(sqlite3_open);
|
||||
GETFUNC(sqlite3_errmsg);
|
||||
GETFUNC(sqlite3_prepare_v2);
|
||||
GETFUNC(sqlite3_bind_parameter_count);
|
||||
GETFUNC(sqlite3_bind_null);
|
||||
GETFUNC(sqlite3_bind_text);
|
||||
GETFUNC(sqlite3_step);
|
||||
GETFUNC(sqlite3_column_count);
|
||||
GETFUNC(sqlite3_finalize);
|
||||
GETFUNC(sqlite3_close);
|
||||
GETFUNC(sqlite3_column_name);
|
||||
GETFUNC(sqlite3_column_type);
|
||||
GETFUNC(sqlite3_column_blob);
|
||||
GETFUNC(sqlite3_column_bytes);
|
||||
GETFUNC(sqlite3_column_text);
|
||||
GETFUNC(sqlite3_changes);
|
||||
GETFUNC(sqlite3_last_insert_rowid);
|
||||
#undef GETFUNC
|
||||
}
|
||||
|
||||
static bool initialized = false;
|
||||
static jclass stringClass;
|
||||
static jclass objectClass;
|
||||
static jclass byteBufferClass;
|
||||
static jclass cursorClass;
|
||||
static jmethodID jByteBufferAllocateDirect;
|
||||
static jmethodID jCursorConstructor;
|
||||
static jmethodID jCursorAddRow;
|
||||
|
||||
static jobject sqliteInternalCall(JNIEnv* jenv, sqlite3 *db, jstring jQuery,
|
||||
jobjectArray jParams, jlongArray jQueryRes);
|
||||
|
||||
static void throwSqliteException(JNIEnv* jenv, const char* aFormat, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, aFormat);
|
||||
char* msg = nullptr;
|
||||
vasprintf(&msg, aFormat, ap);
|
||||
LOG("Error in SQLiteBridge: %s\n", msg);
|
||||
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", msg);
|
||||
free(msg);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
JNI_Setup(JNIEnv* jenv)
|
||||
{
|
||||
if (initialized) return;
|
||||
|
||||
jclass lObjectClass = jenv->FindClass("java/lang/Object");
|
||||
jclass lStringClass = jenv->FindClass("java/lang/String");
|
||||
jclass lByteBufferClass = jenv->FindClass("java/nio/ByteBuffer");
|
||||
jclass lCursorClass = jenv->FindClass("org/mozilla/gecko/sqlite/MatrixBlobCursor");
|
||||
|
||||
if (lStringClass == nullptr
|
||||
|| lObjectClass == nullptr
|
||||
|| lByteBufferClass == nullptr
|
||||
|| lCursorClass == nullptr) {
|
||||
throwSqliteException(jenv, "FindClass error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Those are only local references. Make them global so they work
|
||||
// across calls and threads.
|
||||
objectClass = (jclass)jenv->NewGlobalRef(lObjectClass);
|
||||
stringClass = (jclass)jenv->NewGlobalRef(lStringClass);
|
||||
byteBufferClass = (jclass)jenv->NewGlobalRef(lByteBufferClass);
|
||||
cursorClass = (jclass)jenv->NewGlobalRef(lCursorClass);
|
||||
|
||||
if (stringClass == nullptr || objectClass == nullptr
|
||||
|| byteBufferClass == nullptr
|
||||
|| cursorClass == nullptr) {
|
||||
throwSqliteException(jenv, "NewGlobalRef error");
|
||||
return;
|
||||
}
|
||||
|
||||
// public static ByteBuffer allocateDirect(int capacity)
|
||||
jByteBufferAllocateDirect =
|
||||
jenv->GetStaticMethodID(byteBufferClass, "allocateDirect", "(I)Ljava/nio/ByteBuffer;");
|
||||
// new MatrixBlobCursor(String [])
|
||||
jCursorConstructor =
|
||||
jenv->GetMethodID(cursorClass, "<init>", "([Ljava/lang/String;)V");
|
||||
// public void addRow (Object[] columnValues)
|
||||
jCursorAddRow =
|
||||
jenv->GetMethodID(cursorClass, "addRow", "([Ljava/lang/Object;)V");
|
||||
|
||||
if (jByteBufferAllocateDirect == nullptr
|
||||
|| jCursorConstructor == nullptr
|
||||
|| jCursorAddRow == nullptr) {
|
||||
throwSqliteException(jenv, "GetMethodId error");
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jobject MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
|
||||
jstring jDb,
|
||||
jstring jQuery,
|
||||
jobjectArray jParams,
|
||||
jlongArray jQueryRes)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
int rc;
|
||||
jobject jCursor = nullptr;
|
||||
const char* dbPath;
|
||||
sqlite3 *db;
|
||||
|
||||
dbPath = jenv->GetStringUTFChars(jDb, nullptr);
|
||||
rc = f_sqlite3_open(dbPath, &db);
|
||||
jenv->ReleaseStringUTFChars(jDb, dbPath);
|
||||
if (rc != SQLITE_OK) {
|
||||
throwSqliteException(jenv,
|
||||
"Can't open database: %s", f_sqlite3_errmsg(db));
|
||||
f_sqlite3_close(db); // close db even if open failed
|
||||
return nullptr;
|
||||
}
|
||||
jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
|
||||
f_sqlite3_close(db);
|
||||
return jCursor;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jobject MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCallWithDb(JNIEnv* jenv, jclass,
|
||||
jlong jDb,
|
||||
jstring jQuery,
|
||||
jobjectArray jParams,
|
||||
jlongArray jQueryRes)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
jobject jCursor = nullptr;
|
||||
sqlite3 *db = (sqlite3*)jDb;
|
||||
jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
|
||||
return jCursor;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT jlong MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_openDatabase(JNIEnv* jenv, jclass,
|
||||
jstring jDb)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
int rc;
|
||||
const char* dbPath;
|
||||
sqlite3 *db;
|
||||
|
||||
dbPath = jenv->GetStringUTFChars(jDb, nullptr);
|
||||
rc = f_sqlite3_open(dbPath, &db);
|
||||
jenv->ReleaseStringUTFChars(jDb, dbPath);
|
||||
if (rc != SQLITE_OK) {
|
||||
throwSqliteException(jenv,
|
||||
"Can't open database: %s", f_sqlite3_errmsg(db));
|
||||
f_sqlite3_close(db); // close db even if open failed
|
||||
return 0;
|
||||
}
|
||||
return (jlong)db;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT void MOZ_JNICALL
|
||||
Java_org_mozilla_gecko_sqlite_SQLiteBridge_closeDatabase(JNIEnv* jenv, jclass,
|
||||
jlong jDb)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
sqlite3 *db = (sqlite3*)jDb;
|
||||
f_sqlite3_close(db);
|
||||
}
|
||||
|
||||
static jobject
|
||||
sqliteInternalCall(JNIEnv* jenv,
|
||||
sqlite3 *db,
|
||||
jstring jQuery,
|
||||
jobjectArray jParams,
|
||||
jlongArray jQueryRes)
|
||||
{
|
||||
JNI_Setup(jenv);
|
||||
|
||||
jobject jCursor = nullptr;
|
||||
jsize numPars = 0;
|
||||
|
||||
const char *pzTail;
|
||||
sqlite3_stmt *ppStmt;
|
||||
int rc;
|
||||
|
||||
const char* queryStr;
|
||||
queryStr = jenv->GetStringUTFChars(jQuery, nullptr);
|
||||
|
||||
rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail);
|
||||
if (rc != SQLITE_OK || ppStmt == nullptr) {
|
||||
throwSqliteException(jenv,
|
||||
"Can't prepare statement: %s", f_sqlite3_errmsg(db));
|
||||
return nullptr;
|
||||
}
|
||||
jenv->ReleaseStringUTFChars(jQuery, queryStr);
|
||||
|
||||
// Check if number of parameters matches
|
||||
if (jParams != nullptr) {
|
||||
numPars = jenv->GetArrayLength(jParams);
|
||||
}
|
||||
int sqlNumPars;
|
||||
sqlNumPars = f_sqlite3_bind_parameter_count(ppStmt);
|
||||
if (numPars != sqlNumPars) {
|
||||
throwSqliteException(jenv,
|
||||
"Passed parameter count (%d) "
|
||||
"doesn't match SQL parameter count (%d)",
|
||||
numPars, sqlNumPars);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (jParams != nullptr) {
|
||||
// Bind parameters, if any
|
||||
if (numPars > 0) {
|
||||
for (int i = 0; i < numPars; i++) {
|
||||
jobject jObjectParam = jenv->GetObjectArrayElement(jParams, i);
|
||||
// IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf
|
||||
// should be OK.
|
||||
jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass);
|
||||
if (isString != JNI_TRUE) {
|
||||
throwSqliteException(jenv,
|
||||
"Parameter is not of String type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// SQLite parameters index from 1.
|
||||
if (jObjectParam == nullptr) {
|
||||
rc = f_sqlite3_bind_null(ppStmt, i + 1);
|
||||
} else {
|
||||
jstring jStringParam = (jstring) jObjectParam;
|
||||
const char* paramStr = jenv->GetStringUTFChars(jStringParam, nullptr);
|
||||
rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
|
||||
jenv->ReleaseStringUTFChars(jStringParam, paramStr);
|
||||
}
|
||||
|
||||
if (rc != SQLITE_OK) {
|
||||
throwSqliteException(jenv, "Error binding query parameter");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the query and step through the results
|
||||
rc = f_sqlite3_step(ppStmt);
|
||||
if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
|
||||
throwSqliteException(jenv,
|
||||
"Can't step statement: (%d) %s", rc, f_sqlite3_errmsg(db));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the column count and names
|
||||
int cols;
|
||||
cols = f_sqlite3_column_count(ppStmt);
|
||||
|
||||
{
|
||||
// Allocate a String[cols]
|
||||
jobjectArray jStringArray = jenv->NewObjectArray(cols,
|
||||
stringClass,
|
||||
nullptr);
|
||||
if (jStringArray == nullptr) {
|
||||
throwSqliteException(jenv, "Can't allocate String[]");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Assign column names to the String[]
|
||||
for (int i = 0; i < cols; i++) {
|
||||
const char* colName = f_sqlite3_column_name(ppStmt, i);
|
||||
jstring jStr = jenv->NewStringUTF(colName);
|
||||
jenv->SetObjectArrayElement(jStringArray, i, jStr);
|
||||
}
|
||||
|
||||
// Construct the MatrixCursor(String[]) with given column names
|
||||
jCursor = jenv->NewObject(cursorClass,
|
||||
jCursorConstructor,
|
||||
jStringArray);
|
||||
if (jCursor == nullptr) {
|
||||
throwSqliteException(jenv, "Can't allocate MatrixBlobCursor");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the id and number of changed rows in jQueryRes
|
||||
{
|
||||
jlong id = f_sqlite3_last_insert_rowid(db);
|
||||
jenv->SetLongArrayRegion(jQueryRes, 0, 1, &id);
|
||||
|
||||
jlong changed = f_sqlite3_changes(db);
|
||||
jenv->SetLongArrayRegion(jQueryRes, 1, 1, &changed);
|
||||
}
|
||||
|
||||
// For each row, add an Object[] to the passed ArrayList,
|
||||
// with that containing either String or ByteArray objects
|
||||
// containing the columns
|
||||
while (rc != SQLITE_DONE) {
|
||||
// Process row
|
||||
// Construct Object[]
|
||||
jobjectArray jRow = jenv->NewObjectArray(cols,
|
||||
objectClass,
|
||||
nullptr);
|
||||
if (jRow == nullptr) {
|
||||
throwSqliteException(jenv, "Can't allocate jRow Object[]");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cols; i++) {
|
||||
int colType = f_sqlite3_column_type(ppStmt, i);
|
||||
if (colType == SQLITE_BLOB) {
|
||||
// Treat as blob
|
||||
const void* blob = f_sqlite3_column_blob(ppStmt, i);
|
||||
int colLen = f_sqlite3_column_bytes(ppStmt, i);
|
||||
|
||||
// Construct ByteBuffer of correct size
|
||||
jobject jByteBuffer =
|
||||
jenv->CallStaticObjectMethod(byteBufferClass,
|
||||
jByteBufferAllocateDirect,
|
||||
colLen);
|
||||
if (jByteBuffer == nullptr) {
|
||||
throwSqliteException(jenv,
|
||||
"Failure calling ByteBuffer.allocateDirect");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get its backing array
|
||||
void* bufferArray = jenv->GetDirectBufferAddress(jByteBuffer);
|
||||
if (bufferArray == nullptr) {
|
||||
throwSqliteException(jenv,
|
||||
"Failure calling GetDirectBufferAddress");
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(bufferArray, blob, colLen);
|
||||
|
||||
jenv->SetObjectArrayElement(jRow, i, jByteBuffer);
|
||||
jenv->DeleteLocalRef(jByteBuffer);
|
||||
} else if (colType == SQLITE_NULL) {
|
||||
jenv->SetObjectArrayElement(jRow, i, nullptr);
|
||||
} else {
|
||||
// Treat everything else as text
|
||||
const char* txt = (const char*)f_sqlite3_column_text(ppStmt, i);
|
||||
jstring jStr = jenv->NewStringUTF(txt);
|
||||
jenv->SetObjectArrayElement(jRow, i, jStr);
|
||||
jenv->DeleteLocalRef(jStr);
|
||||
}
|
||||
}
|
||||
|
||||
// Append Object[] to Cursor
|
||||
jenv->CallVoidMethod(jCursor, jCursorAddRow, jRow);
|
||||
|
||||
// Clean up
|
||||
jenv->DeleteLocalRef(jRow);
|
||||
|
||||
// Get next row
|
||||
rc = f_sqlite3_step(ppStmt);
|
||||
// Real error?
|
||||
if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
|
||||
throwSqliteException(jenv,
|
||||
"Can't re-step statement:(%d) %s", rc, f_sqlite3_errmsg(db));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
rc = f_sqlite3_finalize(ppStmt);
|
||||
if (rc != SQLITE_OK) {
|
||||
throwSqliteException(jenv,
|
||||
"Can't finalize statement: %s", f_sqlite3_errmsg(db));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return jCursor;
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/* 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 SQLiteBridge_h
|
||||
#define SQLiteBridge_h
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
void setup_sqlite_functions(void *sqlite_handle);
|
||||
|
||||
#define SQLITE_WRAPPER(name, return_type, args...) \
|
||||
typedef return_type (*name ## _t)(args); \
|
||||
extern name ## _t f_ ## name;
|
||||
|
||||
SQLITE_WRAPPER(sqlite3_open, int, const char*, sqlite3**)
|
||||
SQLITE_WRAPPER(sqlite3_errmsg, const char*, sqlite3*)
|
||||
SQLITE_WRAPPER(sqlite3_prepare_v2, int, sqlite3*, const char*, int, sqlite3_stmt**, const char**)
|
||||
SQLITE_WRAPPER(sqlite3_bind_parameter_count, int, sqlite3_stmt*)
|
||||
SQLITE_WRAPPER(sqlite3_bind_text, int, sqlite3_stmt*, int, const char*, int, void(*)(void*))
|
||||
SQLITE_WRAPPER(sqlite3_bind_null, int, sqlite3_stmt*, int)
|
||||
SQLITE_WRAPPER(sqlite3_step, int, sqlite3_stmt*)
|
||||
SQLITE_WRAPPER(sqlite3_column_count, int, sqlite3_stmt*)
|
||||
SQLITE_WRAPPER(sqlite3_finalize, int, sqlite3_stmt*)
|
||||
SQLITE_WRAPPER(sqlite3_close, int, sqlite3*)
|
||||
SQLITE_WRAPPER(sqlite3_column_name, const char*, sqlite3_stmt*, int)
|
||||
SQLITE_WRAPPER(sqlite3_column_type, int, sqlite3_stmt*, int)
|
||||
SQLITE_WRAPPER(sqlite3_column_blob, const void*, sqlite3_stmt*, int)
|
||||
SQLITE_WRAPPER(sqlite3_column_bytes, int, sqlite3_stmt*, int)
|
||||
SQLITE_WRAPPER(sqlite3_column_text, const unsigned char*, sqlite3_stmt*, int)
|
||||
SQLITE_WRAPPER(sqlite3_changes, int, sqlite3*)
|
||||
SQLITE_WRAPPER(sqlite3_last_insert_rowid, sqlite3_int64, sqlite3*)
|
||||
|
||||
#endif /* SQLiteBridge_h */
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; 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 <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT
|
||||
void JNICALL
|
||||
Java_org_mozilla_gecko_mozglue_SharedMemBuffer_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_mozglue_SharedMemBuffer_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);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# -*- 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',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'APKOpen.cpp',
|
||||
'NativeCrypto.cpp',
|
||||
'nsGeckoUtils.cpp',
|
||||
'NSSBridge.cpp',
|
||||
'pbkdf2_sha256.c',
|
||||
'SharedMemNatives.cpp',
|
||||
'SQLiteBridge.cpp',
|
||||
]
|
||||
|
||||
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',
|
||||
'/db/sqlite3/src',
|
||||
'/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',
|
||||
'/toolkit/components/startup',
|
||||
'/xpcom/build',
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; 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"
|
||||
|
||||
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"
|
||||
__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());
|
||||
}
|
||||
|
|
@ -1,432 +0,0 @@
|
|||
/*-
|
||||
* 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));
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*-
|
||||
* 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_ */
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <android/log.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define NS_EXPORT __attribute__ ((visibility("default")))
|
||||
|
||||
#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
|
||||
/* Android doesn't have pthread_atfork(), so we need to use our own. */
|
||||
struct AtForkFuncs {
|
||||
void (*prepare)(void);
|
||||
void (*parent)(void);
|
||||
void (*child)(void);
|
||||
};
|
||||
|
||||
/* jemalloc's initialization calls pthread_atfork. When pthread_atfork (see
|
||||
* further below) stores the corresponding data, it's going to allocate memory,
|
||||
* which will loop back to jemalloc's initialization, leading to a dead-lock.
|
||||
* So, for that specific vector, we use a special allocator that returns a
|
||||
* static buffer for small sizes, and force the initial vector capacity to
|
||||
* a size enough to store one atfork function table. */
|
||||
template <typename T>
|
||||
struct SpecialAllocator: public std::allocator<T>
|
||||
{
|
||||
SpecialAllocator(): bufUsed(false) {}
|
||||
|
||||
inline typename std::allocator<T>::pointer allocate(typename std::allocator<T>::size_type n, const void * = 0) {
|
||||
if (!bufUsed && n == 1) {
|
||||
bufUsed = true;
|
||||
return buf.addr();
|
||||
}
|
||||
return reinterpret_cast<T *>(::operator new(sizeof(T) * n));
|
||||
}
|
||||
|
||||
inline void deallocate(typename std::allocator<T>::pointer p, typename std::allocator<T>::size_type n) {
|
||||
if (p == buf.addr())
|
||||
bufUsed = false;
|
||||
else
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
struct rebind {
|
||||
typedef SpecialAllocator<U> other;
|
||||
};
|
||||
|
||||
private:
|
||||
mozilla::AlignedStorage2<T> buf;
|
||||
bool bufUsed;
|
||||
};
|
||||
|
||||
static std::vector<AtForkFuncs, SpecialAllocator<AtForkFuncs> > atfork;
|
||||
#endif
|
||||
|
||||
#define cpuacct_add(x)
|
||||
|
||||
#if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
|
||||
extern "C" NS_EXPORT int
|
||||
pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
|
||||
{
|
||||
AtForkFuncs funcs;
|
||||
funcs.prepare = prepare;
|
||||
funcs.parent = parent;
|
||||
funcs.child = child;
|
||||
if (!atfork.capacity())
|
||||
atfork.reserve(1);
|
||||
atfork.push_back(funcs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" NS_EXPORT pid_t __fork(void);
|
||||
|
||||
extern "C" NS_EXPORT pid_t
|
||||
fork(void)
|
||||
{
|
||||
pid_t pid;
|
||||
for (auto it = atfork.rbegin();
|
||||
it < atfork.rend(); ++it)
|
||||
if (it->prepare)
|
||||
it->prepare();
|
||||
|
||||
switch ((pid = syscall(__NR_clone, SIGCHLD, NULL, NULL, NULL, NULL))) {
|
||||
case 0:
|
||||
cpuacct_add(getuid());
|
||||
for (auto it = atfork.begin();
|
||||
it < atfork.end(); ++it)
|
||||
if (it->child)
|
||||
it->child();
|
||||
break;
|
||||
default:
|
||||
for (auto it = atfork.begin();
|
||||
it < atfork.end(); ++it)
|
||||
if (it->parent)
|
||||
it->parent();
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" NS_EXPORT int
|
||||
raise(int sig)
|
||||
{
|
||||
// Bug 741272: Bionic incorrectly uses kill(), which signals the
|
||||
// process, and thus could signal another thread (and let this one
|
||||
// return "successfully" from raising a fatal signal).
|
||||
//
|
||||
// Bug 943170: POSIX specifies pthread_kill(pthread_self(), sig) as
|
||||
// equivalent to raise(sig), but Bionic also has a bug with these
|
||||
// functions, where a forked child will kill its parent instead.
|
||||
|
||||
extern pid_t gettid(void);
|
||||
return syscall(__NR_tgkill, getpid(), gettid(), sig);
|
||||
}
|
||||
|
||||
/* Flash plugin uses symbols that are not present in Android >= 4.4 */
|
||||
namespace android {
|
||||
namespace VectorImpl {
|
||||
NS_EXPORT void reservedVectorImpl1(void) { }
|
||||
NS_EXPORT void reservedVectorImpl2(void) { }
|
||||
NS_EXPORT void reservedVectorImpl3(void) { }
|
||||
NS_EXPORT void reservedVectorImpl4(void) { }
|
||||
NS_EXPORT void reservedVectorImpl5(void) { }
|
||||
NS_EXPORT void reservedVectorImpl6(void) { }
|
||||
NS_EXPORT void reservedVectorImpl7(void) { }
|
||||
NS_EXPORT void reservedVectorImpl8(void) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
// we don't compile one of these detection methods. The detection code here is
|
||||
// based on the CPU detection in libtheora.
|
||||
|
||||
# if defined(__linux__) || defined(ANDROID)
|
||||
# if defined(__linux__)
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
|
@ -125,7 +125,7 @@ check_neon(void)
|
|||
}
|
||||
# endif
|
||||
|
||||
# endif // defined(__linux__) || defined(ANDROID)
|
||||
# endif // defined(__linux__)
|
||||
|
||||
namespace mozilla {
|
||||
namespace arm_private {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
# endif
|
||||
|
||||
// Currently we only have CPU detection for Linux via /proc/cpuinfo
|
||||
# if defined(__linux__) || defined(ANDROID)
|
||||
# if defined(__linux__)
|
||||
# define MOZILLA_ARM_HAVE_CPUID_DETECTION 1
|
||||
# endif
|
||||
|
||||
|
|
|
|||
|
|
@ -4,31 +4,22 @@
|
|||
# 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/.
|
||||
|
||||
# Build mozglue as a shared lib on Windows, OSX and Android.
|
||||
# Build mozglue as a shared lib on Windows, OSX.
|
||||
# If this is ever changed, update MOZ_SHARED_MOZGLUE in browser/installer/Makefile.in
|
||||
if CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android'):
|
||||
if CONFIG['OS_TARGET'] in ('WINNT', 'Darwin'):
|
||||
SharedLibrary('mozglue')
|
||||
else:
|
||||
Library('mozglue')
|
||||
|
||||
SDK_LIBRARY = True
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'Android':
|
||||
SOURCES += [
|
||||
'BionicGlue.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_ASAN']:
|
||||
SOURCES += [
|
||||
'AsanOptions.cpp',
|
||||
]
|
||||
SOURCES += ['AsanOptions.cpp']
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
DEFFILE = 'mozglue.def'
|
||||
# We'll break the DLL blocklist if we immediately load user32.dll
|
||||
DELAYLOAD_DLLS += [
|
||||
'user32.dll',
|
||||
]
|
||||
DELAYLOAD_DLLS += ['user32.dll']
|
||||
|
||||
if not CONFIG['JS_STANDALONE']:
|
||||
|
||||
|
|
@ -38,21 +29,13 @@ if not CONFIG['JS_STANDALONE']:
|
|||
else:
|
||||
# Temporary, until bug 662814 lands
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
SOURCES += [
|
||||
'dummy.cpp',
|
||||
]
|
||||
SOURCES += ['dummy.cpp']
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
LOCAL_INCLUDES += [
|
||||
'/memory/build',
|
||||
]
|
||||
SOURCES += [
|
||||
'WindowsDllBlocklist.cpp',
|
||||
]
|
||||
LOCAL_INCLUDES += ['/memory/build']
|
||||
SOURCES += ['WindowsDllBlocklist.cpp']
|
||||
DISABLE_STL_WRAPPING = True
|
||||
OS_LIBS += [
|
||||
'version',
|
||||
]
|
||||
OS_LIBS += ['version']
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'arm.h',
|
||||
|
|
@ -62,28 +45,18 @@ if not CONFIG['JS_STANDALONE']:
|
|||
]
|
||||
|
||||
if CONFIG['CPU_ARCH'].startswith('x86'):
|
||||
SOURCES += [
|
||||
'SSE.cpp',
|
||||
]
|
||||
SOURCES += ['SSE.cpp']
|
||||
|
||||
if CONFIG['CPU_ARCH'] == 'arm':
|
||||
SOURCES += [
|
||||
'arm.cpp',
|
||||
]
|
||||
SOURCES += ['arm.cpp']
|
||||
|
||||
if CONFIG['CPU_ARCH'].startswith('mips'):
|
||||
SOURCES += [
|
||||
'mips.cpp',
|
||||
]
|
||||
SOURCES += ['mips.cpp']
|
||||
|
||||
if CONFIG['MOZ_LINKER']:
|
||||
USE_LIBS += [
|
||||
'zlib',
|
||||
]
|
||||
USE_LIBS += ['zlib']
|
||||
|
||||
USE_LIBS += [
|
||||
'mfbt',
|
||||
]
|
||||
USE_LIBS += ['mfbt']
|
||||
|
||||
DEFINES['IMPL_MFBT'] = True
|
||||
LIBRARY_DEFINES['MOZ_HAS_MOZGLUE'] = True
|
||||
|
|
|
|||
|
|
@ -20,15 +20,8 @@ using namespace mozilla;
|
|||
|
||||
/* Function used to report library mappings from the custom linker to Gecko
|
||||
* crash reporter */
|
||||
#ifdef ANDROID
|
||||
extern "C" {
|
||||
void report_mapping(char *name, void *base, uint32_t len, uint32_t offset);
|
||||
void delete_mapping(const char *name);
|
||||
}
|
||||
#else
|
||||
#define report_mapping(...)
|
||||
#define delete_mapping(...)
|
||||
#endif
|
||||
|
||||
const Ehdr *Ehdr::validate(const void *buf)
|
||||
{
|
||||
|
|
@ -162,13 +155,10 @@ CustomElf::Load(Mappable *mappable, const char *path, int flags)
|
|||
break;
|
||||
case PT_GNU_STACK:
|
||||
debug_phdr("PT_GNU_STACK", phdr);
|
||||
// Skip on Android until bug 706116 is fixed
|
||||
#ifndef ANDROID
|
||||
if (phdr->p_flags & PF_X) {
|
||||
ERROR("%s: Executable stack is not supported", elf->GetPath());
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef __ARM_EABI__
|
||||
case PT_ARM_EXIDX:
|
||||
|
|
|
|||
|
|
@ -18,23 +18,6 @@
|
|||
#include "Logging.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <android/api-level.h>
|
||||
#if __ANDROID_API__ < 8
|
||||
/* Android API < 8 doesn't provide sigaltstack */
|
||||
|
||||
extern "C" {
|
||||
|
||||
inline int sigaltstack(const stack_t *ss, stack_t *oss) {
|
||||
return syscall(__NR_sigaltstack, ss, oss);
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
#endif /* __ANDROID_API__ */
|
||||
#endif /* ANDROID */
|
||||
|
||||
#ifdef __ARM_EABI__
|
||||
extern "C" MOZ_EXPORT const void *
|
||||
__gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
|
||||
|
|
@ -348,16 +331,6 @@ SystemElf::GetMappable() const
|
|||
const char *path = GetPath();
|
||||
if (!path)
|
||||
return nullptr;
|
||||
#ifdef ANDROID
|
||||
/* On Android, if we don't have the full path, try in /system/lib */
|
||||
const char *name = LeafName(path);
|
||||
std::string systemPath;
|
||||
if (name == path) {
|
||||
systemPath = "/system/lib/";
|
||||
systemPath += path;
|
||||
path = systemPath.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
return MappableFile::Create(path);
|
||||
}
|
||||
|
|
@ -550,17 +523,9 @@ void
|
|||
ElfLoader::Init()
|
||||
{
|
||||
Dl_info info;
|
||||
/* On Android < 4.1 can't reenter dl* functions. So when the library
|
||||
* containing this code is dlopen()ed, it can't call dladdr from a
|
||||
* static initializer. */
|
||||
if (dladdr(_DYNAMIC, &info) != 0) {
|
||||
self_elf = LoadedElf::Create(info.dli_fname, info.dli_fbase);
|
||||
}
|
||||
#if defined(ANDROID)
|
||||
if (dladdr(FunctionPtr(syscall), &info) != 0) {
|
||||
libc = LoadedElf::Create(info.dli_fname, info.dli_fbase);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ElfLoader::~ElfLoader()
|
||||
|
|
@ -573,9 +538,6 @@ ElfLoader::~ElfLoader()
|
|||
|
||||
/* Release self_elf and libc */
|
||||
self_elf = nullptr;
|
||||
#if defined(ANDROID)
|
||||
libc = nullptr;
|
||||
#endif
|
||||
|
||||
/* Build up a list of all library handles with direct (external) references.
|
||||
* We actually skip system library handles because we want to keep at least
|
||||
|
|
@ -962,88 +924,6 @@ ElfLoader::DebuggerHelper::Remove(ElfLoader::link_map *map)
|
|||
dbg->r_brk();
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* As some system libraries may be calling signal() or sigaction() to
|
||||
* set a SIGSEGV handler, effectively breaking MappableSeekableZStream,
|
||||
* or worse, restore our SIGSEGV handler with wrong flags (which using
|
||||
* signal() will do), we want to hook into the system's sigaction() to
|
||||
* replace it with our own wrapper instead, so that our handler is never
|
||||
* replaced. We used to only do that with libraries this linker loads,
|
||||
* but it turns out at least one system library does call signal() and
|
||||
* breaks us (libsc-a3xx.so on the Samsung Galaxy S4).
|
||||
* As libc's signal (bsd_signal/sysv_signal, really) calls sigaction
|
||||
* under the hood, instead of calling the signal system call directly,
|
||||
* we only need to hook sigaction. This is true for both bionic and
|
||||
* glibc.
|
||||
*/
|
||||
|
||||
/* libc's sigaction */
|
||||
extern "C" int
|
||||
sigaction(int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact);
|
||||
|
||||
/* Simple reimplementation of sigaction. This is roughly equivalent
|
||||
* to the assembly that comes in bionic, but not quite equivalent to
|
||||
* glibc's implementation, so we only use this on Android. */
|
||||
int
|
||||
sys_sigaction(int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
{
|
||||
return syscall(__NR_sigaction, signum, act, oldact);
|
||||
}
|
||||
|
||||
/* Replace the first instructions of the given function with a jump
|
||||
* to the given new function. */
|
||||
template <typename T>
|
||||
static bool
|
||||
Divert(T func, T new_func)
|
||||
{
|
||||
void *ptr = FunctionPtr(func);
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
#if defined(__i386__)
|
||||
// A 32-bit jump is a 5 bytes instruction.
|
||||
EnsureWritable w(ptr, 5);
|
||||
*reinterpret_cast<unsigned char *>(addr) = 0xe9; // jmp
|
||||
*reinterpret_cast<intptr_t *>(addr + 1) =
|
||||
reinterpret_cast<uintptr_t>(new_func) - addr - 5; // target displacement
|
||||
return true;
|
||||
#elif defined(__arm__)
|
||||
const unsigned char trampoline[] = {
|
||||
// .thumb
|
||||
0x46, 0x04, // nop
|
||||
0x78, 0x47, // bx pc
|
||||
0x46, 0x04, // nop
|
||||
// .arm
|
||||
0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
|
||||
// .word <new_func>
|
||||
};
|
||||
const unsigned char *start;
|
||||
if (addr & 0x01) {
|
||||
/* Function is thumb, the actual address of the code is without the
|
||||
* least significant bit. */
|
||||
addr--;
|
||||
/* The arm part of the trampoline needs to be 32-bit aligned */
|
||||
if (addr & 0x02)
|
||||
start = trampoline;
|
||||
else
|
||||
start = trampoline + 2;
|
||||
} else {
|
||||
/* Function is arm, we only need the arm part of the trampoline */
|
||||
start = trampoline + 6;
|
||||
}
|
||||
|
||||
size_t len = sizeof(trampoline) - (start - trampoline);
|
||||
EnsureWritable w(reinterpret_cast<void *>(addr), len + sizeof(void *));
|
||||
memcpy(reinterpret_cast<void *>(addr), start, len);
|
||||
*reinterpret_cast<void **>(addr + len) = FunctionPtr(new_func);
|
||||
cacheflush(addr, addr + len + sizeof(void *), 0);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#define sys_sigaction sigaction
|
||||
template <typename T>
|
||||
static bool
|
||||
|
|
@ -1051,7 +931,7 @@ Divert(T func, T new_func)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
@ -1144,48 +1024,6 @@ SEGVHandler::FinishInitialization()
|
|||
|
||||
sigaction_func libc_sigaction;
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* Android > 4.4 comes with a sigaction wrapper in a LD_PRELOADed library
|
||||
* (libsigchain) for ART. That wrapper kind of does the same trick as we
|
||||
* do, so we need extra care in handling it.
|
||||
* - Divert the libc's sigaction, assuming the LD_PRELOADed library uses
|
||||
* it under the hood (which is more or less true according to the source
|
||||
* of that library, since it's doing a lookup in RTLD_NEXT)
|
||||
* - With the LD_PRELOADed library in place, all calls to sigaction from
|
||||
* from system libraries will go to the LD_PRELOADed library.
|
||||
* - The LD_PRELOADed library calls to sigaction go to our __wrap_sigaction.
|
||||
* - The calls to sigaction from libraries faulty.lib loads are sent to
|
||||
* the LD_PRELOADed library.
|
||||
* In practice, for signal handling, this means:
|
||||
* - The signal handler registered to the kernel is ours.
|
||||
* - Our handler redispatches to the LD_PRELOADed library's if there's a
|
||||
* segfault we don't handle.
|
||||
* - The LD_PRELOADed library redispatches according to whatever system
|
||||
* library or faulty.lib-loaded library set with sigaction.
|
||||
*
|
||||
* When there is no sigaction wrapper in place:
|
||||
* - Divert the libc's sigaction.
|
||||
* - Calls to sigaction from system library and faulty.lib-loaded libraries
|
||||
* all go to the libc's sigaction, which end up in our __wrap_sigaction.
|
||||
* - The signal handler registered to the kernel is ours.
|
||||
* - Our handler redispatches according to whatever system library or
|
||||
* faulty.lib-loaded library set with sigaction.
|
||||
*/
|
||||
void *libc = dlopen("libc.so", RTLD_GLOBAL | RTLD_LAZY);
|
||||
if (libc) {
|
||||
/*
|
||||
* Lollipop bionic only has a small trampoline in sigaction, with the real
|
||||
* work happening in __sigaction. Divert there instead of sigaction if it exists.
|
||||
* Bug 1154803
|
||||
*/
|
||||
libc_sigaction = reinterpret_cast<sigaction_func>(dlsym(libc, "__sigaction"));
|
||||
|
||||
if (!libc_sigaction) {
|
||||
libc_sigaction =
|
||||
reinterpret_cast<sigaction_func>(dlsym(libc, "sigaction"));
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
libc_sigaction = sigaction;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -471,14 +471,6 @@ private:
|
|||
* is used to resolve wrapped functions. */
|
||||
RefPtr<LibHandle> self_elf;
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* System loader handle for the libc. This is used to resolve weak symbols
|
||||
* that some libcs contain that the Android linker won't dlsym(). Normally,
|
||||
* we wouldn't treat non-Android differently, but glibc uses versioned
|
||||
* symbols which this linker doesn't support. */
|
||||
RefPtr<LibHandle> libc;
|
||||
#endif
|
||||
|
||||
/* Bookkeeping */
|
||||
typedef std::vector<LibHandle *> LibHandleList;
|
||||
LibHandleList handles;
|
||||
|
|
|
|||
|
|
@ -5,15 +5,7 @@
|
|||
#ifndef Elfxx_h
|
||||
#define Elfxx_h
|
||||
|
||||
/**
|
||||
* Android system headers have two different elf.h file. The one under linux/
|
||||
* is the most complete on older android API versions.
|
||||
*/
|
||||
#if defined(ANDROID) && __ANDROID_API__ < 21
|
||||
#include <linux/elf.h>
|
||||
#else
|
||||
#include <elf.h>
|
||||
#endif
|
||||
#include <endian.h>
|
||||
|
||||
#if defined(__ARM_EABI__) && !defined(PT_ARM_EXIDX)
|
||||
|
|
|
|||
|
|
@ -7,41 +7,6 @@
|
|||
|
||||
#include "mozilla/Likely.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "GeckoLinker", __VA_ARGS__)
|
||||
#define WARN(...) __android_log_print(ANDROID_LOG_WARN, "GeckoLinker", __VA_ARGS__)
|
||||
#define ERROR(...) __android_log_print(ANDROID_LOG_ERROR, "GeckoLinker", __VA_ARGS__)
|
||||
#else
|
||||
#include <cstdio>
|
||||
|
||||
/* Expand to 1 or m depending on whether there is one argument or more
|
||||
* given. */
|
||||
#define MOZ_ONE_OR_MORE_ARGS_IMPL2(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) \
|
||||
N
|
||||
#define MOZ_ONE_OR_MORE_ARGS_IMPL(args) MOZ_ONE_OR_MORE_ARGS_IMPL2 args
|
||||
#define MOZ_ONE_OR_MORE_ARGS(...) \
|
||||
MOZ_ONE_OR_MORE_ARGS_IMPL((__VA_ARGS__, m, m, m, m, m, m, m, m, 1, 0))
|
||||
|
||||
#define MOZ_MACRO_GLUE(a, b) a b
|
||||
#define MOZ_CONCAT2(a, b) a ## b
|
||||
#define MOZ_CONCAT1(a, b) MOZ_CONCAT2(a, b)
|
||||
#define MOZ_CONCAT(a, b) MOZ_CONCAT1(a, b)
|
||||
|
||||
/* Some magic to choose between LOG1 and LOGm depending on the number of
|
||||
* arguments */
|
||||
#define MOZ_CHOOSE_LOG(...) \
|
||||
MOZ_MACRO_GLUE(MOZ_CONCAT(LOG, MOZ_ONE_OR_MORE_ARGS(__VA_ARGS__)), \
|
||||
(__VA_ARGS__))
|
||||
|
||||
#define LOG1(format) fprintf(stderr, format "\n")
|
||||
#define LOGm(format, ...) fprintf(stderr, format "\n", __VA_ARGS__)
|
||||
#define LOG(...) MOZ_CHOOSE_LOG(__VA_ARGS__)
|
||||
#define WARN(...) MOZ_CHOOSE_LOG("Warning: " __VA_ARGS__)
|
||||
#define ERROR(...) MOZ_CHOOSE_LOG("Error: " __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
class Logging
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@
|
|||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <linux/ashmem.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include "ElfLoader.h"
|
||||
|
|
@ -263,7 +260,6 @@ MappableExtractFile::Create(const char *name, Zip *zip, Zip::Stream *stream)
|
|||
* _MappableBuffer is a buffer which content can be mapped at different
|
||||
* locations in the virtual address space.
|
||||
* On Linux, uses a (deleted) temporary file on a tmpfs for sharable content.
|
||||
* On Android, uses ashmem.
|
||||
*/
|
||||
class _MappableBuffer: public MappedPtr
|
||||
{
|
||||
|
|
@ -275,57 +271,7 @@ public:
|
|||
static _MappableBuffer *Create(const char *name, size_t length)
|
||||
{
|
||||
AutoCloseFD fd;
|
||||
#ifdef ANDROID
|
||||
/* On Android, initialize an ashmem region with the given length */
|
||||
fd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600);
|
||||
if (fd == -1)
|
||||
return nullptr;
|
||||
char str[ASHMEM_NAME_LEN];
|
||||
strlcpy(str, name, sizeof(str));
|
||||
ioctl(fd, ASHMEM_SET_NAME, str);
|
||||
if (ioctl(fd, ASHMEM_SET_SIZE, length))
|
||||
return nullptr;
|
||||
|
||||
/* The Gecko crash reporter is confused by adjacent memory mappings of
|
||||
* the same file and chances are we're going to map from the same file
|
||||
* descriptor right away. To avoid problems with the crash reporter,
|
||||
* create an empty anonymous page before or after the ashmem mapping,
|
||||
* depending on how mappings grow in the address space.
|
||||
*/
|
||||
#if defined(__arm__)
|
||||
void *buf = ::mmap(nullptr, length + PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
::mmap(AlignedEndPtr(reinterpret_cast<char *>(buf) + length, PAGE_SIZE),
|
||||
PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
DEBUG_LOG("Decompression buffer of size 0x%x in ashmem \"%s\", mapped @%p",
|
||||
length, str, buf);
|
||||
return new _MappableBuffer(fd.forget(), buf, length);
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
size_t anon_mapping_length = length + PAGE_SIZE;
|
||||
void *buf = ::mmap(nullptr, anon_mapping_length, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (buf != MAP_FAILED) {
|
||||
char *first_page = reinterpret_cast<char *>(buf);
|
||||
char *map_page = first_page + PAGE_SIZE;
|
||||
|
||||
void *actual_buf = ::mmap(map_page, length, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_SHARED, fd, 0);
|
||||
if (actual_buf == MAP_FAILED) {
|
||||
::munmap(buf, anon_mapping_length);
|
||||
DEBUG_LOG("Fixed allocation of decompression buffer at %p failed", map_page);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Decompression buffer of size 0x%x in ashmem \"%s\", mapped @%p",
|
||||
length, str, actual_buf);
|
||||
return new _MappableBuffer(fd.forget(), actual_buf, length);
|
||||
}
|
||||
#else
|
||||
#error need to add a case for your CPU
|
||||
#endif
|
||||
#else
|
||||
/* On Linux, use /dev/shm as base directory for temporary files, assuming
|
||||
* it's on tmpfs */
|
||||
/* TODO: check that /dev/shm is tmpfs */
|
||||
|
|
@ -344,37 +290,16 @@ public:
|
|||
length, path, buf);
|
||||
return new _MappableBuffer(fd.forget(), buf, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *mmap(const void *addr, size_t length, int prot, int flags, off_t offset)
|
||||
{
|
||||
MOZ_ASSERT(fd != -1);
|
||||
#ifdef ANDROID
|
||||
/* Mapping ashmem MAP_PRIVATE is like mapping anonymous memory, even when
|
||||
* there is content in the ashmem */
|
||||
if (flags & MAP_PRIVATE) {
|
||||
flags &= ~MAP_PRIVATE;
|
||||
flags |= MAP_SHARED;
|
||||
}
|
||||
#endif
|
||||
return ::mmap(const_cast<void *>(addr), length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
~_MappableBuffer() {
|
||||
/* Free the additional page we allocated. See _MappableBuffer::Create */
|
||||
#if defined(__arm__)
|
||||
::munmap(AlignedEndPtr(*this + GetLength(), PAGE_SIZE), PAGE_SIZE);
|
||||
#elif defined(__i386__)
|
||||
::munmap(*this - PAGE_SIZE, GetLength() + PAGE_SIZE);
|
||||
#else
|
||||
#error need to add a case for your CPU
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
_MappableBuffer(int fd, void *buf, size_t length)
|
||||
: MappedPtr(buf, length), fd(fd) { }
|
||||
|
|
@ -440,15 +365,6 @@ MappableDeflate::mmap(const void *addr, size_t length, int prot, int flags, off_
|
|||
}
|
||||
}
|
||||
}
|
||||
#if defined(ANDROID) && defined(__arm__)
|
||||
if (prot & PROT_EXEC) {
|
||||
/* We just extracted data that may be executed in the future.
|
||||
* We thus need to ensure Instruction and Data cache coherency. */
|
||||
DEBUG_LOG("cacheflush(%p, %p)", *buffer + offset, *buffer + (offset + length));
|
||||
cacheflush(reinterpret_cast<uintptr_t>(*buffer + offset),
|
||||
reinterpret_cast<uintptr_t>(*buffer + (offset + length)), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return MemoryRange(buffer->mmap(addr, length, prot, flags, offset), length);
|
||||
}
|
||||
|
|
@ -611,15 +527,6 @@ MappableSeekableZStream::ensure(const void *addr)
|
|||
if (!zStream.DecompressChunk(*buffer + chunkStart, chunk, length))
|
||||
return false;
|
||||
|
||||
#if defined(ANDROID) && defined(__arm__)
|
||||
if (map->prot & PROT_EXEC) {
|
||||
/* We just extracted data that may be executed in the future.
|
||||
* We thus need to ensure Instruction and Data cache coherency. */
|
||||
DEBUG_LOG("cacheflush(%p, %p)", *buffer + chunkStart, *buffer + (chunkStart + length));
|
||||
cacheflush(reinterpret_cast<uintptr_t>(*buffer + chunkStart),
|
||||
reinterpret_cast<uintptr_t>(*buffer + (chunkStart + length)), 0);
|
||||
}
|
||||
#endif
|
||||
/* Only count if we haven't already decompressed parts of the chunk */
|
||||
if (chunkAvail[chunk] == 0)
|
||||
chunkAvailNum++;
|
||||
|
|
|
|||
|
|
@ -59,12 +59,6 @@ static CriticalAddress gCriticalAddress;
|
|||
extern MOZ_EXPORT void* __libc_stack_end; // from ld-linux.so
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <algorithm>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if MOZ_STACKWALK_SUPPORTS_MACOSX
|
||||
#include <pthread.h>
|
||||
#include <sys/errno.h>
|
||||
|
|
@ -931,31 +925,6 @@ MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
|
|||
stackEnd = __libc_stack_end;
|
||||
#elif defined(XP_DARWIN)
|
||||
stackEnd = pthread_get_stackaddr_np(pthread_self());
|
||||
#elif defined(ANDROID)
|
||||
pthread_attr_t sattr;
|
||||
pthread_attr_init(&sattr);
|
||||
pthread_getattr_np(pthread_self(), &sattr);
|
||||
void* stackBase = stackEnd = nullptr;
|
||||
size_t stackSize = 0;
|
||||
if (gettid() != getpid()) {
|
||||
// bionic's pthread_attr_getstack doesn't tell the truth for the main
|
||||
// thread (see bug 846670). So don't use it for the main thread.
|
||||
if (!pthread_attr_getstack(&sattr, &stackBase, &stackSize)) {
|
||||
stackEnd = static_cast<char*>(stackBase) + stackSize;
|
||||
} else {
|
||||
stackEnd = nullptr;
|
||||
}
|
||||
}
|
||||
if (!stackEnd) {
|
||||
// So consider the current frame pointer + an arbitrary size of 8MB
|
||||
// (modulo overflow ; not really arbitrary as it's the default stack
|
||||
// size for the main thread) if pthread_attr_getstack failed for
|
||||
// some reason (or was skipped).
|
||||
static const uintptr_t kMaxStackSize = 8 * 1024 * 1024;
|
||||
uintptr_t maxStackStart = uintptr_t(-1) - kMaxStackSize;
|
||||
uintptr_t stackStart = std::max(maxStackStart, uintptr_t(bp));
|
||||
stackEnd = reinterpret_cast<void*>(stackStart + kMaxStackSize);
|
||||
}
|
||||
#else
|
||||
# error Unsupported configuration
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ TimeStamp::Now(bool aHighResolution)
|
|||
return TimeStamp(ClockTimeNs());
|
||||
}
|
||||
|
||||
#if defined(XP_LINUX) || defined(ANDROID)
|
||||
#ifdef XP_LINUX
|
||||
|
||||
// Calculates the amount of jiffies that have elapsed since boot and up to the
|
||||
// starttime value of a specific process as found in its /proc/*/stat file.
|
||||
|
|
|
|||
|
|
@ -7,9 +7,6 @@
|
|||
if CONFIG['MOZ_LINKER']:
|
||||
DIRS += ['linker']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DIRS += ['android']
|
||||
|
||||
DIRS += [
|
||||
'build',
|
||||
'misc',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue