Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export app crash restart #579

Open
topcoco opened this issue Jun 4, 2024 · 16 comments
Open

Export app crash restart #579

topcoco opened this issue Jun 4, 2024 · 16 comments

Comments

@topcoco
Copy link

topcoco commented Jun 4, 2024

How can I stop communicating with the device? I try to change the device status or unplug the device, which causes the app to crash and restart. I try to close it with mSerialIoManager.stop()
port.close()
connection.close(), but it still crashes. Is there any way to close the device connection as long as the device status changes or is unplugged? I don't want the app to crash and restart.
image

@kai-morich
Copy link
Collaborator

that's not a crash, only a warning trace showing the SerialInputOutputManager thread termination reason

@topcoco
Copy link
Author

topcoco commented Jun 4, 2024

这不是崩溃,只是显示 SerialInputOutputManager 线程终止原因的警告跟踪
This problem caused me to re-run the app It will search for the device again. It will not cause the app to close directly, but it will re-execute some processes of MainActivity.
image

@topcoco
Copy link
Author

topcoco commented Jun 4, 2024

image
When I change the state of esp32, it will report an error and re-run the code of MainActivity. For example, println("====") prints for the first time. If I unplug or change the state of the device, it will print again. That is, the code of MainActivity will run again. It should cause the jvm to restart.

@kai-morich
Copy link
Collaborator

To stop communication yourself, close the UsbSerialPort.
To stop communication on external error (e.g. disconnect) handle SerialInputOutpManager.Listener.onRunError() and close the port

@IagonaDevTeam
Copy link

IagonaDevTeam commented Jun 14, 2024

Hey @kai-morich, almost created a new issue before checking this one, which is the exact same one I encounter. I tried many (Not to say dozen) of code check in order to avoid this issue without any success. I've got the same warning as @0cococ and after that the onPause of my app is called and everything seems "restarted" but in a very stange way. So I admit this come from the plugin as it never appear if we don't use COM object. I tried your solution with addition of my private closeConnection function inside the onRunError listener, but it didn't change anything. I've checked the code of the plugin another time (Already done a PR on this project a year before) and think it can be workarounded by adding a Looper on the listerner call. Do you think its viable?

Here is what I do for closing connection:

      this.usbIoManager?.listener = null
      this.usbIoManager?.stop()

      try
      {
          this.port?.close()
      }
      catch (e: Exception)
      {
          Log.error("Unable to close port: ${e.message}")
      }

      try
      {
          this.myConnection?.close()
      }
      catch (e: Exception)
      {
          Log.error("Unable to close connection: ${e.message}")
      }

Here's the workaround

@Override
public void run() {
    synchronized (this) {
        if (getState() != State.STOPPED) {
            throw new IllegalStateException("Already running");
        }
        mState = State.RUNNING;
    }
    Log.i(TAG, "Running ...");
    try {
        if(mThreadPriority != Process.THREAD_PRIORITY_DEFAULT)
            Process.setThreadPriority(mThreadPriority);
        while (true) {
            if (getState() != State.RUNNING) {
                Log.i(TAG, "Stopping mState=" + getState());
                break;
            }
            step();
        }
    } catch (Exception e) {
        if (mSerialPort.isOpen()) {
            Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
        } else {
            Log.i(TAG, "Socket closed");
        }
        final Listener listener = getListener();
        if (listener != null) {
            // Here, handle the exception without triggering onPause
            new Handler(Looper.getMainLooper()).post(() -> listener.onRunError(e));
        }
    } finally {
        synchronized (this) {
            mState = State.STOPPED;
            Log.i(TAG, "Stopped");
        }
    }
}

Thanks in advance

@kai-morich
Copy link
Collaborator

The listener is invoked in the same background thread as the SerialInputOutputManager is running.
If you want to perform UI operations, you have to switch to the main thread with 'looper.post'.
This should be done in the Listener, as done in the example app.

@ExPl0siF
Copy link
Contributor

The listener is invoked in the same background thread as the SerialInputOutputManager is running. If you want to perform UI operations, you have to switch to the main thread with 'looper.post'. This should be done in the Listener, as done in the example app.

Thanks for the infos (Sorry, wrong account on the first post). But I don't do any UI operations (Except if you count UsbSerial disconnection and other disconnect things as UI Operations). I use this plugin in order to communicate with custom Serial object and it just get status every 30 seconds and send it to a server online. If I don't disconnect anything in case of failure, do the app can "crash" too? Thanks in advance

@IagonaDevTeam
Copy link

So, I just tested what you've said (Added Handler(Looper.getMainLooper()).post() inside the onRunError) and It didn't change anything, the behavior is still the same. Do you have any other potential fix for this issue?

@kai-morich
Copy link
Collaborator

The listener is invoked in the same background thread as the SerialInputOutputManager is running. If you want to perform UI operations, you have to switch to the main thread with 'looper.post'. This should be done in the Listener, as done in the example app.

Thanks for the infos (Sorry, wrong account on the first post). But I don't do any UI operations (Except if you count UsbSerial disconnection and other disconnect things as UI Operations). I use this plugin in order to communicate with custom Serial object and it just get status every 30 seconds and send it to a server online. If I don't disconnect anything in case of failure, do the app can "crash" too? Thanks in advance

what kind of "crash" do you get? Can you provide a callstack or logcat output?

@IagonaDevTeam
Copy link

IagonaDevTeam commented Jun 17, 2024

The listener is invoked in the same background thread as the SerialInputOutputManager is running. If you want to perform UI operations, you have to switch to the main thread with 'looper.post'. This should be done in the Listener, as done in the example app.

Thanks for the infos (Sorry, wrong account on the first post). But I don't do any UI operations (Except if you count UsbSerial disconnection and other disconnect things as UI Operations). I use this plugin in order to communicate with custom Serial object and it just get status every 30 seconds and send it to a server online. If I don't disconnect anything in case of failure, do the app can "crash" too? Thanks in advance

what kind of "crash" do you get? Can you provide a callstack or logcat output?

It's doens't seems to be a real crash, but the onPause of my current activity is called, then, the activity is fully relaunched on top of the previous one, so, something bad seems to happen. I got the same Warning as the first post of the issue and then everything goes wrong.

Here is the logcat log that is generated:

06-17 12:03:23.684 D/CCodecBuffers(14495): [c2.android.aac.decoder#672:1D-Input.Impl[N]] codec released a buffer owned by client (index 0)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): Run ending due to exception: USB get_status request failed
06-17 12:03:24.946 W/SerialInputOutputManager(14495): java.io.IOException: USB get_status request failed
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.driver.CommonUsbSerialPort.testConnection(CommonUsbSerialPort.java:171)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.driver.CommonUsbSerialPort.read(CommonUsbSerialPort.java:224)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.driver.CommonUsbSerialPort.read(CommonUsbSerialPort.java:183)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.driver.FtdiSerialDriver$FtdiSerialPort.read(FtdiSerialDriver.java:172)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.driver.FtdiSerialDriver$FtdiSerialPort.read(FtdiSerialDriver.java:150)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.util.SerialInputOutputManager.step(SerialInputOutputManager.java:229)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at com.hoho.android.usbserial.util.SerialInputOutputManager.run(SerialInputOutputManager.java:203)
06-17 12:03:24.946 W/SerialInputOutputManager(14495): 	at java.lang.Thread.run(Thread.java:923)
06-17 12:03:24.954 I/System.out(14495): [ERROR] : Controller: Error on run: USB get_status request failed
06-17 12:03:24.954 I/SerialInputOutputManager(14495): Stopped
06-17 12:03:24.976 I/System.out(14495): [INFO] : Controller: Closing all connections
06-17 12:03:24.977 D/UsbDeviceConnectionJNI(14495): close
06-17 12:03:24.983 I/System.out(14495): [INFO] : Controller: All Connection Closed
06-17 12:03:24.987 I/System.out(14495): [ERROR] : Controller: No available drivers
06-17 12:03:25.271 D/BufferPoolAccessor2.0(14495): bufferpool2 0xee04dca8 : 5(40960 size) total buffers - 4(32768 size) used buffers - 1/6 (recycle/alloc) - 5/242 (fetch/transfer)
06-17 12:03:25.271 D/BufferPoolAccessor2.0(14495): evictor expired: 1, evicted: 1
06-17 12:03:25.486 D/CCodecBuffers(14495): [c2.android.aac.decoder#672:1D-Input.Impl[N]] codec released a buffer owned by client (index 2)
06-17 12:03:25.513 I/System.out(14495): [INFO] : BroadcastActivity onPause Called

@kai-morich
Copy link
Collaborator

Android lifecycle is complex. I recommend https://github.com/xxv/android-lifecycle.
To prevent multiple instances of your app, you could try different launchMode as used here.

@IagonaDevTeam
Copy link

Android lifecycle is complex. I recommend https://github.com/xxv/android-lifecycle. To prevent multiple instances of your app, you could try different launchMode as used here.

Thanks, I know Android Lifecycle is complex, but it shouldn't be triggered with the plugin and a warning. I already tried to setup singleTask and singleTop but it just a bad workaround that create other problems. This behavior only happen with USB plugged in and the plugin running. So, do you have more infos about this behavior and maybe a fix? As there is already 3 issues opened that seems to trigger this problem :/ Thank you very much in advance

@IagonaDevTeam
Copy link

Ok! I have some (good?) news about this! I think I've managed to find the root cause of all the problems! The problem was an app restart after the get_status error. The fact is, when this issue is triggered it seems that the COM device (I admitted this come from the device) create a micro-disconnection that trigger the warning (Which is right, as the connection is/seems lost) and the micro-disconnection trigger the Intent registered with the app. SO, the app onPause is called in order to let another instance (Of the same app/Activity) to be launched and this is why there is this strange behavior. So, for all the other that will read this, you have mainly two solutions:

  • Kill/Quit the app inside the onPause when get_status error is triggered and let the intent do the thing and restart the app gracefully
  • Maybe remove the intent in order for the app/Activty to not be relaunched (But when I remove the intent, it seems that I can't connect anymore to the COM device, but need more test on this point, so, maybe it's possible)

@kai-morich
Copy link
Collaborator

what kind of intent are you using?

@IagonaDevTeam
Copy link

what kind of intent are you using?

I'm using android.hardware.usb.action.USB_DEVICE_ATTACHED, so when a device is attached it launch my Launchscreen, this is why I'm thinking of micro-disconnection from the COM device

@kai-morich
Copy link
Collaborator

android.hardware.usb.action.USB_DEVICE_ATTACHED is not really needed. Access permissions are handled differently. USB_DEVICE_ATTACHED is more like a convenience feature for your App and for users. If multiple Apps can handle USB devices the previously selected can be automatically started.
You should use

to get the intent delivered to the existing App instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants