You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
4.2 KiB
162 lines
4.2 KiB
/* |
|
* Copyright 2018 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#define LOG_TAG "JavaVMHelper" |
|
|
|
#include "mediaplayer2/JavaVMHelper.h" |
|
|
|
#include <media/stagefright/foundation/ADebug.h> |
|
#include <utils/threads.h> |
|
|
|
#include <stdlib.h> |
|
|
|
namespace android { |
|
|
|
// static |
|
std::atomic<JavaVM *> JavaVMHelper::sJavaVM(NULL); |
|
|
|
/* |
|
* Makes the current thread visible to the VM. |
|
* |
|
* The JNIEnv pointer returned is only valid for the current thread, and |
|
* thus must be tucked into thread-local storage. |
|
*/ |
|
static int javaAttachThread(const char* threadName, JNIEnv** pEnv) { |
|
JavaVMAttachArgs args; |
|
JavaVM* vm; |
|
jint result; |
|
|
|
vm = JavaVMHelper::getJavaVM(); |
|
if (vm == NULL) { |
|
return JNI_ERR; |
|
} |
|
|
|
args.version = JNI_VERSION_1_4; |
|
args.name = (char*) threadName; |
|
args.group = NULL; |
|
|
|
result = vm->AttachCurrentThread(pEnv, (void*) &args); |
|
if (result != JNI_OK) { |
|
ALOGI("NOTE: attach of thread '%s' failed\n", threadName); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
/* |
|
* Detach the current thread from the set visible to the VM. |
|
*/ |
|
static int javaDetachThread(void) { |
|
JavaVM* vm; |
|
jint result; |
|
|
|
vm = JavaVMHelper::getJavaVM(); |
|
if (vm == NULL) { |
|
return JNI_ERR; |
|
} |
|
|
|
result = vm->DetachCurrentThread(); |
|
if (result != JNI_OK) { |
|
ALOGE("ERROR: thread detach failed\n"); |
|
} |
|
return result; |
|
} |
|
|
|
/* |
|
* When starting a native thread that will be visible from the VM, we |
|
* bounce through this to get the right attach/detach action. |
|
* Note that this function calls free(args) |
|
*/ |
|
static int javaThreadShell(void* args) { |
|
void* start = ((void**)args)[0]; |
|
void* userData = ((void **)args)[1]; |
|
char* name = (char*) ((void **)args)[2]; // we own this storage |
|
free(args); |
|
JNIEnv* env; |
|
int result; |
|
|
|
/* hook us into the VM */ |
|
if (javaAttachThread(name, &env) != JNI_OK) { |
|
return -1; |
|
} |
|
|
|
/* start the thread running */ |
|
result = (*(android_thread_func_t)start)(userData); |
|
|
|
/* unhook us */ |
|
javaDetachThread(); |
|
free(name); |
|
|
|
return result; |
|
} |
|
|
|
/* |
|
* This is invoked from androidCreateThreadEtc() via the callback |
|
* set with androidSetCreateThreadFunc(). |
|
* |
|
* We need to create the new thread in such a way that it gets hooked |
|
* into the VM before it really starts executing. |
|
*/ |
|
static int javaCreateThreadEtc( |
|
android_thread_func_t entryFunction, |
|
void* userData, |
|
const char* threadName, |
|
int32_t threadPriority, |
|
size_t threadStackSize, |
|
android_thread_id_t* threadId) { |
|
void** args = (void**) malloc(3 * sizeof(void*)); // javaThreadShell must free |
|
int result; |
|
|
|
LOG_ALWAYS_FATAL_IF(threadName == nullptr, "threadName not provided to javaCreateThreadEtc"); |
|
|
|
args[0] = (void*) entryFunction; |
|
args[1] = userData; |
|
args[2] = (void*) strdup(threadName); // javaThreadShell must free |
|
|
|
result = androidCreateRawThreadEtc(javaThreadShell, args, |
|
threadName, threadPriority, threadStackSize, threadId); |
|
return result; |
|
} |
|
|
|
// static |
|
JNIEnv *JavaVMHelper::getJNIEnv() { |
|
JNIEnv *env; |
|
JavaVM *vm = sJavaVM.load(); |
|
CHECK(vm != NULL); |
|
|
|
if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) { |
|
return NULL; |
|
} |
|
|
|
return env; |
|
} |
|
|
|
//static |
|
JavaVM *JavaVMHelper::getJavaVM() { |
|
return sJavaVM.load(); |
|
} |
|
|
|
// static |
|
void JavaVMHelper::setJavaVM(JavaVM *vm) { |
|
sJavaVM.store(vm); |
|
|
|
// Ensure that Thread(/*canCallJava*/ true) in libutils is attached to the VM. |
|
// This is supposed to be done by runtime, but when libutils is used with linker |
|
// namespace, CreateThreadFunc should be initialized separately within the namespace. |
|
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); |
|
} |
|
|
|
} // namespace android
|
|
|