• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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