Skip to content

Commit

Permalink
Implemented few jni methods properly.
Browse files Browse the repository at this point in the history
  • Loading branch information
AeonLucid committed Feb 3, 2019
1 parent 294f89f commit 375145b
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 20 deletions.
16 changes: 13 additions & 3 deletions androidemu/java/java_class_def.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@

class JavaClassDef(type):
next_jvm_id = itertools.count(start=1)
next_jvm_method_id = itertools.count(start=0xd2000000, step=4)

def __init__(cls, name, base, ns, jvm_name=None):
cls.jvm_id = next(JavaClassDef.next_jvm_id)
cls.jvm_name = jvm_name
cls.jvm_methods = list()
cls.jvm_methods = dict()

# Register all defined Java methods.
for func in inspect.getmembers(cls, predicate=inspect.isfunction):
if hasattr(func[1], 'jvm_method'):
cls.jvm_methods.append(func[1].jvm_method)
method = func[1].jvm_method
method.jvm_id = next(JavaClassDef.next_jvm_method_id)
cls.jvm_methods[method] = method

type.__init__(cls, name, base, ns)

Expand All @@ -28,7 +31,7 @@ def register_native(self, name, signature, ptr_func):
found_method = None

# Search for a defined jvm method.
for method in self.jvm_methods:
for method in self.jvm_methods.values():
if method.name == name and method.signature == signature:
method.native_addr = ptr_func
found = True
Expand All @@ -40,3 +43,10 @@ def register_native(self, name, signature, ptr_func):

logger.debug("Registered native function ('%s', '%s') to %s.%s" % (name, signature,
self.__name__, found_method.func_name))

def find_method(cls, name, signature):
for method in cls.jvm_methods.values():
if method.name == name and method.signature == signature:
return method

return None
1 change: 1 addition & 0 deletions androidemu/java/java_method_def.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class JavaMethodDef:

def __init__(self, func_name, name, signature, native):
self.jvm_id = None # Assigned by JavaClassDef.
self.func_name = func_name
self.name = name
self.signature = signature
Expand Down
78 changes: 62 additions & 16 deletions androidemu/java/jni_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class JNIEnv:
"""
def __init__(self, class_loader, hooker):
self._class_loader = class_loader
self._locals = ReferenceTable()
self._globals = ReferenceTable()
self._locals = ReferenceTable(start=1, max_entries=2048)
self._globals = ReferenceTable(start=4096, max_entries=512000)

(self.address_ptr, self.address) = hooker.write_function_table({
4: self.get_version,
Expand Down Expand Up @@ -255,6 +255,18 @@ def __init__(self, class_loader, hooker):
232: self.get_object_ref_type
})

def get_reference(self, idx):
if idx == 0:
return None

if self._locals.in_range(idx):
return self._locals.get(idx)

if self._globals.in_range(idx):
return self._globals.get(idx)

raise RuntimeError('Invalid get_reference(%d)' % idx)

def add_local_reference(self, obj):
if not isinstance(obj, jobject):
raise ValueError('Expected a jobject.')
Expand Down Expand Up @@ -375,27 +387,41 @@ def new_global_ref(self, mu, env, obj):
global or local reference. Global references must be explicitly disposed of by calling DeleteGlobalRef().
"""
logger.debug("JNIEnv->NewGlobalRef(%d) was called" % obj)
# TODO: Implement
return obj + 1

obj = self.get_local_reference(obj)

if obj is None:
# TODO: Implement global > global support (?)
raise NotImplementedError('Invalid local reference obj.')

return self.add_global_reference(obj)

@native_method
def delete_global_ref(self, mu, env):
raise NotImplementedError()

@native_method
def delete_local_ref(self, mu, env, local_ref):
def delete_local_ref(self, mu, env, idx):
"""
Deletes the local reference pointed to by localRef.
"""
logger.debug("JNIEnv->DeleteLocalRef(%d) was called" % local_ref)
# TODO: Implement
logger.debug("JNIEnv->DeleteLocalRef(%d) was called" % idx)
obj = self.get_local_reference(idx)
self.delete_local_reference(obj)

