blob: dcb19298e7827cfc0ce4733ffb701adc2b414eb0 [file] [log] [blame]
/*
* Copyright 2019 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.
*/
#include "jni_helper.h"
#include "jnictx.h"
namespace tuningfork {
namespace jni {
static jmethodID find_class_;
static LocalObject activity_class_loader_;
void InitActivityClassLoader() {
if (activity_class_loader_.IsNull()) {
jobject activity = AppContextGlobalRef();
jclass activity_clazz = Env()->GetObjectClass(activity);
jmethodID get_class_loader = Env()->GetMethodID(
activity_clazz, "getClassLoader", "()Ljava/lang/ClassLoader;");
activity_class_loader_ =
Env()->CallObjectMethod(activity, get_class_loader);
jclass class_loader = Env()->FindClass("java/lang/ClassLoader");
find_class_ = Env()->GetMethodID(
class_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
Env()->DeleteLocalRef(activity_clazz);
Env()->DeleteLocalRef(class_loader);
}
}
void Init(JNIEnv* env, jobject ctx) {
Ctx::Init(env, ctx);
}
bool IsValid() {
return Ctx::Instance()!=nullptr && Ctx::Instance()->IsValid();
}
JNIEnv* Env() {
return Ctx::Instance()->Env();
}
void DetachThread() {
return Ctx::Instance()->DetachThread();
}
jobject AppContextGlobalRef() {
return Ctx::Instance()->AppCtx();
}
jclass FindClass(const char* class_name) {
jclass jni_class = Env()->FindClass(class_name);
if (jni_class == NULL) {
InitActivityClassLoader();
// FindClass would have thrown.
Env()->ExceptionClear();
jstring class_jname = Env()->NewStringUTF(class_name);
jni_class =
(jclass)(Env()->CallObjectMethod(activity_class_loader_, find_class_, class_jname));
Env()->DeleteLocalRef(class_jname);
}
return jni_class;
}
LocalObject NewObjectV(const char * cclz, const char* ctorSig, va_list argptr) {
jclass clz = FindClass(cclz);
jmethodID constructor = Env()->GetMethodID(clz, "<init>", ctorSig);
jobject o = Env()->NewObjectV(clz, constructor, argptr);
return LocalObject(o, clz);
}
LocalObject NewObject(const char * cclz, const char* ctorSig, ...) {
va_list argptr;
va_start(argptr, ctorSig);
auto o = NewObjectV(cclz, ctorSig, argptr);
va_end(argptr);
return o;
}
jobject LocalObject::CallObjectMethod(const char* name, const char* sig, ...) const {
jmethodID mid = Env()->GetMethodID(clz_, name, sig);
va_list argptr;
va_start(argptr, sig);
jobject o = Env()->CallObjectMethodV(obj_, mid, argptr);
va_end(argptr);
return o;
}
jobject LocalObject::CallStaticObjectMethod(const char* name, const char* sig, ...) const {
jmethodID mid = Env()->GetStaticMethodID(clz_, name, sig);
va_list argptr;
va_start(argptr, sig);
jobject o = Env()->CallStaticObjectMethodV(clz_, mid, argptr);
va_end(argptr);
return o;
}
String LocalObject::CallStringMethod(const char* name, const char* sig, ...) const {
jmethodID mid = Env()->GetMethodID(clz_, name, sig);
va_list argptr;
va_start(argptr, sig);
jobject o = Env()->CallObjectMethodV(obj_, mid, argptr);
va_end(argptr);
String s((jstring)o);
return s;
}
void LocalObject::CallVoidMethod(const char* name, const char* sig, ...) const {
jmethodID mid = Env()->GetMethodID(clz_, name, sig);
va_list argptr;
va_start(argptr, sig);
Env()->CallVoidMethodV(obj_, mid, argptr);
va_end(argptr);
}
int LocalObject::CallIntMethod(const char* name, const char* sig, ...) const {
jmethodID mid = Env()->GetMethodID(clz_, name, sig);
va_list argptr;
va_start(argptr, sig);
int r = Env()->CallIntMethodV(obj_, mid, argptr);
va_end(argptr);
return r;
}
std::string GetExceptionMessage() {
std::string msg;
jthrowable exception = Env()->ExceptionOccurred();
Env()->ExceptionClear();
jclass oclass = FindClass("java/lang/Object");
jmethodID toString = Env()->GetMethodID(oclass,
"toString", "()Ljava/lang/String;");
jstring s = (jstring)Env()->CallObjectMethod(exception, toString);
const char* utf = Env()->GetStringUTFChars(s, nullptr);
msg = utf;
Env()->ReleaseStringUTFChars(s, utf);
Env()->DeleteLocalRef(oclass);
Env()->DeleteLocalRef(s);
Env()->DeleteLocalRef(exception);
return msg;
}
bool CheckForException(std::string& msg) {
if(Env()->ExceptionCheck()) {
msg = GetExceptionMessage();
return true;
}
return false;
}
LocalObject LocalObject::GetObjectField(const char* field_name,
const char* sig) const {
jfieldID fid = Env()->GetFieldID(clz_, field_name, sig);
if(!RawExceptionCheck()) {
auto out = Env()->GetObjectField(obj_, fid);
return LocalObject(out, nullptr);
} else {
return LocalObject(nullptr, nullptr);
}
}
int LocalObject::GetIntField(const char* field_name) const {
jfieldID fid = Env()->GetFieldID(clz_, field_name, "I");
if(!RawExceptionCheck())
return Env()->GetIntField(obj_, fid);
else
return BAD_FIELD;
}
std::vector<char> GetByteArrayBytesAndDeleteRef(jbyteArray jbs) {
jbyte* bs = Env()->GetByteArrayElements(jbs, 0);
std::vector<char> ret(bs, bs + Env()->GetArrayLength(jbs));
Env()->ReleaseByteArrayElements(jbs, bs, JNI_ABORT);
Env()->DeleteLocalRef(jbs);
return ret;
}
#ifndef NDEBUG
void DumpLocalRefTable()
{
JNIEnv* env = Env();
jclass vm_class = env->FindClass("dalvik/system/VMDebug");
jmethodID dump_mid = env->GetStaticMethodID( vm_class, "dumpReferenceTables", "()V" );
env->CallStaticVoidMethod( vm_class, dump_mid );
env->DeleteLocalRef(vm_class);
}
#endif
} // namespace jni
} // namespace tuningfork