[ERLEDIGT] Auffangen von nativen C Exeptions in Java Code?

  • 7 Antworten
  • Letztes Antwortdatum
Androidfan7

Androidfan7

Stamm-User
132
Guten Abend,

ich bin heute auf ein kleines Problem gestoßen und weiß nicht wie ich mir behelfen kann.

Wenn ich zwischen zwei Geräten mit der FileChannel Methode "transferTo" Daten austausche und der Socket auf der anderen Seite die Verbindung abbricht, stürzt meine App ab. Ich habe auch keine Möglichkeit das aufzufangen, nicht mal catch Throwable hilft da. Das Problem ist wohl, dass es sich da um eine Exception handelt die im nativen Code geworfen wird.

Ich habe mal Auszüge aus dem Log:

08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI SetLongField called with pending exception 'android.system.ErrnoException' thrown in long libcore.io.Posix.sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long):-2
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] in call to SetLongField
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] from long libcore.io.Posix.sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] "Thread-7455" prio=5 tid=30 Runnable
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] | group="main" sCount=0 dsCount=0 obj=0x1363a7c0 self=0x9d0dcc00
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] | sysTid=31601 nice=0 cgrp=default sched=0/0 handle=0x9a078480
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] | state=R schedstat=( 390865008 306383116 876 ) utm=11 stm=28 core=3 HZ=100
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] | stack=0x9a4c3000-0x9a4c5000 stackSize=1036KB
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] | held mutexes= "mutator lock"(shared held)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #00 pc 00004758 /system/lib/libbacktrace_libc++.so (_ZN13UnwindCurrent6UnwindEjP8ucontext+23)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #01 pc 00002f8d /system/lib/libbacktrace_libc++.so (_ZN9Backtrace6UnwindEjP8ucontext+8)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #02 pc 00246fd5 /system/lib/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiPKcPNS_6mirror9ArtMethodE+68)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #03 pc 0022b999 /system/lib/libart.so (_ZNK3art6Thread4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+144)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #04 pc 000b1c6b /system/lib/libart.so (_ZN3artL8JniAbortEPKcS1_+602)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #05 pc 000b23d5 /system/lib/libart.so (_ZN3art9JniAbortFEPKcS1_z+60)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #06 pc 000b5273 /system/lib/libart.so (_ZN3art11ScopedCheckC2EP7_JNIEnviPKc+1142)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #07 pc 000b8e9b /system/lib/libart.so (_ZN3art8CheckJNI12SetLongFieldEP7_JNIEnvP8_jobjectP9_jfieldIDx+30)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #08 pc 0001d831 /system/lib/libjavacore.so (???)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #09 pc 0001e587 /system/lib/libjavacore.so (???)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] native: #10 pc 0028ff55 /data/dalvik-cache/arm/system@framework@boot.oat (Java_libcore_io_Posix_sendfile__Ljava_io_FileDescriptor_2Ljava_io_FileDescriptor_2Landroid_util_MutableLong_2J+168)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] at libcore.io.Posix.sendfile(Native method)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] at libcore.io.BlockGuardOs.sendfile(BlockGuardOs.java:265)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] at java.nio.FileChannelImpl.transferTo(FileChannelImpl.java:429)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] at com.example.channels.MyService$1.run(MyService.java:343)
08-08 21:27:42.156 30938-31601/com.example.channels A/art: art/runtime/check_jni.cc:65] at java.lang.Thread.run(Thread.java:818)

Auch dieser Stackoverflow Beitrag beschreibt mein Problem. (Dort wurde leider keine Lösung gefunden) Ich habe leider keine Ahnung von C und kann mir daher selbst nicht weiterhelfen.
Kann mir jemand sagen wir ich verhindern kann das meine App abstürzt und ich die Ausnahme in Java behandeln kann?

Besten Dank für eure Hilfe!