@native_method
def is_same_object(self, mu, env, ref1, ref2):
"""
Returns JNI_TRUE if ref1 and ref2 refer to the same Java object, or are both NULL; otherwise, returns JNI_FALSE.
"""
logger.debug("JNIEnv->IsSameObject(%d, %d) was called" % (ref1, ref2))

obj1 = self.get_reference(ref1)
obj2 = self.get_reference(ref2)

if obj1 is obj2:
return JNI_TRUE

return JNI_FALSE

@native_method
Expand Down Expand Up @@ -431,16 +457,26 @@ def is_instance_of(self, mu, env):
raise NotImplementedError()

@native_method
def get_method_id(self, mu, env, clazz, name_ptr, sig_ptr):
def get_method_id(self, mu, env, clazz_idx, name_ptr, sig_ptr):
"""
Returns the method ID for an instance (nonstatic) method of a class or interface. The method may be defined
in one of the clazz’s superclasses and inherited by clazz. The method is determined by its name and signature.
"""
name = memory_helpers.read_utf8(mu, name_ptr)
sig = memory_helpers.read_utf8(mu, sig_ptr)
logger.debug("JNIEnv->GetMethodId(%d, %s, %s) was called" % (clazz, name, sig))
# TODO: Implement
return 0xFC
clazz = self.get_reference(clazz_idx)
logger.debug("JNIEnv->GetMethodId(%d, %s, %s) was called" % (clazz_idx, name, sig))

if not isinstance(clazz, jclass):
raise ValueError('Expected a jclass.')

method = clazz.value.find_method(name, sig)

if method is None:
# TODO: Proper Java error?
raise RuntimeError("Could not find method ('%s', '%s') in class %s." % (name, sig, clazz.value.jvm_name))

return method.jvm_id

@native_method
def call_object_method(self, mu, env):
Expand Down Expand Up @@ -771,15 +807,26 @@ def set_double_field(self, mu, env):
raise NotImplementedError()

@native_method
def get_static_method_id(self, mu, env, clazz, name_ptr, sig_ptr):
def get_static_method_id(self, mu, env, clazz_idx, name_ptr, sig_ptr):
"""
Returns the method ID for a static method of a class. The method is specified by its name and signature.
"""
name = memory_helpers.read_utf8(mu, name_ptr)
sig = memory_helpers.read_utf8(mu, sig_ptr)
logger.debug("JNIEnv->GetStaticMethodId(%d, %s, %s) was called" % (clazz, name, sig))
# TODO: Implement
return 0xFB
clazz = self.get_reference(clazz_idx)

logger.debug("JNIEnv->GetStaticMethodId(%d, %s, %s) was called" % (clazz_idx, name, sig))

if not isinstance(clazz, jclass):
raise ValueError('Expected a jclass.')

method = clazz.value.find_method(name, sig)

if method is None:
# TODO: Proper Java error?
raise RuntimeError("Could not find static method ('%s', '%s') in class %s." % (name, sig, clazz.value.jvm_name))

return method.jvm_id

@native_method
def call_static_object_method(self, mu, env):
Expand Down Expand Up @@ -1278,7 +1325,6 @@ def exception_check(self, mu, env):
"""
logger.debug("JNIEnv->ExceptionCheck() was called")
# TODO: Implement

return JNI_FALSE

@native_method
Expand Down
6 changes: 5 additions & 1 deletion androidemu/java/reference_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ class ReferenceTable:
"""
:type _table dict[int, jobject|None]
"""
def __init__(self, start=1):
def __init__(self, start=1, max_entries=1024):
self._table = dict()
self._start = start
self._size = max_entries

def add(self, obj):
if not isinstance(obj, jobject):
Expand Down Expand Up @@ -45,5 +46,8 @@ def get(self, idx):

return self._table[idx]

def in_range(self, idx):
return self._start <= idx < self._start + self._start

def clear(self):
self._table.clear()

0 comments on commit 375145b

Please sign in to comment.