diff --git a/index.js b/index.js index 246e88e..aea3bd5 100644 --- a/index.js +++ b/index.js @@ -21,20 +21,20 @@ const jsizeSize = 4; const pointerSize = Process.pointerSize; class Runtime { - ACC_PUBLIC = 0x0001; - ACC_PRIVATE = 0x0002; - ACC_PROTECTED = 0x0004; - ACC_STATIC = 0x0008; - ACC_FINAL = 0x0010; + ACC_PUBLIC = 0x0001; + ACC_PRIVATE = 0x0002; + ACC_PROTECTED = 0x0004; + ACC_STATIC = 0x0008; + ACC_FINAL = 0x0010; ACC_SYNCHRONIZED = 0x0020; - ACC_BRIDGE = 0x0040; - ACC_VARARGS = 0x0080; - ACC_NATIVE = 0x0100; - ACC_ABSTRACT = 0x0400; - ACC_STRICT = 0x0800; - ACC_SYNTHETIC = 0x1000; - - constructor () { + ACC_BRIDGE = 0x0040; + ACC_VARARGS = 0x0080; + ACC_NATIVE = 0x0100; + ACC_ABSTRACT = 0x0400; + ACC_STRICT = 0x0800; + ACC_SYNTHETIC = 0x1000; + + constructor() { this.classFactory = null; this.ClassFactory = ClassFactory; this.vm = null; @@ -54,7 +54,7 @@ class Runtime { } } - _tryInitialize () { + _tryInitialize() { if (this._initialized) { return true; } @@ -87,7 +87,7 @@ class Runtime { return true; } - _dispose () { + _dispose() { if (this.api === null) { return; } @@ -102,15 +102,15 @@ class Runtime { }); } - get available () { + get available() { return this._tryInitialize(); } - get androidVersion () { + get androidVersion() { return getAndroidVersion(); } - synchronized (obj, fn) { + synchronized(obj, fn) { const { $h: objHandle = obj } = obj; if (!(objHandle instanceof NativePointer)) { throw new Error('Java.synchronized: the first argument `obj` must be either a pointer or a Java instance'); @@ -125,7 +125,7 @@ class Runtime { } } - enumerateLoadedClasses (callbacks) { + enumerateLoadedClasses(callbacks) { this._checkAvailable(); const { flavor } = this.api; @@ -138,19 +138,19 @@ class Runtime { } } - enumerateLoadedClassesSync () { + enumerateLoadedClassesSync() { const classes = []; this.enumerateLoadedClasses({ - onMatch (c) { + onMatch(c) { classes.push(c); }, - onComplete () { + onComplete() { } }); return classes; } - enumerateClassLoaders (callbacks) { + enumerateClassLoaders(callbacks) { this._checkAvailable(); const { flavor } = this.api; @@ -163,19 +163,19 @@ class Runtime { } } - enumerateClassLoadersSync () { + enumerateClassLoadersSync() { const loaders = []; this.enumerateClassLoaders({ - onMatch (c) { + onMatch(c) { loaders.push(c); }, - onComplete () { + onComplete() { } }); return loaders; } - _enumerateLoadedClassesJvm (callbacks) { + _enumerateLoadedClassesJvm(callbacks) { const { api, vm } = this; const { jvmti } = api; const env = vm.getEnv(); @@ -206,11 +206,11 @@ class Runtime { } } - _enumerateClassLoadersJvm (callbacks) { + _enumerateClassLoadersJvm(callbacks) { this.choose('java.lang.ClassLoader', callbacks); } - _enumerateLoadedClassesArt (callbacks) { + _enumerateLoadedClassesArt(callbacks) { const { vm, api } = this; const env = vm.getEnv(); @@ -219,9 +219,14 @@ class Runtime { withRunnableArtThread(vm, env, thread => { const collectClassHandles = makeArtClassVisitor(klass => { const handle = addGlobalReference(vmHandle, thread, klass); - const className = env.getClassName(handle); - callbacks.onMatch(className, handle); - env.deleteGlobalRef(handle); + try { + const className = env.getClassName(handle); + callbacks.onMatch(className, handle); + env.deleteGlobalRef(handle); + } + finally { + env.deleteGlobalRef(handle); + } return true; }); @@ -231,7 +236,7 @@ class Runtime { callbacks.onComplete(); } - _enumerateClassLoadersArt (callbacks) { + _enumerateClassLoadersArt(callbacks) { const { classFactory: factory, vm, api } = this; const env = vm.getEnv(); @@ -269,7 +274,7 @@ class Runtime { callbacks.onComplete(); } - _enumerateLoadedClassesDalvik (callbacks) { + _enumerateLoadedClassesDalvik(callbacks) { const { api } = this; const HASH_TOMBSTONE = ptr('0xcbcacccd'); @@ -303,7 +308,7 @@ class Runtime { callbacks.onComplete(); } - enumerateMethods (query) { + enumerateMethods(query) { const { classFactory: factory } = this; const env = this.vm.getEnv(); const ClassLoader = factory.use('java.lang.ClassLoader'); @@ -316,7 +321,7 @@ class Runtime { }); } - scheduleOnMainThread (fn) { + scheduleOnMainThread(fn) { this.performNow(() => { this._pendingMainOps.push(fn); @@ -339,7 +344,7 @@ class Runtime { }); } - _makePollHook () { + _makePollHook() { const mainThreadId = Process.id; const { _pendingMainOps: pending } = this; @@ -359,7 +364,7 @@ class Runtime { }; } - perform (fn) { + perform(fn) { this._checkAvailable(); if (!this._isAppProcess() || this.classFactory.loader !== null) { @@ -376,7 +381,7 @@ class Runtime { } } - performNow (fn) { + performNow(fn) { this._checkAvailable(); return this.vm.perform(() => { @@ -394,7 +399,7 @@ class Runtime { }); } - _performPendingVmOpsWhenReady () { + _performPendingVmOpsWhenReady() { this.vm.perform(() => { const { classFactory: factory } = this; @@ -450,7 +455,7 @@ class Runtime { }); } - _performPendingVmOps () { + _performPendingVmOps() { const { vm, _pendingVmOps: pending } = this; let fn; @@ -463,36 +468,36 @@ class Runtime { } } - use (className, options) { + use(className, options) { return this.classFactory.use(className, options); } - openClassFile (filePath) { + openClassFile(filePath) { return this.classFactory.openClassFile(filePath); } - choose (specifier, callbacks) { + choose(specifier, callbacks) { this.classFactory.choose(specifier, callbacks); } - retain (obj) { + retain(obj) { return this.classFactory.retain(obj); } - cast (obj, C) { + cast(obj, C) { return this.classFactory.cast(obj, C); } - array (type, elements) { + array(type, elements) { return this.classFactory.array(type, elements); } - backtrace (options) { + backtrace(options) { return backtrace(this.vm, options); } // Reference: http://stackoverflow.com/questions/2848575/how-to-detect-ui-thread-on-android - isMainThread () { + isMainThread() { const Looper = this.classFactory.use('android.os.Looper'); const mainLooper = Looper.getMainLooper(); const myLooper = Looper.myLooper(); @@ -502,32 +507,32 @@ class Runtime { return mainLooper.$isSameObject(myLooper); } - registerClass (spec) { + registerClass(spec) { return this.classFactory.registerClass(spec); } - deoptimizeEverything () { + deoptimizeEverything() { const { vm } = this; return deoptimizeEverything(vm, vm.getEnv()); } - deoptimizeBootImage () { + deoptimizeBootImage() { const { vm } = this; return deoptimizeBootImage(vm, vm.getEnv()); } - deoptimizeMethod (method) { + deoptimizeMethod(method) { const { vm } = this; return deoptimizeMethod(vm, vm.getEnv(), method); } - _checkAvailable () { + _checkAvailable() { if (!this.available) { throw new Error('Java API not available'); } } - _isAppProcess () { + _isAppProcess() { let result = this._cachedIsAppProcess; if (result === null) { if (this.api.flavor === 'jvm') { @@ -559,7 +564,7 @@ class Runtime { } } -function initFactoryFromApplication (factory, app) { +function initFactoryFromApplication(factory, app) { const Process = factory.use('android.os.Process'); factory.loader = app.getClassLoader(); @@ -578,7 +583,7 @@ function initFactoryFromApplication (factory, app) { } } -function initFactoryFromLoadedApk (factory, apk) { +function initFactoryFromLoadedApk(factory, apk) { const JFile = factory.use('java.io.File'); factory.loader = apk.getClassLoader();