1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <jni.h> 18 19 #include <hash_map> 20 #include <string> 21 22 #include "base/utilities.h" 23 #include "core/value.h" 24 25 #ifndef ANDROID_FILTERFW_JNI_JNI_UTIL_H 26 #define ANDROID_FILTERFW_JNI_JNI_UTIL_H 27 28 // We add this JNI_NULL macro to allow consistent code separation of Java and 29 // C++ types. 30 #define JNI_NULL NULL 31 32 #if 0 33 // Pointer to current JavaVM. Do not use this directly. Instead use the funciton 34 // GetCurrentJavaVM(). 35 extern JavaVM* g_current_java_vm_; 36 37 // Wrapper around a java object pointer, which includes the environment 38 // pointer in which the object "lives". This is used for passing down Java 39 // objects from the Java layer to C++. 40 // While an instance of this class does not own the underlying java object, it 41 // does hold a global reference to it, so that the Java garbage collector does 42 // not destroy it. It uses reference counting to determine when it can destroy 43 // the reference. 44 // TODO: Add multi-thread support! 45 class JavaObject { 46 public: 47 // Creates a NULL JavaObject. 48 JavaObject(); 49 50 // Creates a wrapper around the given object in the given JNI environment. 51 JavaObject(jobject object, JNIEnv* env); 52 53 // Copy constructor. 54 JavaObject(const JavaObject& java_obj); 55 56 // Destructor. 57 ~JavaObject(); 58 59 // Assignment operator. 60 JavaObject& operator=(const JavaObject& java_obj); 61 62 // Access to the object (non-const as JNI functions are non-const). 63 jobject object() const { 64 return object_; 65 } 66 67 // Resets this object to the NULL JavaObject. 68 void Reset(); 69 70 private: 71 // Retain the instance, i.e. increase reference count. 72 void Retain(); 73 74 // Release the instance, i.e. decrease reference count. 75 void Release(); 76 77 // The object pointer (not owned). 78 jobject object_; 79 80 // The reference count of this object 81 int* ref_count_; 82 }; 83 #endif 84 85 // ObjectPool template class. This class keeps track of C++ instances that are 86 // coupled to Java objects. This is done by using an "id" field in the Java 87 // object, which is then mapped to the correct instance here. It should not be 88 // necessary to use this class directly. Instead, the convenience functions 89 // below can be used. 90 template<class T> 91 class ObjectPool { 92 public: 93 // Create a new ObjectPool for a specific object type. Pass the path to the 94 // Java equivalent class of the C++ class, and the name of the java member 95 // field that will store the object's ID. 96 static void Setup(const std::string& jclass_name, 97 const std::string& id_fld_name) { 98 instance_ = new ObjectPool<T>(jclass_name, id_fld_name); 99 } 100 101 // Return the shared instance to this type's pool. 102 static ObjectPool* Instance() { 103 return instance_; 104 } 105 106 // Delete this type's pool. 107 static void TearDown() { 108 delete instance_; 109 } 110 111 // Register a new C++ object with the pool. This does not affect the Java 112 // layer. Use WrapObject() instead to perform the necessary Java-side 113 // assignments. Pass true to owns if the object pool owns the object. 114 int RegisterObject(T* object, bool owns) { 115 const int id = next_id_; 116 objects_[id] = object; 117 owns_[id] = owns; 118 ++next_id_; 119 return id; 120 } 121 122 // Return the object in the pool with the specified ID. 123 T* ObjectWithID(int obj_id) const { 124 typename CObjMap::const_iterator iter = objects_.find(obj_id); 125 return iter == objects_.end() ? NULL : iter->second; 126 } 127 128 // Get the ID of a Java object. This ID can be used to look-up the C++ 129 // object. 130 int GetObjectID(JNIEnv* env, jobject j_object) { 131 jclass cls = env->GetObjectClass(j_object); 132 jfieldID id_field = env->GetFieldID(cls, id_field_name_.c_str(), "I"); 133 const int result = env->GetIntField(j_object, id_field); 134 env->DeleteLocalRef(cls); 135 return result; 136 } 137 138 // Take a C++ object and wrap it with a given Java object. This will 139 // essentially set the ID member of the Java object to the ID of the C++ 140 // object. Pass true to owns if the object pool owns the object. 141 bool WrapObject(T* c_object, JNIEnv* env, jobject j_object, bool owns) { 142 const int id = RegisterObject(c_object, owns); 143 jclass cls = env->GetObjectClass(j_object); 144 jfieldID id_field = env->GetFieldID(cls, id_field_name_.c_str(), "I"); 145 env->SetIntField(j_object, id_field, id); 146 env->DeleteLocalRef(cls); 147 return true; 148 } 149 150 // Remove the object with the given ID from this pool, and delete it. This 151 // does not affect the Java layer. 152 bool DeleteObjectWithID(int obj_id) { 153 typename CObjMap::iterator iter = objects_.find(obj_id); 154 const bool found = iter != objects_.end(); 155 if (found) { 156 if (owns_[obj_id]) 157 delete iter->second; 158 objects_.erase(iter); 159 } 160 return found; 161 } 162 163 // Instantiates a new java object for this class. The Java class must have 164 // a default constructor for this to succeed. 165 jobject CreateJavaObject(JNIEnv* env) { 166 jclass cls = env->FindClass(jclass_name_.c_str()); 167 jmethodID constructor = env->GetMethodID( 168 cls, 169 "<init>", 170 "(Landroid/filterfw/core/NativeAllocatorTag;)V"); 171 jobject result = env->NewObject(cls, constructor, JNI_NULL); 172 env->DeleteLocalRef(cls); 173 return result; 174 } 175 176 int GetObjectCount() const { 177 return objects_.size(); 178 } 179 180 const std::string& GetJavaClassName() const { 181 return jclass_name_; 182 } 183 184 private: 185 explicit ObjectPool(const std::string& jclass_name, 186 const std::string& id_fld_name) 187 : jclass_name_(jclass_name), 188 id_field_name_(id_fld_name), 189 next_id_(0) { } 190 191 typedef std::hash_map<int, T*> CObjMap; 192 typedef std::hash_map<int, bool> FlagMap; 193 static ObjectPool* instance_; 194 std::string jclass_name_; 195 std::string id_field_name_; 196 int next_id_; 197 CObjMap objects_; 198 FlagMap owns_; 199 200 DISALLOW_COPY_AND_ASSIGN(ObjectPool); 201 }; 202 203 template<typename T> ObjectPool<T>* ObjectPool<T>::instance_ = NULL; 204 205 // Convenience Functions /////////////////////////////////////////////////////// 206 207 // This function "links" the C++ instance and the Java instance, so that they 208 // can be mapped to one another. This must be called for every C++ instance 209 // which is wrapped by a Java front-end interface. Pass true to owns, if the 210 // Java layer should own the object. 211 template<typename T> 212 bool WrapObjectInJava(T* c_object, JNIEnv* env, jobject j_object, bool owns) { 213 ObjectPool<T>* pool = ObjectPool<T>::Instance(); 214 return pool ? pool->WrapObject(c_object, env, j_object, owns) : false; 215 } 216 217 // Creates a new Java instance, which wraps the passed C++ instance. Returns 218 // the wrapped object or JNI_NULL if there was an error. Pass true to owns, if 219 // the Java layer should own the object. 220 template<typename T> 221 jobject WrapNewObjectInJava(T* c_object, JNIEnv* env, bool owns) { 222 ObjectPool<T>* pool = ObjectPool<T>::Instance(); 223 if (pool) { 224 jobject result = pool->CreateJavaObject(env); 225 if (WrapObjectInJava(c_object, env, result, owns)) 226 return result; 227 } 228 return JNI_NULL; 229 } 230 231 // Use ConvertFromJava to obtain a C++ instance given a Java object. This 232 // instance must have been wrapped in Java using the WrapObjectInJava() 233 // function. 234 template<typename T> 235 T* ConvertFromJava(JNIEnv* env, jobject j_object) { 236 ObjectPool<T>* pool = ObjectPool<T>::Instance(); 237 return pool && j_object 238 ? pool->ObjectWithID(pool->GetObjectID(env, j_object)) 239 : NULL; 240 } 241 242 // Delete the native object given a Java instance. This should be called from 243 // the Java object's finalizer. 244 template<typename T> 245 bool DeleteNativeObject(JNIEnv* env, jobject j_object) { 246 ObjectPool<T>* pool = ObjectPool<T>::Instance(); 247 return pool && j_object 248 ? pool->DeleteObjectWithID(pool->GetObjectID(env, j_object)) 249 : false; 250 } 251 252 #if 0 253 // Get the current JNI VM, or NULL if there is no current VM 254 JavaVM* GetCurrentJavaVM(); 255 256 // Get the current JNI environment, or NULL if this is not a JNI thread 257 JNIEnv* GetCurrentJNIEnv(); 258 #endif 259 260 // Convert C++ boolean to Java boolean. 261 jboolean ToJBool(bool value); 262 263 // Convert Java boolean to C++ boolean. 264 bool ToCppBool(jboolean value); 265 266 // Convert Java String to C++ string. 267 jstring ToJString(JNIEnv* env, const std::string& value); 268 269 // Convert C++ string to Java String. 270 std::string ToCppString(JNIEnv* env, jstring value); 271 272 // Convert Java object to a (C) Value object. 273 Value ToCValue(JNIEnv* env, jobject object); 274 275 // Convert a (C) Value object to a Java object. 276 jobject ToJObject(JNIEnv* env, const Value& value); 277 278 // Returns true, iff the passed object is an instance of the class specified 279 // by its fully qualified class name. 280 bool IsJavaInstanceOf(JNIEnv* env, jobject object, 281 const std::string& class_name); 282 283 #endif // ANDROID_FILTERFW_JNI_JNI_UTIL_H 284