About Android Linux Permission?MavSDK not supported?

MAVSDK’s Android bindings primarily rely on JNI to call the C++ core library. There is no direct implementation using the Android USB Serial API. The core library defaults to using Linux-style serial port access.

If it’s not possible to manage Linux file permissions on Android, what should be done then?

Many Thanks

Let me explain more…

We need to use MAVSDK Android to connect via Type-C, but we encountered an issue where serial access fails due to a lack of Linux file permissions. We are not root users and cannot gain root access. However, we noticed that the Android version of QGC also operates as a regular user but is able to establish a connection.

Does this mean that the MAVSDK library inherently requires Linux file permissions to connect to PX4? If that’s the case and root access is not available, does it imply that MAVSDK might be unusable in this scenario?

thanks

Have a look at this thread:

From what I understand the serial ports are not accessible via files (“Linux style”) but you need to use the Android/Java API to do so. So you have to write a layer that deals with it in Java and then send it on via e.g. UDP over localhost.

In mavsdkServer.run(), calling initNative returns a negative handle, and after entering runNative, there is no response. I don’t know what to do??

Currently, the package seems normal:

  • The build directory contains the arm64-v8a package.
  • The result of adb shell getprop ro.product.cpu.abi is arm64-v8a.

The code as follows:

private void startMavsdkConnection() {
MavsdkEventQueue.executor().execute(() → {

    int mavsdkServerPort = mavsdkServer.run();
    drone = new System(BACKEND_IP_ADDRESS, mavsdkServerPort);
    

    disposables.add(drone.getTelemetry().getFlightMode()...);
    disposables.add(drone.getTelemetry().getArmed()...);
    disposables.add(drone.getTelemetry().getPosition()...);

    isMavsdkServerRunning = true;
    runOnUiThread(() -> 
        buttonRunDestroyMavsdkServer.setText(R.string.destroy_mavsdk_server));
});

}

UsbSerialHandler as follows:
which runs OK

package io.mavsdk.androidclient;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.os.Looper;

import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

public class UsbSerialHandler {
private static final Logger logger = LoggerFactory.getLogger(UsbSerialHandler.class);
private static final String ACTION_USB_PERMISSION = “io.mavsdk.androidclient.USB_PERMISSION”;
private static final int WRITE_WAIT_MILLIS = 2000;
private static final int READ_BUFFER_SIZE = 1024;
private static final int UDP_PORT = 14550; // MAVLink standard port

private final Context context;
private final UsbManager usbManager;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private final Handler mainHandler = new Handler(Looper.getMainLooper());

private UsbSerialPort serialPort;
private DatagramSocket udpSocket;
private final AtomicBoolean running = new AtomicBoolean(false);
private UsbConnectionCallback callback;

public interface UsbConnectionCallback {
    void onConnectionResult(boolean success);
}

public UsbSerialHandler(Context context) {
    this.context = context;
    this.usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
    setupUsbPermissionReceiver();
}

private final BroadcastReceiver usbPermissionReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
            synchronized (this) {
                UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    if (device != null) {
                        connectToDevice(device);
                    }
                } else {
                    logger.error("USB Permission denied");
                    notifyCallback(false);
                }
            }
        }
    }
};

private void setupUsbPermissionReceiver() {
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    context.registerReceiver(usbPermissionReceiver, filter);
}

public void connect(int baudRate, UsbConnectionCallback callback) {
    this.callback = callback;
    
    List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
    if (availableDrivers.isEmpty()) {
        logger.error("No USB serial devices found");
        notifyCallback(false);
        return;
    }

    UsbSerialDriver driver = availableDrivers.get(0);
    UsbDevice device = driver.getDevice();

    if (usbManager.hasPermission(device)) {
        connectToDevice(device);
    } else {
        requestUsbPermission(device);
    }
}

private void requestUsbPermission(UsbDevice device) {
    PendingIntent permissionIntent = PendingIntent.getBroadcast(
        context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
    usbManager.requestPermission(device, permissionIntent);
}

private void connectToDevice(UsbDevice device) {
    executor.execute(() -> {
        try {
            List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
            UsbSerialDriver driver = availableDrivers.get(0);
            
            UsbDeviceConnection connection = usbManager.openDevice(device);
            if (connection == null) {
                logger.error("Failed to open device");
                notifyCallback(false);
                return;
            }

            serialPort = driver.getPorts().get(0);
            serialPort.open(connection);
            serialPort.setParameters(57600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);

            // Setup UDP socket
            udpSocket = new DatagramSocket();
            running.set(true);
            
            // Start read/write threads
            startUsbReadThread();
            
            notifyCallback(true);
        } catch (Exception e) {
            logger.error("Error connecting to USB device", e);
            notifyCallback(false);
        }
    });
}

private void startUsbReadThread() {
    executor.execute(() -> {
        byte[] buffer = new byte[READ_BUFFER_SIZE];
        while (running.get()) {
            try {
                int len = serialPort.read(buffer, WRITE_WAIT_MILLIS);
                if (len > 0) {
                    // Forward to UDP
                    DatagramPacket packet = new DatagramPacket(
                        buffer, len, 
                        InetAddress.getLocalHost(), UDP_PORT
                    );
                    udpSocket.send(packet);
                }
            } catch (IOException e) {
                if (running.get()) {
                    logger.error("Error reading from USB", e);
                }
            }
        }
    });
}

private void notifyCallback(boolean success) {
    mainHandler.post(() -> {
        if (callback != null) {
            callback.onConnectionResult(success);
        }
    });
}

public void disconnect() {
    running.set(false);
    executor.execute(() -> {
        try {
            if (serialPort != null) {
                serialPort.close();
                serialPort = null;
            }
            if (udpSocket != null) {
                udpSocket.close();
                udpSocket = null;
            }
        } catch (IOException e) {
            logger.error("Error closing USB connection", e);
        }
    });
}

public boolean isConnected() {
    return serialPort != null && running.get();
}

public void onDestroy() {
    disconnect();
    try {
        context.unregisterReceiver(usbPermissionReceiver);
    } catch (Exception e) {
        // Ignore if receiver is not registered
    }
    executor.shutdown();
}

}

Here you use 14550, and in the mavsdk code you use 14540. That doesn’t match…