Edit:
Ich reiche morgen meinen Code nach und erläuterte dann auch warum ich es so gemacht habe. Schaffe es nur jetzt zeitlich nicht mehr.
 
Zuletzt bearbeitet:
Hallo Android fan,

ohne code können wir nur selten helfen - auch wenn ich des C mächtig bin

C Exceptions fängt man am besten im C-Code selbst ab - wenn es dort mal zum
Problem kommt , dann erreicht das den Java Code i.d.R nicht mehr

Zwischen welchen Geräten transferierst du denn ?

Was spricht denn gegen eine ganz normale Socket Verbindung ?
Socket | Android Developers
Damit kannst du eher und besser ein Disconnect in einem nonblocked abfangen

Lass uns bitte ein wenig mehr wissen ..
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: Androidfan7
@swa00
Vielen Dank erstmal für die Antwort.
Beigefügt nun die Codeschnipsel. Ich habe es auf das wichtige reduziert. Hoffe die Methoden sind nachvollziehbar.
Ich habe schon einiges ausprobiert, auch Sockets in Kombination mit Streams aber die FileChannel Klasse ist in Sachen Geschwindigkeit allem weit überlegen.

Meinen Code auf Android folgt hier:
Code:
private void share(int port, File file){
    SocketChannel socketChannel = null;
    ServerSocketChannel serverSocketChannel = null;
    ServerSocket serverSocket = null;
    try{
        serverSocketChannel = ServerSocketChannel.open();
        serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));
        socketChannel = serverSocketChannel.accept();

        FileInputStream fileInputStream = new FileInputStream(file);
        FileChannel fileChannel = fileInputStream.getChannel();
        long transferredSum = 0L;
        long toTransfer = file.length();
        while (transferredSum<toTransfer){
            // In der nächsten Zeile sitzt der Fehler
            long bytesTransferred = fileChannel.transferTo(transferredSum, Math.min(1024*1024*2, toTransfer - transferredSum), socketChannel);
            transferredSum +=bytesTransferred;
        }
        fileInputStream.close();
        fileChannel.close();
    } catch (IOException e) {
        e.printStackTrace();
    }finally
    {
        if (serverSocketChannel!=null){
            try {
                serverSocketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (serverSocket!=null){
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (socketChannel!=null){
            try {
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
Und hier der Code auf meinem PC:
Code:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

public class Test extends Thread{
    private int port;
    private InetAddress inetAddress;
    private long fileSize;
    private File fileToSave;

    public Test(int port, InetAddress inetAddress, File fileToSave, long fileSize){
            this.port = port;
            this.inetAddress = inetAddress;
            this.fileToSave = fileToSave;
            this.fileSize = fileSize;
        }

    @Override
    public void run() {
        try(SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(inetAddress, port));) {
            FileOutputStream fileOutputStream = new FileOutputStream(fileToSave);
            FileChannel fileChannel = fileOutputStream.getChannel();
            long transferredSum = 0L;
            while (transferredSum < fileSize) {
                if (isInterrupted()){
                    /* Ursprünglich  hab ich das eingebaut damit die Operation beendet werden kann, falls
                    * das Gegenüber nicht mehr reagiert. Wenn ich den Thread aber interrupte während
                    * das Handy noch sendet, wird zwar am PC alles sauber beendet, aber die APP am Handy stürzt ab
                    * Diese Ausnahme würde ich gerne auffangen
                    */
                    fileOutputStream.close();
                    fileChannel.close();
                    throw new InterruptedException("Interrupted");
                }
                long transferred = fileChannel.transferFrom(socketChannel, transferredSum, Math.min(1024 * 1024 * 2, fileSize - transferredSum));
                transferredSum += transferred;
            }
            fileOutputStream.close();
            fileChannel.close();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Vielen Dank für die Zeit die du dir nimmst!
 
Nabend,

sehe ich das Richtig, dass du auf beiden Seiten Java verwendest ?

Auf PC Seite kann ich dir nicht 100% helfen , da ich i.d.R sowas immer auf C++ Daemon aufbaue -
und da ist der Durchsatz am besten .
Ich setze grundsätzlich IMMER nur pure Socket ein , weil du dann keine High-Level hast,
sondern ziemlich weit unten ansetzen kannst.

Und wo hast du denn jetzt den Absturz ? Auf PC oder App seite ??

Was die PC Seite betrifft :
Ich bin ein wenig erstaunt, normalerweise benutzt man auf PC seite nonblocked mode un fragt im Loop ab,
ob das read fehlerhaft war , oder nicht .

Auch wenn die Verbindung dann abbricht , liefert dir das read ein -1 zurück und du kannst darauf reagieren,
Auch blockiert das read nicht , wenn nichts da war. ( kommt mit 0 zurück)

Ich mag dich jetzt nicht erschrecken, aber ich halte gar nichts von den "workaround" Klassen.
Das "pure" macht zwar ein wenig mehr Arbeit, du musst dir deinen Handshake selber bauen , aber
du bist dir sicher , dass du den Bockmist gebaut hast ,wenns nicht geht :)
 
Ja, benutze auf beidem Java.

Das C/C++ schneller ist, ist mir schon klar, nur will ich nicht wegen dieser App C lernen. :D

Das Problem tritt auf wenn ich am PC den Thread unterbreche und das Handy noch beim Senden ist. Dann wird die App am Handy beendet.

Ich bin jetzt kein Networking Experte, nutze zur Hilfe die beiden Inseln von Christian Ullenboom. Wenn ich mich nicht täusche wurde da das NIO Package empfohlen, wegen der Geschwindigkeit. Ich hab die Methode zum Senden schon ein paar Mal geändert, die jetzige schafft im LAN problemlos 70 MBit/s und ist fast absolut ausfallsicher.

Ich werde sicher irgendeine Lösung für das Problem finden, aber vermutlich ist keine so einfach und performant wie das Auffangen einer Ausnahme wäre.
 
Das C/C++ schneller ist, ist mir schon klar, nur will ich nicht wegen dieser App C lernen

Das hört sich aber eher danach an , dass es eigentlich "egal" wäre ,wenn das Ganze mal ausfallen sollte und
sich der Socket auf PC ebene verabschiedet .
Also wahrscheinlich kein "commercial" Produkt , sondern was für einen kleineren Kreis.

Dann würde ich aus dem Bauch heraus ein Ei drüber schlagen , denn es geht doch :)
Ich weis , es ärgert einen, aber man muss auch mal für sich selbst die Bremse ziehen :)

Und wenn das nächste mal so was ansteht , dann halt Pure Socket / C / C++ und vernünftig :)
 
Nein ich mache das hauptsächlich, weil es mit Spaß macht und als Herausforderung für mich selbst. Fehler, von denen ich weiß das sie vorhanden sind kann ich einfach nicht haben. :D

Irgendwann werde ich sicher mal C in Angriff nehmen. Aber ich denke mal das wird Monate dauern bis man da halbwegs was Vernünftiges programmieren kann. Finde das spielt aufgrund der Nähe zur Maschine schon in einer ganz anderen Liga als Java.

Fürs erste Danke ich dir auf jeden fall für deine Tipps. Falls ich beim rumprobieren noch auf eine Lösung mit den Filechannels stoße werde ich es hier reinschreiben.

Liebe Grüße und schönen Abend noch! :)
 
Fürs erste Danke ich dir auf jeden fall für deine Tipps. Falls ich beim rumprobieren noch auf eine Lösung mit den Filechannels stoße werde ich es hier reinschreiben.

a) Immer wieder sehr gerne
b) Darum würden wir Bitten :)

P.S C ist KEINE Hexerei, du darfst dich dann auch gerne hier melden :)



Ich setze dann erst mal hier auf "Erledigt"
 
  • Danke
Reaktionen: Androidfan7
Zurück
Oben Unten