Porting the Delphi Android ARM JNI framework to Win32/x86

The new Delphi XE5 provides support for the Android platform, and provides an object oriented JNI framework that allows one to access Android/Java classes (in the rest of this article, I'll refer to it as Java instead, as it's shorter) by merely redeclaring them as a Delphi class inheriting from the TJavaGenericImport class implementing two interfaces, like the following example:

JDialogInterface_OnKeyListenerClass = interface(IJavaClass)
['{F95ED60A-27E5-4A1C-8081-E4646C4AF61D}']
end;

[JavaSignature('android/content/DialogInterface$OnKeyListener')]
JDialogInterface_OnKeyListener = interface(IJavaInstance)
['{597D3989-B3F3-4AE2-8521-1D1141FBE3E3}']
  {Methods}
  function onKey(dialog: JDialogInterface; keyCode: Integer; event: JKeyEvent): Boolean; cdecl;
end;
TJDialogInterface_OnKeyListener = class(TJavaGenericImport< JDialogInterface_OnKeyListenerClass, JDialogInterface_OnKeyListener>) end;

The first interface allows direct access to public static Java methods, or in Delphi parlance, class methods. The second interface allows access to instance methods. To instantiate the above Java class, one calls either

dlgIntf := TJDialogInterface_OnKeyListener.Create(...);

or

dlgIntf := TJDialogInterface_OnKeyListener.JavaClass.init(...);

and then, to access any instance methods (for the above class), just access it from dlgIntf, like so:

dlgIntf.onKey(...)

Since Java is implemented in C/C++, the calling convention for Java/Android methods is cdecl.

The TJavaGenericImport class provides access to the declared Java class by building a method table for the Java class, with each method pointing to a stub built during runtime that does some parameter wrapping, before using JNI to call into the actual Java method.

I decided to port the Android ARM JNI framework to Win32, after I was approached to write a wrapper. Another motivation was that  debugging any Android code on Delphi XE5 didn't get very far. The IDE would hang often when debugging any code on Android. The first target platform for the Android JNI port is Win32, instead of Win32 and Win64, because parameter passing on Win64 is very different from Win32.

The initial prototype was written in Java. After the prototype was completed, I decided to dogfood the prototype by rewriting it in Delphi, hence, providing myself the opportunity to test out the generated wrappers.

The port involved converting ARM assembly to x86 assembly, as well as the rest of the Android JNI framework. Other than that, it also involved creating a Java VM in Delphi, since the generated wrappers require a Java VM in place, and calling parts of the Java framework from within Delphi, using the same generated wrappers as well.

During the port, I noticed that the Delphi ARM JNI framework may possibly not handle return results such as float, double, or any kind of Java array. So I quickly learnt some assembly that took float/double results, and convert it into a form more palatable to Delphi. This also meant that my application might generate Android/Java class wrappers that exposes bugs in the Delphi JNI RTL.

The Android 2 Delphi Import application has been ready for weeks. I'm now figuring out what my best options are:

  • To sell the application to a vendor,
  • or to sell it directly to developers.

 

Published Thu, 24 Oct 2013 @ 12:40 PM by chuacw
Related articles: , ,

Comments (Will be reviewed before being published)

# JNI - the old way of doing it and the Delphi OO way

In XE5, Embarcadero introduced a new object oriented way of calling into any Android API. Before looking

# re: Porting the Delphi Android ARM JNI framework to Win32/x86

Monday, December 30, 2013 1:28 AM by Anderson Grande

Hello,

I found your article very interesting.

 

# re: Porting the Delphi Android ARM JNI framework to Win32/x86

Monday, December 30, 2013 2:20 PM by chuacw

Anderson, if you need consulting, let me know. Just leave me a comment with your email, and I'll follow up.

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Enter the following code to ensure that your comment reaches the intended party:
Enter the numbers you see in the image: