"Unity Exception: JNI: Init'd AndroidJavaObject with null ptr!" AndroidJavaObject + System.Threading

Hello.
I’m trying to program an AT-10A tablet using Unity for this. The Unity version is 2022.3.21f1.

The tablet manufacturer provided me with a file “canbus_api.aar”, which contains the CanBus communication functions that I need to access.

I was able to communicate with their API successfully, using the code below:

using UnityEngine;
public class JavaClassCAN : MonoBehaviour {
    AndroidJavaObject canBusHelper;
    private void Start() {
        canBusHelper = new AndroidJavaObject("com.android.canbus.CanBusHelper");
        //config serial baudrate
        var retConfigSerial = canBusHelper.Call<int>("setSerialBaudrate", 1, 115200, 8, 0, 1); //OK - it works
        if (retConfigSerial < 0) {
            Debug.Log("ERROR - Config Serial Baudrate");
        }
        Debug.Log("Return 'setSerialBaudrate': " + retConfigSerial.ToString());
        //initialize canbus
        var retInitCAN = canBusHelper.Call<int>("initialize", 1, 115200, 500000, false); //OK - it works
        if (retInitCAN < 0) {
            Debug.Log("ERROR - Config CAN");
        }
        Debug.Log("Return 'initialize': " + retInitCAN.ToString());
        //Start read CanBus
        if (canBusHelper != null) {
            var retReadCan = canBusHelper.Call<int>("readCan", 1, new CanBusCallbackProxy()); //OK - it works
            Debug.Log(retReadCan);
        }
        else {
            Debug.LogError("AndroidJavaObject canBusHelper is null");
        }
    }
    public class CanBusCallbackProxy : AndroidJavaProxy {
        public CanBusCallbackProxy() : base("com.android.canbus.CanBusHelper$CanBusCallback") {
        }
        public void onSetError() {
            Debug.Log("zyz0 --> onSetError");
        }
        public void onSendError() {
            Debug.Log("zyz0 --> onSendError");
        }
        public void onIdError(int count) {
            Debug.Log("onIdError: " + count);
        }
        public void onReceiveCanbusData(int FF, int RTR, int DLC, int ID, int[] DATA) {
            Debug.Log("onReceiveCanbusData: FF=" + FF + ", RTR=" + RTR + ", DLC=" + DLC + ", ID=" + ID.ToString("X"));
            string dataString = "DATA: ";
            for (int i = 0; i < DATA.Length; i++) {
                dataString += DATA[i].ToString("X") + " ";
            }
            Debug.Log(dataString);
        }
    }
}

It’s quite simple and it works, as shown in logcat:

However, the “readCan” function is blocking, leaving the program stuck inside a while while waiting to receive data, and this obviously blocks the main unity thread and blocks the execution of the program itself.

The solution to this is apparently simple, just move the “readCan” function to a separate thread and everything will work fine. So I created this code below, making the function initialize in a new Thread.

using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class JavaClassCAN : MonoBehaviour {
    AndroidJavaObject canBusHelper;
    private Thread canReadThread;
    private bool runThread;
    private void Start() {
        canBusHelper = new AndroidJavaObject("com.android.canbus.CanBusHelper");
        //config serial baudrate
        var retConfigSerial = canBusHelper.Call<int>("setSerialBaudrate", 1, 115200, 8, 0, 1);
        if (retConfigSerial < 0) {
            Debug.Log("ERROR - Config Serial Baudrate");
        }
        Debug.Log("Return 'setSerialBaudrate': " + retConfigSerial.ToString());
        //initialize canbus
        var retInitCAN = canBusHelper.Call<int>("initialize", 1, 115200, 500000, false);
        if (retInitCAN < 0) {
            Debug.Log("ERROR - Config CAN");
        }
        Debug.Log("Return 'initialize': " + retInitCAN.ToString());
        //Start thread
        runThread = true;
        canReadThread = new Thread(ReadCanData);
        canReadThread.Start();
    }
    private void OnDisable() {
        runThread = false;
        if (canReadThread != null && canReadThread.IsAlive) {
            canReadThread.Join();
        }
    }
    private void ReadCanData() {
        Thread.Sleep(1000);
        if (runThread) {
            if (canBusHelper != null) {
                var retReadCan = canBusHelper.Call<int>("readCan", 1, new CanBusCallbackProxy()); //HERE - BUG
                Debug.Log(retReadCan);
            }
            else {
                Debug.LogError("AndroidJavaObject canBusHelper is null");
            }
        }
    }
    public class CanBusCallbackProxy : AndroidJavaProxy {
        public CanBusCallbackProxy() : base("com.android.canbus.CanBusHelper$CanBusCallback") {
        }
        public void onSetError() {
            Debug.Log("zyz0 --> onSetError");
        }
        public void onSendError() {
            Debug.Log("zyz0 --> onSendError");
        }
        public void onIdError(int count) {
            Debug.Log("onIdError: " + count);
        }
        public void onReceiveCanbusData(int FF, int RTR, int DLC, int ID, int[] DATA) {
            Debug.Log("onReceiveCanbusData: FF=" + FF + ", RTR=" + RTR + ", DLC=" + DLC + ", ID=" + ID.ToString("X"));
            string dataString = "DATA: ";
            for (int i = 0; i < DATA.Length; i++) {
                dataString += DATA[i].ToString("X") + " ";
            }
            Debug.Log(dataString);
        }
    }
}

However, this time, when trying to run the readCan function, I get the error “Error Unity Exception: JNI: Init’d AndroidJavaObject with null ptr!”

Check this out - Unity - Scripting API: AndroidJNI.AttachCurrentThread

1 Like

Simply perfect!!!

Just add “AndroidJNI.AttachCurrentThread();” at the beginning of the thread and everything works perfectly.

Thank you very much for your help and quick response!!!

My custom thread now:

private void ReadCanData() {
        Thread.Sleep(100);
        AndroidJNI.AttachCurrentThread();
        //
        CanBusCallbackProxy callBack = new CanBusCallbackProxy();
        if (callBack != null && canBusHelper != null) {
            var retReadCan = canBusHelper.Call<int>("readCan", 1, callBack);
        }
    }
1 Like