blob: 1df1fd6ddb8a23b04d5c3bfaadb4f8ee4f9b787c [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.
*/
#pragma once
#include <jni.h>
#include <vector>
namespace tuningfork {
// A helper class that makes calling methods easier and also keeps track of object/string references
// and deletes them when the helper is destroyed.
class JNIHelper {
JNIEnv* env_;
std::vector<jobject> objs_;
jmethodID find_class_;
jobject activity_class_loader_;
public:
typedef std::pair<jclass,jobject> Object;
JNIHelper(JNIEnv* env, jobject activity) : env_(env) {
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;");
}
~JNIHelper() {
for(auto& o: objs_)
env_->DeleteLocalRef(o);
}
jclass FindClass(const char* class_name) {
jclass jni_class = env_->FindClass(class_name);
if (jni_class == NULL) {
// 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;
}
Object NewObject(const char * cclz, const char* ctorSig, ...) {
jclass clz = FindClass(cclz);
jmethodID constructor = env_->GetMethodID(clz, "<init>", ctorSig);
va_list argptr;
va_start(argptr, ctorSig);
jobject o = env_->NewObjectV(clz, constructor, argptr);
va_end(argptr);
objs_.push_back(o);
return {clz, o};
}
jobject CallObjectMethod(const Object& obj, const char* name, const char* sig, ...) {
jmethodID mid = env_->GetMethodID(obj.first, name, sig);
va_list argptr;
va_start(argptr, sig);
jobject o = env_->CallObjectMethodV(obj.second, mid, argptr);
va_end(argptr);
objs_.push_back(o);
return o;
}
Object Cast(jobject o, const std::string& clz="") {
if(clz.empty())
return {env_->GetObjectClass(o), o};
else
return {FindClass(clz.c_str()), o};
}
void CallVoidMethod(const Object& obj, const char* name, const char* sig, ...) {
jmethodID mid = env_->GetMethodID(obj.first, name, sig);
va_list argptr;
va_start(argptr, sig);
env_->CallVoidMethodV(obj.second, mid, argptr);
va_end(argptr);
}
int CallIntMethod(const Object& obj, const char* name, const char* sig, ...) {
jmethodID mid = env_->GetMethodID(obj.first, name, sig);
va_list argptr;
va_start(argptr, sig);
int r = env_->CallIntMethodV(obj.second, mid, argptr);
va_end(argptr);
return r;
}
jstring NewString(const char* c) {
auto s = env_->NewStringUTF(c);
objs_.push_back(s);
return s;
}
jstring NewString(const std::string& s) {
auto js = env_->NewStringUTF(s.c_str());
objs_.push_back(js);
return js;
}
bool CheckForException(std::string& msg) {
if(env_->ExceptionCheck()) {
jthrowable exception = env_->ExceptionOccurred();
env_->ExceptionClear();
jmethodID toString = env_->GetMethodID(FindClass("java/lang/Object"),
"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(s);
return true;
}
return false;
}
};
} // namespace tuningfork