mobile/android/modules/JNI.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/modules/JNI.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,197 @@
     1.4 +/* Very basic JNI support for JS
     1.5 + *
     1.6 + * Example Usage:
     1.7 + *   let jni = new JNI();
     1.8 + *   cls = jni.findClass("org/mozilla/gecko/GeckoAppShell");
     1.9 + *   method = jni.getStaticMethodID(cls, "getPreferredIconSize", "(I)I");
    1.10 + *
    1.11 + *   let val = jni.callStaticIntMethod(cls, method, 3);
    1.12 + *   // close the jni library when you are done
    1.13 + *   jni.close();
    1.14 + *
    1.15 + * Note: the getters in this file are deleted and replaced with static
    1.16 + * values once computed, as in, for example
    1.17 + * http://code.activestate.com/recipes/577310-using-a-getter-for-a-one-time-calculation-of-a-jav/
    1.18 + */
    1.19 +this.EXPORTED_SYMBOLS = ["JNI"];
    1.20 +
    1.21 +Components.utils.import("resource://gre/modules/ctypes.jsm")
    1.22 +Components.utils.import("resource://gre/modules/Services.jsm")
    1.23 +
    1.24 +this.JNI = function JNI() { }
    1.25 +
    1.26 +JNI.prototype = {
    1.27 +  get lib() {
    1.28 +    delete this.lib;
    1.29 +    return this.lib = ctypes.open("libxul.so");
    1.30 +  },
    1.31 +
    1.32 +  getType: function(aType) {
    1.33 +    switch(aType) {
    1.34 +      case "B": return ctypes.char;
    1.35 +      case "C": return ctypes.char;
    1.36 +      case "D": return ctypes.double;
    1.37 +      case "F": return ctypes.float;
    1.38 +      case "I": return ctypes.int32_t;
    1.39 +      case "J": return ctypes.int64_t;
    1.40 +      case "S": return ctypes.int16_t;
    1.41 +      case "V": return ctypes.void_t;
    1.42 +      case "Z": return ctypes.bool;
    1.43 +      default: return this.types.jobject
    1.44 +    }
    1.45 +  },
    1.46 +
    1.47 +  getArgs: function(aMethod, aArgs) {
    1.48 +    if (aArgs.length != aMethod.parameters.length)
    1.49 +      throw ("Incorrect number of arguments passed to " + aMethod.name);
    1.50 +
    1.51 +    // Convert arguments to an array of jvalue objects
    1.52 +    let modifiedArgs = new ctypes.ArrayType(this.types.jvalue, aMethod.parameters.length)();
    1.53 +    for (let i = 0; i < aMethod.parameters.length; i++) {
    1.54 +      let parameter = aMethod.parameters[i];
    1.55 +      let arg = new this.types.jvalue();
    1.56 +
    1.57 +      if (aArgs[i] instanceof Array || parameter[0] == "[")
    1.58 +        throw "No support for array arguments yet";
    1.59 +      else
    1.60 +        ctypes.cast(arg, this.getType(parameter)).value = aArgs[i];
    1.61 +
    1.62 +      modifiedArgs[i] = arg;
    1.63 +    }
    1.64 +
    1.65 +    return modifiedArgs;
    1.66 +  },
    1.67 +
    1.68 +  types: {
    1.69 +    jobject: ctypes.StructType("_jobject").ptr,
    1.70 +    jclass: ctypes.StructType("_jobject").ptr,
    1.71 +    jmethodID: ctypes.StructType("jmethodID").ptr,
    1.72 +    jvalue: ctypes.double
    1.73 +  },
    1.74 +
    1.75 +  get _findClass() {
    1.76 +    delete this._findClass;
    1.77 +    return this._findClass = this.lib.declare("jsjni_FindClass",
    1.78 +                                              ctypes.default_abi,
    1.79 +                                              this.types.jclass,
    1.80 +                                              ctypes.char.ptr);
    1.81 +  },
    1.82 +
    1.83 +  findClass: function(name) {
    1.84 +    let ret = this._findClass(name);
    1.85 +    if (this.exceptionCheck())
    1.86 +       throw("Can't find class " + name);
    1.87 +    return ret;
    1.88 +  },
    1.89 +
    1.90 +  get _getStaticMethodID() {
    1.91 +    delete this._getStaticMethodID;
    1.92 +    return this._getStaticMethodID = this.lib.declare("jsjni_GetStaticMethodID",
    1.93 +                                                      ctypes.default_abi,
    1.94 +                                                      this.types.jmethodID,
    1.95 +                                                      this.types.jclass, // class
    1.96 +                                                      ctypes.char.ptr,   // method name
    1.97 +                                                      ctypes.char.ptr);  // signature
    1.98 +  },
    1.99 +
   1.100 +  getStaticMethodID: function(aClass, aName, aSignature) {
   1.101 +    let ret = this._getStaticMethodID(aClass, aName, aSignature);
   1.102 +    if (this.exceptionCheck())
   1.103 +       throw("Can't find method " + aName);
   1.104 +    return new jMethod(aName, ret, aSignature);
   1.105 +  },
   1.106 +
   1.107 +  get _exceptionCheck() {
   1.108 +    delete this._exceptionCheck;
   1.109 +    return this._exceptionCheck = this.lib.declare("jsjni_ExceptionCheck",
   1.110 +                                                   ctypes.default_abi,
   1.111 +                                                   ctypes.bool);
   1.112 +  },
   1.113 +
   1.114 +  exceptionCheck: function() {
   1.115 +    return this._exceptionCheck();
   1.116 +  },
   1.117 +
   1.118 +  get _callStaticVoidMethod() {
   1.119 +    delete this._callStaticVoidMethod;
   1.120 +    return this._callStaticVoidMethod = this.lib.declare("jsjni_CallStaticVoidMethodA",
   1.121 +                                                   ctypes.default_abi,
   1.122 +                                                   ctypes.void_t,
   1.123 +                                                   this.types.jclass,
   1.124 +                                                   this.types.jmethodID,
   1.125 +                                                   this.types.jvalue.ptr);
   1.126 +  },
   1.127 +
   1.128 +  callStaticVoidMethod: function(aClass, aMethod) {
   1.129 +    let args = Array.prototype.slice.apply(arguments, [2]);
   1.130 +    this._callStaticVoidMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args));
   1.131 +    if (this.exceptionCheck())
   1.132 +       throw("Error calling static void method");
   1.133 +  },
   1.134 +
   1.135 +  get _callStaticIntMethod() {
   1.136 +    delete this._callStaticIntMethod;
   1.137 +    return this._callStaticIntMethod = this.lib.declare("jsjni_CallStaticIntMethodA",
   1.138 +                                                   ctypes.default_abi,
   1.139 +                                                   ctypes.int,
   1.140 +                                                   this.types.jclass,
   1.141 +                                                   this.types.jmethodID,
   1.142 +                                                   this.types.jvalue.ptr);
   1.143 +  },
   1.144 +
   1.145 +  callStaticIntMethod: function(aClass, aMethod) {
   1.146 +    let args = Array.prototype.slice.apply(arguments, [2]);
   1.147 +    let ret = this._callStaticIntMethod(aClass, aMethod.methodId, this.getArgs(aMethod, args));
   1.148 +    if (this.exceptionCheck())
   1.149 +       throw("Error calling static int method");
   1.150 +    return ret;
   1.151 +  },
   1.152 +
   1.153 +  close: function() {
   1.154 +    this.lib.close();
   1.155 +  },
   1.156 +}
   1.157 +
   1.158 +function jMethod(name, jMethodId, signature) {
   1.159 +  this.name = name;
   1.160 +  this.methodId = jMethodId;
   1.161 +  this.signature = signature;
   1.162 +}
   1.163 +
   1.164 +jMethod.prototype = {
   1.165 +  parameters: [],
   1.166 +  returnType: null,
   1.167 +  _signature: "",
   1.168 +
   1.169 +  // this just splits up the return value from the parameters
   1.170 +  signatureRegExp: /^\(([^\)]*)\)(.*)$/,
   1.171 +
   1.172 +  // This splits up the actual parameters
   1.173 +  parameterRegExp: /(\[*)(B|C|D|F|I|J|S|V|Z|L[^;]*;)/y,
   1.174 +
   1.175 +  parseSignature: function(aSignature) {
   1.176 +    let [, parameters, returnType] = this.signatureRegExp.exec(aSignature);
   1.177 +
   1.178 +    // parse the parameters that should be passed to this method
   1.179 +    if (parameters) {
   1.180 +      let parameter = this.parameterRegExp.exec(parameters);
   1.181 +      while (parameter) {
   1.182 +        this.parameters.push(parameter[0]);
   1.183 +        parameter = this.parameterRegExp.exec(parameters);
   1.184 +      }
   1.185 +    } else {
   1.186 +      this.parameters = [];
   1.187 +    }
   1.188 +
   1.189 +    // parse the return type
   1.190 +    this.returnType = returnType;
   1.191 +  },
   1.192 +
   1.193 +  _signature: "",
   1.194 +  get signature() { return this._signature; },
   1.195 +  set signature(val) {
   1.196 +    this.parameters = [];
   1.197 +    this.returnType = null;
   1.198 +    this.parseSignature(val);
   1.199 +  }
   1.200 +}

mercurial