summaryrefslogtreecommitdiff
path: root/libs/samba/src/main/cpp/jni.cpp
blob: be13df78f231bd5e84d82f0dab54890ef8a553ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "jni.hpp"

#include <android/log.h>

namespace {

JavaVM *g_vm;

const char *_jni_error(jint err) {
  switch (err) {
    case JNI_OK:
      return "OK";
    case JNI_ERR:
      return "Unknown error";
    case JNI_EDETACHED:
      return "Thread detached from the VM";
    case JNI_EVERSION:
      return "JNI version error";
    case JNI_ENOMEM:
      return "Not enough memory";
    case JNI_EEXIST:
      return "VM already created";
    case JNI_EINVAL:
      return "Invalid arguments";
    default:
      return "Unexpected error";
  }
}

}  // namespace

namespace jni {

namespace internal {

void _abort_if_not_ok(const char *file, int line, jint ret) {
  if (ret == JNI_OK) [[likely]] return;
  __android_log_assert(nullptr, "jni", "JNI error: %s", _jni_error(ret));
}

void _abort_with_exception(const char* file, int line, JNIEnv* env) {
  auto throwable = jni::ExceptionOccurred(env);
  env->ExceptionClear();
  if (throwable) {
    auto throwable_class = jni::FindClass(env, "java/lang/Throwable");
    if (throwable_class) {
      auto throwable_toString = env->GetMethodID(throwable_class.get(),
                                                 "toString",
                                                 "()Ljava/lang/String;");
      if (throwable_toString) {
        auto description = jni::CallObjectMethod<jstring>(env, throwable,
                                                          throwable_toString);
        auto str = jni::StringToUTF8(env, description);
        __android_log_assert(nullptr, "jni", "JNI error: %s", str.c_str());
      }
    }
    env->ExceptionClear();
    __android_log_assert(nullptr, "jni",
                         "Unexpected NULL but no exception");
  }
}

}  // namespace internal

JNIEnv* AttachCurrentThread() {
  JNIEnv* env;
  auto ret = g_vm->AttachCurrentThread(&env, nullptr);
  ABORT_IF_NOT_OK(ret);
  return env;
}

JNIEnv* OnLoad(JavaVM* vm) {
  void* v_env;
  auto ret = vm->GetEnv(&v_env, JNI_VERSION);
  ABORT_IF_NOT_OK(ret);
  return reinterpret_cast<JNIEnv*>(v_env);
}

LocalRef<jclass> FindClass(JNIEnv *env, const char *name) {
  return {env, env->FindClass(name)};
}

LocalRef<jthrowable> ExceptionOccurred(JNIEnv* env) {
  return {env, env->ExceptionOccurred()};
}

std::string StringToUTF8(JNIEnv* env, const Ref<jstring>& str) {
  if (!str) return "null";
  auto len = env->GetStringUTFLength(str.get());
  std::string ret(len, ' ');
  env->GetStringUTFRegion(str.get(), 0, len, ret.data());
  // This returns modified UTF-8 encoding, don't care.
  return ret;
}

LocalRef<jstring> UTF8ToString(JNIEnv* env, const std::string& str) {
  return {env, env->NewStringUTF(str.c_str())};
}

}  // namespace jni