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 <unordered_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.
Setup(const std::string & jclass_name,const std::string & id_fld_name)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.
Instance()102 static ObjectPool* Instance() {
103 return instance_;
104 }
105
106 // Delete this type's pool.
TearDown()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.
RegisterObject(T * object,bool owns)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.
ObjectWithID(int obj_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.
GetObjectID(JNIEnv * env,jobject j_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.
WrapObject(T * c_object,JNIEnv * env,jobject j_object,bool owns)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.
DeleteObjectWithID(int obj_id)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.
CreateJavaObject(JNIEnv * env)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
GetObjectCount()176 int GetObjectCount() const {
177 return objects_.size();
178 }
179
GetJavaClassName()180 const std::string& GetJavaClassName() const {
181 return jclass_name_;
182 }
183
184 private:
ObjectPool(const std::string & jclass_name,const std::string & id_fld_name)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::unordered_map<int, T*> CObjMap;
192 typedef std::unordered_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>
WrapObjectInJava(T * c_object,JNIEnv * env,jobject j_object,bool owns)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>
WrapNewObjectInJava(T * c_object,JNIEnv * env,bool owns)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>
ConvertFromJava(JNIEnv * env,jobject j_object)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>
DeleteNativeObject(JNIEnv * env,jobject j_object)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